retroarch.c 1.2 MB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711207122071320714207152071620717207182071920720207212072220723207242072520726207272072820729207302073120732207332073420735207362073720738207392074020741207422074320744207452074620747207482074920750207512075220753207542075520756207572075820759207602076120762207632076420765207662076720768207692077020771207722077320774207752077620777207782077920780207812078220783207842078520786207872078820789207902079120792207932079420795207962079720798207992080020801208022080320804208052080620807208082080920810208112081220813208142081520816208172081820819208202082120822208232082420825208262082720828208292083020831208322083320834208352083620837208382083920840208412084220843208442084520846208472084820849208502085120852208532085420855208562085720858208592086020861208622086320864208652086620867208682086920870208712087220873208742087520876208772087820879208802088120882208832088420885208862088720888208892089020891208922089320894208952089620897208982089920900209012090220903209042090520906209072090820909209102091120912209132091420915209162091720918209192092020921209222092320924209252092620927209282092920930209312093220933209342093520936209372093820939209402094120942209432094420945209462094720948209492095020951209522095320954209552095620957209582095920960209612096220963209642096520966209672096820969209702097120972209732097420975209762097720978209792098020981209822098320984209852098620987209882098920990209912099220993209942099520996209972099820999210002100121002210032100421005210062100721008210092101021011210122101321014210152101621017210182101921020210212102221023210242102521026210272102821029210302103121032210332103421035210362103721038210392104021041210422104321044210452104621047210482104921050210512105221053210542105521056210572105821059210602106121062210632106421065210662106721068210692107021071210722107321074210752107621077210782107921080210812108221083210842108521086210872108821089210902109121092210932109421095210962109721098210992110021101211022110321104211052110621107211082110921110211112111221113211142111521116211172111821119211202112121122211232112421125211262112721128211292113021131211322113321134211352113621137211382113921140211412114221143211442114521146211472114821149211502115121152211532115421155211562115721158211592116021161211622116321164211652116621167211682116921170211712117221173211742117521176211772117821179211802118121182211832118421185211862118721188211892119021191211922119321194211952119621197211982119921200212012120221203212042120521206212072120821209212102121121212212132121421215212162121721218212192122021221212222122321224212252122621227212282122921230212312123221233212342123521236212372123821239212402124121242212432124421245212462124721248212492125021251212522125321254212552125621257212582125921260212612126221263212642126521266212672126821269212702127121272212732127421275212762127721278212792128021281212822128321284212852128621287212882128921290212912129221293212942129521296212972129821299213002130121302213032130421305213062130721308213092131021311213122131321314213152131621317213182131921320213212132221323213242132521326213272132821329213302133121332213332133421335213362133721338213392134021341213422134321344213452134621347213482134921350213512135221353213542135521356213572135821359213602136121362213632136421365213662136721368213692137021371213722137321374213752137621377213782137921380213812138221383213842138521386213872138821389213902139121392213932139421395213962139721398213992140021401214022140321404214052140621407214082140921410214112141221413214142141521416214172141821419214202142121422214232142421425214262142721428214292143021431214322143321434214352143621437214382143921440214412144221443214442144521446214472144821449214502145121452214532145421455214562145721458214592146021461214622146321464214652146621467214682146921470214712147221473214742147521476214772147821479214802148121482214832148421485214862148721488214892149021491214922149321494214952149621497214982149921500215012150221503215042150521506215072150821509215102151121512215132151421515215162151721518215192152021521215222152321524215252152621527215282152921530215312153221533215342153521536215372153821539215402154121542215432154421545215462154721548215492155021551215522155321554215552155621557215582155921560215612156221563215642156521566215672156821569215702157121572215732157421575215762157721578215792158021581215822158321584215852158621587215882158921590215912159221593215942159521596215972159821599216002160121602216032160421605216062160721608216092161021611216122161321614216152161621617216182161921620216212162221623216242162521626216272162821629216302163121632216332163421635216362163721638216392164021641216422164321644216452164621647216482164921650216512165221653216542165521656216572165821659216602166121662216632166421665216662166721668216692167021671216722167321674216752167621677216782167921680216812168221683216842168521686216872168821689216902169121692216932169421695216962169721698216992170021701217022170321704217052170621707217082170921710217112171221713217142171521716217172171821719217202172121722217232172421725217262172721728217292173021731217322173321734217352173621737217382173921740217412174221743217442174521746217472174821749217502175121752217532175421755217562175721758217592176021761217622176321764217652176621767217682176921770217712177221773217742177521776217772177821779217802178121782217832178421785217862178721788217892179021791217922179321794217952179621797217982179921800218012180221803218042180521806218072180821809218102181121812218132181421815218162181721818218192182021821218222182321824218252182621827218282182921830218312183221833218342183521836218372183821839218402184121842218432184421845218462184721848218492185021851218522185321854218552185621857218582185921860218612186221863218642186521866218672186821869218702187121872218732187421875218762187721878218792188021881218822188321884218852188621887218882188921890218912189221893218942189521896218972189821899219002190121902219032190421905219062190721908219092191021911219122191321914219152191621917219182191921920219212192221923219242192521926219272192821929219302193121932219332193421935219362193721938219392194021941219422194321944219452194621947219482194921950219512195221953219542195521956219572195821959219602196121962219632196421965219662196721968219692197021971219722197321974219752197621977219782197921980219812198221983219842198521986219872198821989219902199121992219932199421995219962199721998219992200022001220022200322004220052200622007220082200922010220112201222013220142201522016220172201822019220202202122022220232202422025220262202722028220292203022031220322203322034220352203622037220382203922040220412204222043220442204522046220472204822049220502205122052220532205422055220562205722058220592206022061220622206322064220652206622067220682206922070220712207222073220742207522076220772207822079220802208122082220832208422085220862208722088220892209022091220922209322094220952209622097220982209922100221012210222103221042210522106221072210822109221102211122112221132211422115221162211722118221192212022121221222212322124221252212622127221282212922130221312213222133221342213522136221372213822139221402214122142221432214422145221462214722148221492215022151221522215322154221552215622157221582215922160221612216222163221642216522166221672216822169221702217122172221732217422175221762217722178221792218022181221822218322184221852218622187221882218922190221912219222193221942219522196221972219822199222002220122202222032220422205222062220722208222092221022211222122221322214222152221622217222182221922220222212222222223222242222522226222272222822229222302223122232222332223422235222362223722238222392224022241222422224322244222452224622247222482224922250222512225222253222542225522256222572225822259222602226122262222632226422265222662226722268222692227022271222722227322274222752227622277222782227922280222812228222283222842228522286222872228822289222902229122292222932229422295222962229722298222992230022301223022230322304223052230622307223082230922310223112231222313223142231522316223172231822319223202232122322223232232422325223262232722328223292233022331223322233322334223352233622337223382233922340223412234222343223442234522346223472234822349223502235122352223532235422355223562235722358223592236022361223622236322364223652236622367223682236922370223712237222373223742237522376223772237822379223802238122382223832238422385223862238722388223892239022391223922239322394223952239622397223982239922400224012240222403224042240522406224072240822409224102241122412224132241422415224162241722418224192242022421224222242322424224252242622427224282242922430224312243222433224342243522436224372243822439224402244122442224432244422445224462244722448224492245022451224522245322454224552245622457224582245922460224612246222463224642246522466224672246822469224702247122472224732247422475224762247722478224792248022481224822248322484224852248622487224882248922490224912249222493224942249522496224972249822499225002250122502225032250422505225062250722508225092251022511225122251322514225152251622517225182251922520225212252222523225242252522526225272252822529225302253122532225332253422535225362253722538225392254022541225422254322544225452254622547225482254922550225512255222553225542255522556225572255822559225602256122562225632256422565225662256722568225692257022571225722257322574225752257622577225782257922580225812258222583225842258522586225872258822589225902259122592225932259422595225962259722598225992260022601226022260322604226052260622607226082260922610226112261222613226142261522616226172261822619226202262122622226232262422625226262262722628226292263022631226322263322634226352263622637226382263922640226412264222643226442264522646226472264822649226502265122652226532265422655226562265722658226592266022661226622266322664226652266622667226682266922670226712267222673226742267522676226772267822679226802268122682226832268422685226862268722688226892269022691226922269322694226952269622697226982269922700227012270222703227042270522706227072270822709227102271122712227132271422715227162271722718227192272022721227222272322724227252272622727227282272922730227312273222733227342273522736227372273822739227402274122742227432274422745227462274722748227492275022751227522275322754227552275622757227582275922760227612276222763227642276522766227672276822769227702277122772227732277422775227762277722778227792278022781227822278322784227852278622787227882278922790227912279222793227942279522796227972279822799228002280122802228032280422805228062280722808228092281022811228122281322814228152281622817228182281922820228212282222823228242282522826228272282822829228302283122832228332283422835228362283722838228392284022841228422284322844228452284622847228482284922850228512285222853228542285522856228572285822859228602286122862228632286422865228662286722868228692287022871228722287322874228752287622877228782287922880228812288222883228842288522886228872288822889228902289122892228932289422895228962289722898228992290022901229022290322904229052290622907229082290922910229112291222913229142291522916229172291822919229202292122922229232292422925229262292722928229292293022931229322293322934229352293622937229382293922940229412294222943229442294522946229472294822949229502295122952229532295422955229562295722958229592296022961229622296322964229652296622967229682296922970229712297222973229742297522976229772297822979229802298122982229832298422985229862298722988229892299022991229922299322994229952299622997229982299923000230012300223003230042300523006230072300823009230102301123012230132301423015230162301723018230192302023021230222302323024230252302623027230282302923030230312303223033230342303523036230372303823039230402304123042230432304423045230462304723048230492305023051230522305323054230552305623057230582305923060230612306223063230642306523066230672306823069230702307123072230732307423075230762307723078230792308023081230822308323084230852308623087230882308923090230912309223093230942309523096230972309823099231002310123102231032310423105231062310723108231092311023111231122311323114231152311623117231182311923120231212312223123231242312523126231272312823129231302313123132231332313423135231362313723138231392314023141231422314323144231452314623147231482314923150231512315223153231542315523156231572315823159231602316123162231632316423165231662316723168231692317023171231722317323174231752317623177231782317923180231812318223183231842318523186231872318823189231902319123192231932319423195231962319723198231992320023201232022320323204232052320623207232082320923210232112321223213232142321523216232172321823219232202322123222232232322423225232262322723228232292323023231232322323323234232352323623237232382323923240232412324223243232442324523246232472324823249232502325123252232532325423255232562325723258232592326023261232622326323264232652326623267232682326923270232712327223273232742327523276232772327823279232802328123282232832328423285232862328723288232892329023291232922329323294232952329623297232982329923300233012330223303233042330523306233072330823309233102331123312233132331423315233162331723318233192332023321233222332323324233252332623327233282332923330233312333223333233342333523336233372333823339233402334123342233432334423345233462334723348233492335023351233522335323354233552335623357233582335923360233612336223363233642336523366233672336823369233702337123372233732337423375233762337723378233792338023381233822338323384233852338623387233882338923390233912339223393233942339523396233972339823399234002340123402234032340423405234062340723408234092341023411234122341323414234152341623417234182341923420234212342223423234242342523426234272342823429234302343123432234332343423435234362343723438234392344023441234422344323444234452344623447234482344923450234512345223453234542345523456234572345823459234602346123462234632346423465234662346723468234692347023471234722347323474234752347623477234782347923480234812348223483234842348523486234872348823489234902349123492234932349423495234962349723498234992350023501235022350323504235052350623507235082350923510235112351223513235142351523516235172351823519235202352123522235232352423525235262352723528235292353023531235322353323534235352353623537235382353923540235412354223543235442354523546235472354823549235502355123552235532355423555235562355723558235592356023561235622356323564235652356623567235682356923570235712357223573235742357523576235772357823579235802358123582235832358423585235862358723588235892359023591235922359323594235952359623597235982359923600236012360223603236042360523606236072360823609236102361123612236132361423615236162361723618236192362023621236222362323624236252362623627236282362923630236312363223633236342363523636236372363823639236402364123642236432364423645236462364723648236492365023651236522365323654236552365623657236582365923660236612366223663236642366523666236672366823669236702367123672236732367423675236762367723678236792368023681236822368323684236852368623687236882368923690236912369223693236942369523696236972369823699237002370123702237032370423705237062370723708237092371023711237122371323714237152371623717237182371923720237212372223723237242372523726237272372823729237302373123732237332373423735237362373723738237392374023741237422374323744237452374623747237482374923750237512375223753237542375523756237572375823759237602376123762237632376423765237662376723768237692377023771237722377323774237752377623777237782377923780237812378223783237842378523786237872378823789237902379123792237932379423795237962379723798237992380023801238022380323804238052380623807238082380923810238112381223813238142381523816238172381823819238202382123822238232382423825238262382723828238292383023831238322383323834238352383623837238382383923840238412384223843238442384523846238472384823849238502385123852238532385423855238562385723858238592386023861238622386323864238652386623867238682386923870238712387223873238742387523876238772387823879238802388123882238832388423885238862388723888238892389023891238922389323894238952389623897238982389923900239012390223903239042390523906239072390823909239102391123912239132391423915239162391723918239192392023921239222392323924239252392623927239282392923930239312393223933239342393523936239372393823939239402394123942239432394423945239462394723948239492395023951239522395323954239552395623957239582395923960239612396223963239642396523966239672396823969239702397123972239732397423975239762397723978239792398023981239822398323984239852398623987239882398923990239912399223993239942399523996239972399823999240002400124002240032400424005240062400724008240092401024011240122401324014240152401624017240182401924020240212402224023240242402524026240272402824029240302403124032240332403424035240362403724038240392404024041240422404324044240452404624047240482404924050240512405224053240542405524056240572405824059240602406124062240632406424065240662406724068240692407024071240722407324074240752407624077240782407924080240812408224083240842408524086240872408824089240902409124092240932409424095240962409724098240992410024101241022410324104241052410624107241082410924110241112411224113241142411524116241172411824119241202412124122241232412424125241262412724128241292413024131241322413324134241352413624137241382413924140241412414224143241442414524146241472414824149241502415124152241532415424155241562415724158241592416024161241622416324164241652416624167241682416924170241712417224173241742417524176241772417824179241802418124182241832418424185241862418724188241892419024191241922419324194241952419624197241982419924200242012420224203242042420524206242072420824209242102421124212242132421424215242162421724218242192422024221242222422324224242252422624227242282422924230242312423224233242342423524236242372423824239242402424124242242432424424245242462424724248242492425024251242522425324254242552425624257242582425924260242612426224263242642426524266242672426824269242702427124272242732427424275242762427724278242792428024281242822428324284242852428624287242882428924290242912429224293242942429524296242972429824299243002430124302243032430424305243062430724308243092431024311243122431324314243152431624317243182431924320243212432224323243242432524326243272432824329243302433124332243332433424335243362433724338243392434024341243422434324344243452434624347243482434924350243512435224353243542435524356243572435824359243602436124362243632436424365243662436724368243692437024371243722437324374243752437624377243782437924380243812438224383243842438524386243872438824389243902439124392243932439424395243962439724398243992440024401244022440324404244052440624407244082440924410244112441224413244142441524416244172441824419244202442124422244232442424425244262442724428244292443024431244322443324434244352443624437244382443924440244412444224443244442444524446244472444824449244502445124452244532445424455244562445724458244592446024461244622446324464244652446624467244682446924470244712447224473244742447524476244772447824479244802448124482244832448424485244862448724488244892449024491244922449324494244952449624497244982449924500245012450224503245042450524506245072450824509245102451124512245132451424515245162451724518245192452024521245222452324524245252452624527245282452924530245312453224533245342453524536245372453824539245402454124542245432454424545245462454724548245492455024551245522455324554245552455624557245582455924560245612456224563245642456524566245672456824569245702457124572245732457424575245762457724578245792458024581245822458324584245852458624587245882458924590245912459224593245942459524596245972459824599246002460124602246032460424605246062460724608246092461024611246122461324614246152461624617246182461924620246212462224623246242462524626246272462824629246302463124632246332463424635246362463724638246392464024641246422464324644246452464624647246482464924650246512465224653246542465524656246572465824659246602466124662246632466424665246662466724668246692467024671246722467324674246752467624677246782467924680246812468224683246842468524686246872468824689246902469124692246932469424695246962469724698246992470024701247022470324704247052470624707247082470924710247112471224713247142471524716247172471824719247202472124722247232472424725247262472724728247292473024731247322473324734247352473624737247382473924740247412474224743247442474524746247472474824749247502475124752247532475424755247562475724758247592476024761247622476324764247652476624767247682476924770247712477224773247742477524776247772477824779247802478124782247832478424785247862478724788247892479024791247922479324794247952479624797247982479924800248012480224803248042480524806248072480824809248102481124812248132481424815248162481724818248192482024821248222482324824248252482624827248282482924830248312483224833248342483524836248372483824839248402484124842248432484424845248462484724848248492485024851248522485324854248552485624857248582485924860248612486224863248642486524866248672486824869248702487124872248732487424875248762487724878248792488024881248822488324884248852488624887248882488924890248912489224893248942489524896248972489824899249002490124902249032490424905249062490724908249092491024911249122491324914249152491624917249182491924920249212492224923249242492524926249272492824929249302493124932249332493424935249362493724938249392494024941249422494324944249452494624947249482494924950249512495224953249542495524956249572495824959249602496124962249632496424965249662496724968249692497024971249722497324974249752497624977249782497924980249812498224983249842498524986249872498824989249902499124992249932499424995249962499724998249992500025001250022500325004250052500625007250082500925010250112501225013250142501525016250172501825019250202502125022250232502425025250262502725028250292503025031250322503325034250352503625037250382503925040250412504225043250442504525046250472504825049250502505125052250532505425055250562505725058250592506025061250622506325064250652506625067250682506925070250712507225073250742507525076250772507825079250802508125082250832508425085250862508725088250892509025091250922509325094250952509625097250982509925100251012510225103251042510525106251072510825109251102511125112251132511425115251162511725118251192512025121251222512325124251252512625127251282512925130251312513225133251342513525136251372513825139251402514125142251432514425145251462514725148251492515025151251522515325154251552515625157251582515925160251612516225163251642516525166251672516825169251702517125172251732517425175251762517725178251792518025181251822518325184251852518625187251882518925190251912519225193251942519525196251972519825199252002520125202252032520425205252062520725208252092521025211252122521325214252152521625217252182521925220252212522225223252242522525226252272522825229252302523125232252332523425235252362523725238252392524025241252422524325244252452524625247252482524925250252512525225253252542525525256252572525825259252602526125262252632526425265252662526725268252692527025271252722527325274252752527625277252782527925280252812528225283252842528525286252872528825289252902529125292252932529425295252962529725298252992530025301253022530325304253052530625307253082530925310253112531225313253142531525316253172531825319253202532125322253232532425325253262532725328253292533025331253322533325334253352533625337253382533925340253412534225343253442534525346253472534825349253502535125352253532535425355253562535725358253592536025361253622536325364253652536625367253682536925370253712537225373253742537525376253772537825379253802538125382253832538425385253862538725388253892539025391253922539325394253952539625397253982539925400254012540225403254042540525406254072540825409254102541125412254132541425415254162541725418254192542025421254222542325424254252542625427254282542925430254312543225433254342543525436254372543825439254402544125442254432544425445254462544725448254492545025451254522545325454254552545625457254582545925460254612546225463254642546525466254672546825469254702547125472254732547425475254762547725478254792548025481254822548325484254852548625487254882548925490254912549225493254942549525496254972549825499255002550125502255032550425505255062550725508255092551025511255122551325514255152551625517255182551925520255212552225523255242552525526255272552825529255302553125532255332553425535255362553725538255392554025541255422554325544255452554625547255482554925550255512555225553255542555525556255572555825559255602556125562255632556425565255662556725568255692557025571255722557325574255752557625577255782557925580255812558225583255842558525586255872558825589255902559125592255932559425595255962559725598255992560025601256022560325604256052560625607256082560925610256112561225613256142561525616256172561825619256202562125622256232562425625256262562725628256292563025631256322563325634256352563625637256382563925640256412564225643256442564525646256472564825649256502565125652256532565425655256562565725658256592566025661256622566325664256652566625667256682566925670256712567225673256742567525676256772567825679256802568125682256832568425685256862568725688256892569025691256922569325694256952569625697256982569925700257012570225703257042570525706257072570825709257102571125712257132571425715257162571725718257192572025721257222572325724257252572625727257282572925730257312573225733257342573525736257372573825739257402574125742257432574425745257462574725748257492575025751257522575325754257552575625757257582575925760257612576225763257642576525766257672576825769257702577125772257732577425775257762577725778257792578025781257822578325784257852578625787257882578925790257912579225793257942579525796257972579825799258002580125802258032580425805258062580725808258092581025811258122581325814258152581625817258182581925820258212582225823258242582525826258272582825829258302583125832258332583425835258362583725838258392584025841258422584325844258452584625847258482584925850258512585225853258542585525856258572585825859258602586125862258632586425865258662586725868258692587025871258722587325874258752587625877258782587925880258812588225883258842588525886258872588825889258902589125892258932589425895258962589725898258992590025901259022590325904259052590625907259082590925910259112591225913259142591525916259172591825919259202592125922259232592425925259262592725928259292593025931259322593325934259352593625937259382593925940259412594225943259442594525946259472594825949259502595125952259532595425955259562595725958259592596025961259622596325964259652596625967259682596925970259712597225973259742597525976259772597825979259802598125982259832598425985259862598725988259892599025991259922599325994259952599625997259982599926000260012600226003260042600526006260072600826009260102601126012260132601426015260162601726018260192602026021260222602326024260252602626027260282602926030260312603226033260342603526036260372603826039260402604126042260432604426045260462604726048260492605026051260522605326054260552605626057260582605926060260612606226063260642606526066260672606826069260702607126072260732607426075260762607726078260792608026081260822608326084260852608626087260882608926090260912609226093260942609526096260972609826099261002610126102261032610426105261062610726108261092611026111261122611326114261152611626117261182611926120261212612226123261242612526126261272612826129261302613126132261332613426135261362613726138261392614026141261422614326144261452614626147261482614926150261512615226153261542615526156261572615826159261602616126162261632616426165261662616726168261692617026171261722617326174261752617626177261782617926180261812618226183261842618526186261872618826189261902619126192261932619426195261962619726198261992620026201262022620326204262052620626207262082620926210262112621226213262142621526216262172621826219262202622126222262232622426225262262622726228262292623026231262322623326234262352623626237262382623926240262412624226243262442624526246262472624826249262502625126252262532625426255262562625726258262592626026261262622626326264262652626626267262682626926270262712627226273262742627526276262772627826279262802628126282262832628426285262862628726288262892629026291262922629326294262952629626297262982629926300263012630226303263042630526306263072630826309263102631126312263132631426315263162631726318263192632026321263222632326324263252632626327263282632926330263312633226333263342633526336263372633826339263402634126342263432634426345263462634726348263492635026351263522635326354263552635626357263582635926360263612636226363263642636526366263672636826369263702637126372263732637426375263762637726378263792638026381263822638326384263852638626387263882638926390263912639226393263942639526396263972639826399264002640126402264032640426405264062640726408264092641026411264122641326414264152641626417264182641926420264212642226423264242642526426264272642826429264302643126432264332643426435264362643726438264392644026441264422644326444264452644626447264482644926450264512645226453264542645526456264572645826459264602646126462264632646426465264662646726468264692647026471264722647326474264752647626477264782647926480264812648226483264842648526486264872648826489264902649126492264932649426495264962649726498264992650026501265022650326504265052650626507265082650926510265112651226513265142651526516265172651826519265202652126522265232652426525265262652726528265292653026531265322653326534265352653626537265382653926540265412654226543265442654526546265472654826549265502655126552265532655426555265562655726558265592656026561265622656326564265652656626567265682656926570265712657226573265742657526576265772657826579265802658126582265832658426585265862658726588265892659026591265922659326594265952659626597265982659926600266012660226603266042660526606266072660826609266102661126612266132661426615266162661726618266192662026621266222662326624266252662626627266282662926630266312663226633266342663526636266372663826639266402664126642266432664426645266462664726648266492665026651266522665326654266552665626657266582665926660266612666226663266642666526666266672666826669266702667126672266732667426675266762667726678266792668026681266822668326684266852668626687266882668926690266912669226693266942669526696266972669826699267002670126702267032670426705267062670726708267092671026711267122671326714267152671626717267182671926720267212672226723267242672526726267272672826729267302673126732267332673426735267362673726738267392674026741267422674326744267452674626747267482674926750267512675226753267542675526756267572675826759267602676126762267632676426765267662676726768267692677026771267722677326774267752677626777267782677926780267812678226783267842678526786267872678826789267902679126792267932679426795267962679726798267992680026801268022680326804268052680626807268082680926810268112681226813268142681526816268172681826819268202682126822268232682426825268262682726828268292683026831268322683326834268352683626837268382683926840268412684226843268442684526846268472684826849268502685126852268532685426855268562685726858268592686026861268622686326864268652686626867268682686926870268712687226873268742687526876268772687826879268802688126882268832688426885268862688726888268892689026891268922689326894268952689626897268982689926900269012690226903269042690526906269072690826909269102691126912269132691426915269162691726918269192692026921269222692326924269252692626927269282692926930269312693226933269342693526936269372693826939269402694126942269432694426945269462694726948269492695026951269522695326954269552695626957269582695926960269612696226963269642696526966269672696826969269702697126972269732697426975269762697726978269792698026981269822698326984269852698626987269882698926990269912699226993269942699526996269972699826999270002700127002270032700427005270062700727008270092701027011270122701327014270152701627017270182701927020270212702227023270242702527026270272702827029270302703127032270332703427035270362703727038270392704027041270422704327044270452704627047270482704927050270512705227053270542705527056270572705827059270602706127062270632706427065270662706727068270692707027071270722707327074270752707627077270782707927080270812708227083270842708527086270872708827089270902709127092270932709427095270962709727098270992710027101271022710327104271052710627107271082710927110271112711227113271142711527116271172711827119271202712127122271232712427125271262712727128271292713027131271322713327134271352713627137271382713927140271412714227143271442714527146271472714827149271502715127152271532715427155271562715727158271592716027161271622716327164271652716627167271682716927170271712717227173271742717527176271772717827179271802718127182271832718427185271862718727188271892719027191271922719327194271952719627197271982719927200272012720227203272042720527206272072720827209272102721127212272132721427215272162721727218272192722027221272222722327224272252722627227272282722927230272312723227233272342723527236272372723827239272402724127242272432724427245272462724727248272492725027251272522725327254272552725627257272582725927260272612726227263272642726527266272672726827269272702727127272272732727427275272762727727278272792728027281272822728327284272852728627287272882728927290272912729227293272942729527296272972729827299273002730127302273032730427305273062730727308273092731027311273122731327314273152731627317273182731927320273212732227323273242732527326273272732827329273302733127332273332733427335273362733727338273392734027341273422734327344273452734627347273482734927350273512735227353273542735527356273572735827359273602736127362273632736427365273662736727368273692737027371273722737327374273752737627377273782737927380273812738227383273842738527386273872738827389273902739127392273932739427395273962739727398273992740027401274022740327404274052740627407274082740927410274112741227413274142741527416274172741827419274202742127422274232742427425274262742727428274292743027431274322743327434274352743627437274382743927440274412744227443274442744527446274472744827449274502745127452274532745427455274562745727458274592746027461274622746327464274652746627467274682746927470274712747227473274742747527476274772747827479274802748127482274832748427485274862748727488274892749027491274922749327494274952749627497274982749927500275012750227503275042750527506275072750827509275102751127512275132751427515275162751727518275192752027521275222752327524275252752627527275282752927530275312753227533275342753527536275372753827539275402754127542275432754427545275462754727548275492755027551275522755327554275552755627557275582755927560275612756227563275642756527566275672756827569275702757127572275732757427575275762757727578275792758027581275822758327584275852758627587275882758927590275912759227593275942759527596275972759827599276002760127602276032760427605276062760727608276092761027611276122761327614276152761627617276182761927620276212762227623276242762527626276272762827629276302763127632276332763427635276362763727638276392764027641276422764327644276452764627647276482764927650276512765227653276542765527656276572765827659276602766127662276632766427665276662766727668276692767027671276722767327674276752767627677276782767927680276812768227683276842768527686276872768827689276902769127692276932769427695276962769727698276992770027701277022770327704277052770627707277082770927710277112771227713277142771527716277172771827719277202772127722277232772427725277262772727728277292773027731277322773327734277352773627737277382773927740277412774227743277442774527746277472774827749277502775127752277532775427755277562775727758277592776027761277622776327764277652776627767277682776927770277712777227773277742777527776277772777827779277802778127782277832778427785277862778727788277892779027791277922779327794277952779627797277982779927800278012780227803278042780527806278072780827809278102781127812278132781427815278162781727818278192782027821278222782327824278252782627827278282782927830278312783227833278342783527836278372783827839278402784127842278432784427845278462784727848278492785027851278522785327854278552785627857278582785927860278612786227863278642786527866278672786827869278702787127872278732787427875278762787727878278792788027881278822788327884278852788627887278882788927890278912789227893278942789527896278972789827899279002790127902279032790427905279062790727908279092791027911279122791327914279152791627917279182791927920279212792227923279242792527926279272792827929279302793127932279332793427935279362793727938279392794027941279422794327944279452794627947279482794927950279512795227953279542795527956279572795827959279602796127962279632796427965279662796727968279692797027971279722797327974279752797627977279782797927980279812798227983279842798527986279872798827989279902799127992279932799427995279962799727998279992800028001280022800328004280052800628007280082800928010280112801228013280142801528016280172801828019280202802128022280232802428025280262802728028280292803028031280322803328034280352803628037280382803928040280412804228043280442804528046280472804828049280502805128052280532805428055280562805728058280592806028061280622806328064280652806628067280682806928070280712807228073280742807528076280772807828079280802808128082280832808428085280862808728088280892809028091280922809328094280952809628097280982809928100281012810228103281042810528106281072810828109281102811128112281132811428115281162811728118281192812028121281222812328124281252812628127281282812928130281312813228133281342813528136281372813828139281402814128142281432814428145281462814728148281492815028151281522815328154281552815628157281582815928160281612816228163281642816528166281672816828169281702817128172281732817428175281762817728178281792818028181281822818328184281852818628187281882818928190281912819228193281942819528196281972819828199282002820128202282032820428205282062820728208282092821028211282122821328214282152821628217282182821928220282212822228223282242822528226282272822828229282302823128232282332823428235282362823728238282392824028241282422824328244282452824628247282482824928250282512825228253282542825528256282572825828259282602826128262282632826428265282662826728268282692827028271282722827328274282752827628277282782827928280282812828228283282842828528286282872828828289282902829128292282932829428295282962829728298282992830028301283022830328304283052830628307283082830928310283112831228313283142831528316283172831828319283202832128322283232832428325283262832728328283292833028331283322833328334283352833628337283382833928340283412834228343283442834528346283472834828349283502835128352283532835428355283562835728358283592836028361283622836328364283652836628367283682836928370283712837228373283742837528376283772837828379283802838128382283832838428385283862838728388283892839028391283922839328394283952839628397283982839928400284012840228403284042840528406284072840828409284102841128412284132841428415284162841728418284192842028421284222842328424284252842628427284282842928430284312843228433284342843528436284372843828439284402844128442284432844428445284462844728448284492845028451284522845328454284552845628457284582845928460284612846228463284642846528466284672846828469284702847128472284732847428475284762847728478284792848028481284822848328484284852848628487284882848928490284912849228493284942849528496284972849828499285002850128502285032850428505285062850728508285092851028511285122851328514285152851628517285182851928520285212852228523285242852528526285272852828529285302853128532285332853428535285362853728538285392854028541285422854328544285452854628547285482854928550285512855228553285542855528556285572855828559285602856128562285632856428565285662856728568285692857028571285722857328574285752857628577285782857928580285812858228583285842858528586285872858828589285902859128592285932859428595285962859728598285992860028601286022860328604286052860628607286082860928610286112861228613286142861528616286172861828619286202862128622286232862428625286262862728628286292863028631286322863328634286352863628637286382863928640286412864228643286442864528646286472864828649286502865128652286532865428655286562865728658286592866028661286622866328664286652866628667286682866928670286712867228673286742867528676286772867828679286802868128682286832868428685286862868728688286892869028691286922869328694286952869628697286982869928700287012870228703287042870528706287072870828709287102871128712287132871428715287162871728718287192872028721287222872328724287252872628727287282872928730287312873228733287342873528736287372873828739287402874128742287432874428745287462874728748287492875028751287522875328754287552875628757287582875928760287612876228763287642876528766287672876828769287702877128772287732877428775287762877728778287792878028781287822878328784287852878628787287882878928790287912879228793287942879528796287972879828799288002880128802288032880428805288062880728808288092881028811288122881328814288152881628817288182881928820288212882228823288242882528826288272882828829288302883128832288332883428835288362883728838288392884028841288422884328844288452884628847288482884928850288512885228853288542885528856288572885828859288602886128862288632886428865288662886728868288692887028871288722887328874288752887628877288782887928880288812888228883288842888528886288872888828889288902889128892288932889428895288962889728898288992890028901289022890328904289052890628907289082890928910289112891228913289142891528916289172891828919289202892128922289232892428925289262892728928289292893028931289322893328934289352893628937289382893928940289412894228943289442894528946289472894828949289502895128952289532895428955289562895728958289592896028961289622896328964289652896628967289682896928970289712897228973289742897528976289772897828979289802898128982289832898428985289862898728988289892899028991289922899328994289952899628997289982899929000290012900229003290042900529006290072900829009290102901129012290132901429015290162901729018290192902029021290222902329024290252902629027290282902929030290312903229033290342903529036290372903829039290402904129042290432904429045290462904729048290492905029051290522905329054290552905629057290582905929060290612906229063290642906529066290672906829069290702907129072290732907429075290762907729078290792908029081290822908329084290852908629087290882908929090290912909229093290942909529096290972909829099291002910129102291032910429105291062910729108291092911029111291122911329114291152911629117291182911929120291212912229123291242912529126291272912829129291302913129132291332913429135291362913729138291392914029141291422914329144291452914629147291482914929150291512915229153291542915529156291572915829159291602916129162291632916429165291662916729168291692917029171291722917329174291752917629177291782917929180291812918229183291842918529186291872918829189291902919129192291932919429195291962919729198291992920029201292022920329204292052920629207292082920929210292112921229213292142921529216292172921829219292202922129222292232922429225292262922729228292292923029231292322923329234292352923629237292382923929240292412924229243292442924529246292472924829249292502925129252292532925429255292562925729258292592926029261292622926329264292652926629267292682926929270292712927229273292742927529276292772927829279292802928129282292832928429285292862928729288292892929029291292922929329294292952929629297292982929929300293012930229303293042930529306293072930829309293102931129312293132931429315293162931729318293192932029321293222932329324293252932629327293282932929330293312933229333293342933529336293372933829339293402934129342293432934429345293462934729348293492935029351293522935329354293552935629357293582935929360293612936229363293642936529366293672936829369293702937129372293732937429375293762937729378293792938029381293822938329384293852938629387293882938929390293912939229393293942939529396293972939829399294002940129402294032940429405294062940729408294092941029411294122941329414294152941629417294182941929420294212942229423294242942529426294272942829429294302943129432294332943429435294362943729438294392944029441294422944329444294452944629447294482944929450294512945229453294542945529456294572945829459294602946129462294632946429465294662946729468294692947029471294722947329474294752947629477294782947929480294812948229483294842948529486294872948829489294902949129492294932949429495294962949729498294992950029501295022950329504295052950629507295082950929510295112951229513295142951529516295172951829519295202952129522295232952429525295262952729528295292953029531295322953329534295352953629537295382953929540295412954229543295442954529546295472954829549295502955129552295532955429555295562955729558295592956029561295622956329564295652956629567295682956929570295712957229573295742957529576295772957829579295802958129582295832958429585295862958729588295892959029591295922959329594295952959629597295982959929600296012960229603296042960529606296072960829609296102961129612296132961429615296162961729618296192962029621296222962329624296252962629627296282962929630296312963229633296342963529636296372963829639296402964129642296432964429645296462964729648296492965029651296522965329654296552965629657296582965929660296612966229663296642966529666296672966829669296702967129672296732967429675296762967729678296792968029681296822968329684296852968629687296882968929690296912969229693296942969529696296972969829699297002970129702297032970429705297062970729708297092971029711297122971329714297152971629717297182971929720297212972229723297242972529726297272972829729297302973129732297332973429735297362973729738297392974029741297422974329744297452974629747297482974929750297512975229753297542975529756297572975829759297602976129762297632976429765297662976729768297692977029771297722977329774297752977629777297782977929780297812978229783297842978529786297872978829789297902979129792297932979429795297962979729798297992980029801298022980329804298052980629807298082980929810298112981229813298142981529816298172981829819298202982129822298232982429825298262982729828298292983029831298322983329834298352983629837298382983929840298412984229843298442984529846298472984829849298502985129852298532985429855298562985729858298592986029861298622986329864298652986629867298682986929870298712987229873298742987529876298772987829879298802988129882298832988429885298862988729888298892989029891298922989329894298952989629897298982989929900299012990229903299042990529906299072990829909299102991129912299132991429915299162991729918299192992029921299222992329924299252992629927299282992929930299312993229933299342993529936299372993829939299402994129942299432994429945299462994729948299492995029951299522995329954299552995629957299582995929960299612996229963299642996529966299672996829969299702997129972299732997429975299762997729978299792998029981299822998329984299852998629987299882998929990299912999229993299942999529996299972999829999300003000130002300033000430005300063000730008300093001030011300123001330014300153001630017300183001930020300213002230023300243002530026300273002830029300303003130032300333003430035300363003730038300393004030041300423004330044300453004630047300483004930050300513005230053300543005530056300573005830059300603006130062300633006430065300663006730068300693007030071300723007330074300753007630077300783007930080300813008230083300843008530086300873008830089300903009130092300933009430095300963009730098300993010030101301023010330104301053010630107301083010930110301113011230113301143011530116301173011830119301203012130122301233012430125301263012730128301293013030131301323013330134301353013630137301383013930140301413014230143301443014530146301473014830149301503015130152301533015430155301563015730158301593016030161301623016330164301653016630167301683016930170301713017230173301743017530176301773017830179301803018130182301833018430185301863018730188301893019030191301923019330194301953019630197301983019930200302013020230203302043020530206302073020830209302103021130212302133021430215302163021730218302193022030221302223022330224302253022630227302283022930230302313023230233302343023530236302373023830239302403024130242302433024430245302463024730248302493025030251302523025330254302553025630257302583025930260302613026230263302643026530266302673026830269302703027130272302733027430275302763027730278302793028030281302823028330284302853028630287302883028930290302913029230293302943029530296302973029830299303003030130302303033030430305303063030730308303093031030311303123031330314303153031630317303183031930320303213032230323303243032530326303273032830329303303033130332303333033430335303363033730338303393034030341303423034330344303453034630347303483034930350303513035230353303543035530356303573035830359303603036130362303633036430365303663036730368303693037030371303723037330374303753037630377303783037930380303813038230383303843038530386303873038830389303903039130392303933039430395303963039730398303993040030401304023040330404304053040630407304083040930410304113041230413304143041530416304173041830419304203042130422304233042430425304263042730428304293043030431304323043330434304353043630437304383043930440304413044230443304443044530446304473044830449304503045130452304533045430455304563045730458304593046030461304623046330464304653046630467304683046930470304713047230473304743047530476304773047830479304803048130482304833048430485304863048730488304893049030491304923049330494304953049630497304983049930500305013050230503305043050530506305073050830509305103051130512305133051430515305163051730518305193052030521305223052330524305253052630527305283052930530305313053230533305343053530536305373053830539305403054130542305433054430545305463054730548305493055030551305523055330554305553055630557305583055930560305613056230563305643056530566305673056830569305703057130572305733057430575305763057730578305793058030581305823058330584305853058630587305883058930590305913059230593305943059530596305973059830599306003060130602306033060430605306063060730608306093061030611306123061330614306153061630617306183061930620306213062230623306243062530626306273062830629306303063130632306333063430635306363063730638306393064030641306423064330644306453064630647306483064930650306513065230653306543065530656306573065830659306603066130662306633066430665306663066730668306693067030671306723067330674306753067630677306783067930680306813068230683306843068530686306873068830689306903069130692306933069430695306963069730698306993070030701307023070330704307053070630707307083070930710307113071230713307143071530716307173071830719307203072130722307233072430725307263072730728307293073030731307323073330734307353073630737307383073930740307413074230743307443074530746307473074830749307503075130752307533075430755307563075730758307593076030761307623076330764307653076630767307683076930770307713077230773307743077530776307773077830779307803078130782307833078430785307863078730788307893079030791307923079330794307953079630797307983079930800308013080230803308043080530806308073080830809308103081130812308133081430815308163081730818308193082030821308223082330824308253082630827308283082930830308313083230833308343083530836308373083830839308403084130842308433084430845308463084730848308493085030851308523085330854308553085630857308583085930860308613086230863308643086530866308673086830869308703087130872308733087430875308763087730878308793088030881308823088330884308853088630887308883088930890308913089230893308943089530896308973089830899309003090130902309033090430905309063090730908309093091030911309123091330914309153091630917309183091930920309213092230923309243092530926309273092830929309303093130932309333093430935309363093730938309393094030941309423094330944309453094630947309483094930950309513095230953309543095530956309573095830959309603096130962309633096430965309663096730968309693097030971309723097330974309753097630977309783097930980309813098230983309843098530986309873098830989309903099130992309933099430995309963099730998309993100031001310023100331004310053100631007310083100931010310113101231013310143101531016310173101831019310203102131022310233102431025310263102731028310293103031031310323103331034310353103631037310383103931040310413104231043310443104531046310473104831049310503105131052310533105431055310563105731058310593106031061310623106331064310653106631067310683106931070310713107231073310743107531076310773107831079310803108131082310833108431085310863108731088310893109031091310923109331094310953109631097310983109931100311013110231103311043110531106311073110831109311103111131112311133111431115311163111731118311193112031121311223112331124311253112631127311283112931130311313113231133311343113531136311373113831139311403114131142311433114431145311463114731148311493115031151311523115331154311553115631157311583115931160311613116231163311643116531166311673116831169311703117131172311733117431175311763117731178311793118031181311823118331184311853118631187311883118931190311913119231193311943119531196311973119831199312003120131202312033120431205312063120731208312093121031211312123121331214312153121631217312183121931220312213122231223312243122531226312273122831229312303123131232312333123431235312363123731238312393124031241312423124331244312453124631247312483124931250312513125231253312543125531256312573125831259312603126131262312633126431265312663126731268312693127031271312723127331274312753127631277312783127931280312813128231283312843128531286312873128831289312903129131292312933129431295312963129731298312993130031301313023130331304313053130631307313083130931310313113131231313313143131531316313173131831319313203132131322313233132431325313263132731328313293133031331313323133331334313353133631337313383133931340313413134231343313443134531346313473134831349313503135131352313533135431355313563135731358313593136031361313623136331364313653136631367313683136931370313713137231373313743137531376313773137831379313803138131382313833138431385313863138731388313893139031391313923139331394313953139631397313983139931400314013140231403314043140531406314073140831409314103141131412314133141431415314163141731418314193142031421314223142331424314253142631427314283142931430314313143231433314343143531436314373143831439314403144131442314433144431445314463144731448314493145031451314523145331454314553145631457314583145931460314613146231463314643146531466314673146831469314703147131472314733147431475314763147731478314793148031481314823148331484314853148631487314883148931490314913149231493314943149531496314973149831499315003150131502315033150431505315063150731508315093151031511315123151331514315153151631517315183151931520315213152231523315243152531526315273152831529315303153131532315333153431535315363153731538315393154031541315423154331544315453154631547315483154931550315513155231553315543155531556315573155831559315603156131562315633156431565315663156731568315693157031571315723157331574315753157631577315783157931580315813158231583315843158531586315873158831589315903159131592315933159431595315963159731598315993160031601316023160331604316053160631607316083160931610316113161231613316143161531616316173161831619316203162131622316233162431625316263162731628316293163031631316323163331634316353163631637316383163931640316413164231643316443164531646316473164831649316503165131652316533165431655316563165731658316593166031661316623166331664316653166631667316683166931670316713167231673316743167531676316773167831679316803168131682316833168431685316863168731688316893169031691316923169331694316953169631697316983169931700317013170231703317043170531706317073170831709317103171131712317133171431715317163171731718317193172031721317223172331724317253172631727317283172931730317313173231733317343173531736317373173831739317403174131742317433174431745317463174731748317493175031751317523175331754317553175631757317583175931760317613176231763317643176531766317673176831769317703177131772317733177431775317763177731778317793178031781317823178331784317853178631787317883178931790317913179231793317943179531796317973179831799318003180131802318033180431805318063180731808318093181031811318123181331814318153181631817318183181931820318213182231823318243182531826318273182831829318303183131832318333183431835318363183731838318393184031841318423184331844318453184631847318483184931850318513185231853318543185531856318573185831859318603186131862318633186431865318663186731868318693187031871318723187331874318753187631877318783187931880318813188231883318843188531886318873188831889318903189131892318933189431895318963189731898318993190031901319023190331904319053190631907319083190931910319113191231913319143191531916319173191831919319203192131922319233192431925319263192731928319293193031931319323193331934319353193631937319383193931940319413194231943319443194531946319473194831949319503195131952319533195431955319563195731958319593196031961319623196331964319653196631967319683196931970319713197231973319743197531976319773197831979319803198131982319833198431985319863198731988319893199031991319923199331994319953199631997319983199932000320013200232003320043200532006320073200832009320103201132012320133201432015320163201732018320193202032021320223202332024320253202632027320283202932030320313203232033320343203532036320373203832039320403204132042320433204432045320463204732048320493205032051320523205332054320553205632057320583205932060320613206232063320643206532066320673206832069320703207132072320733207432075320763207732078320793208032081320823208332084320853208632087320883208932090320913209232093320943209532096320973209832099321003210132102321033210432105321063210732108321093211032111321123211332114321153211632117321183211932120321213212232123321243212532126321273212832129321303213132132321333213432135321363213732138321393214032141321423214332144321453214632147321483214932150321513215232153321543215532156321573215832159321603216132162321633216432165321663216732168321693217032171321723217332174321753217632177321783217932180321813218232183321843218532186321873218832189321903219132192321933219432195321963219732198321993220032201322023220332204322053220632207322083220932210322113221232213322143221532216322173221832219322203222132222322233222432225322263222732228322293223032231322323223332234322353223632237322383223932240322413224232243322443224532246322473224832249322503225132252322533225432255322563225732258322593226032261322623226332264322653226632267322683226932270322713227232273322743227532276322773227832279322803228132282322833228432285322863228732288322893229032291322923229332294322953229632297322983229932300323013230232303323043230532306323073230832309323103231132312323133231432315323163231732318323193232032321323223232332324323253232632327323283232932330323313233232333323343233532336323373233832339323403234132342323433234432345323463234732348323493235032351323523235332354323553235632357323583235932360323613236232363323643236532366323673236832369323703237132372323733237432375323763237732378323793238032381323823238332384323853238632387323883238932390323913239232393323943239532396323973239832399324003240132402324033240432405324063240732408324093241032411324123241332414324153241632417324183241932420324213242232423324243242532426324273242832429324303243132432324333243432435324363243732438324393244032441324423244332444324453244632447324483244932450324513245232453324543245532456324573245832459324603246132462324633246432465324663246732468324693247032471324723247332474324753247632477324783247932480324813248232483324843248532486324873248832489324903249132492324933249432495324963249732498324993250032501325023250332504325053250632507325083250932510325113251232513325143251532516325173251832519325203252132522325233252432525325263252732528325293253032531325323253332534325353253632537325383253932540325413254232543325443254532546325473254832549325503255132552325533255432555325563255732558325593256032561325623256332564325653256632567325683256932570325713257232573325743257532576325773257832579325803258132582325833258432585325863258732588325893259032591325923259332594325953259632597325983259932600326013260232603326043260532606326073260832609326103261132612326133261432615326163261732618326193262032621326223262332624326253262632627326283262932630326313263232633326343263532636326373263832639326403264132642326433264432645326463264732648326493265032651326523265332654326553265632657326583265932660326613266232663326643266532666326673266832669326703267132672326733267432675326763267732678326793268032681326823268332684326853268632687326883268932690326913269232693326943269532696326973269832699327003270132702327033270432705327063270732708327093271032711327123271332714327153271632717327183271932720327213272232723327243272532726327273272832729327303273132732327333273432735327363273732738327393274032741327423274332744327453274632747327483274932750327513275232753327543275532756327573275832759327603276132762327633276432765327663276732768327693277032771327723277332774327753277632777327783277932780327813278232783327843278532786327873278832789327903279132792327933279432795327963279732798327993280032801328023280332804328053280632807328083280932810328113281232813328143281532816328173281832819328203282132822328233282432825328263282732828328293283032831328323283332834328353283632837328383283932840328413284232843328443284532846328473284832849328503285132852328533285432855328563285732858328593286032861328623286332864328653286632867328683286932870328713287232873328743287532876328773287832879328803288132882328833288432885328863288732888328893289032891328923289332894328953289632897328983289932900329013290232903329043290532906329073290832909329103291132912329133291432915329163291732918329193292032921329223292332924329253292632927329283292932930329313293232933329343293532936329373293832939329403294132942329433294432945329463294732948329493295032951329523295332954329553295632957329583295932960329613296232963329643296532966329673296832969329703297132972329733297432975329763297732978329793298032981329823298332984329853298632987329883298932990329913299232993329943299532996329973299832999330003300133002330033300433005330063300733008330093301033011330123301333014330153301633017330183301933020330213302233023330243302533026330273302833029330303303133032330333303433035330363303733038330393304033041330423304333044330453304633047330483304933050330513305233053330543305533056330573305833059330603306133062330633306433065330663306733068330693307033071330723307333074330753307633077330783307933080330813308233083330843308533086330873308833089330903309133092330933309433095330963309733098330993310033101331023310333104331053310633107331083310933110331113311233113331143311533116331173311833119331203312133122331233312433125331263312733128331293313033131331323313333134331353313633137331383313933140331413314233143331443314533146331473314833149331503315133152331533315433155331563315733158331593316033161331623316333164331653316633167331683316933170331713317233173331743317533176331773317833179331803318133182331833318433185331863318733188331893319033191331923319333194331953319633197331983319933200332013320233203332043320533206332073320833209332103321133212332133321433215332163321733218332193322033221332223322333224332253322633227332283322933230332313323233233332343323533236332373323833239332403324133242332433324433245332463324733248332493325033251332523325333254332553325633257332583325933260332613326233263332643326533266332673326833269332703327133272332733327433275332763327733278332793328033281332823328333284332853328633287332883328933290332913329233293332943329533296332973329833299333003330133302333033330433305333063330733308333093331033311333123331333314333153331633317333183331933320333213332233323333243332533326333273332833329333303333133332333333333433335333363333733338333393334033341333423334333344333453334633347333483334933350333513335233353333543335533356333573335833359333603336133362333633336433365333663336733368333693337033371333723337333374333753337633377333783337933380333813338233383333843338533386333873338833389333903339133392333933339433395333963339733398333993340033401334023340333404334053340633407334083340933410334113341233413334143341533416334173341833419334203342133422334233342433425334263342733428334293343033431334323343333434334353343633437334383343933440334413344233443334443344533446334473344833449334503345133452334533345433455334563345733458334593346033461334623346333464334653346633467334683346933470334713347233473334743347533476334773347833479334803348133482334833348433485334863348733488334893349033491334923349333494334953349633497334983349933500335013350233503335043350533506335073350833509335103351133512335133351433515335163351733518335193352033521335223352333524335253352633527335283352933530335313353233533335343353533536335373353833539335403354133542335433354433545335463354733548335493355033551335523355333554335553355633557335583355933560335613356233563335643356533566335673356833569335703357133572335733357433575335763357733578335793358033581335823358333584335853358633587335883358933590335913359233593335943359533596335973359833599336003360133602336033360433605336063360733608336093361033611336123361333614336153361633617336183361933620336213362233623336243362533626336273362833629336303363133632336333363433635336363363733638336393364033641336423364333644336453364633647336483364933650336513365233653336543365533656336573365833659336603366133662336633366433665336663366733668336693367033671336723367333674336753367633677336783367933680336813368233683336843368533686336873368833689336903369133692336933369433695336963369733698336993370033701337023370333704337053370633707337083370933710337113371233713337143371533716337173371833719337203372133722337233372433725337263372733728337293373033731337323373333734337353373633737337383373933740337413374233743337443374533746337473374833749337503375133752337533375433755337563375733758337593376033761337623376333764337653376633767337683376933770337713377233773337743377533776337773377833779337803378133782337833378433785337863378733788337893379033791337923379333794337953379633797337983379933800338013380233803338043380533806338073380833809338103381133812338133381433815338163381733818338193382033821338223382333824338253382633827338283382933830338313383233833338343383533836338373383833839338403384133842338433384433845338463384733848338493385033851338523385333854338553385633857338583385933860338613386233863338643386533866338673386833869338703387133872338733387433875338763387733878338793388033881338823388333884338853388633887338883388933890338913389233893338943389533896338973389833899339003390133902339033390433905339063390733908339093391033911339123391333914339153391633917339183391933920339213392233923339243392533926339273392833929339303393133932339333393433935339363393733938339393394033941339423394333944339453394633947339483394933950339513395233953339543395533956339573395833959339603396133962339633396433965339663396733968339693397033971339723397333974339753397633977339783397933980339813398233983339843398533986339873398833989339903399133992339933399433995339963399733998339993400034001340023400334004340053400634007340083400934010340113401234013340143401534016340173401834019340203402134022340233402434025340263402734028340293403034031340323403334034340353403634037340383403934040340413404234043340443404534046340473404834049340503405134052340533405434055340563405734058340593406034061340623406334064340653406634067340683406934070340713407234073340743407534076340773407834079340803408134082340833408434085340863408734088340893409034091340923409334094340953409634097340983409934100341013410234103341043410534106341073410834109341103411134112341133411434115341163411734118341193412034121341223412334124341253412634127341283412934130341313413234133341343413534136341373413834139341403414134142341433414434145341463414734148341493415034151341523415334154341553415634157341583415934160341613416234163341643416534166341673416834169341703417134172341733417434175341763417734178341793418034181341823418334184341853418634187341883418934190341913419234193341943419534196341973419834199342003420134202342033420434205342063420734208342093421034211342123421334214342153421634217342183421934220342213422234223342243422534226342273422834229342303423134232342333423434235342363423734238342393424034241342423424334244342453424634247342483424934250342513425234253342543425534256342573425834259342603426134262342633426434265342663426734268342693427034271342723427334274342753427634277342783427934280342813428234283342843428534286342873428834289342903429134292342933429434295342963429734298342993430034301343023430334304343053430634307343083430934310343113431234313343143431534316343173431834319343203432134322343233432434325343263432734328343293433034331343323433334334343353433634337343383433934340343413434234343343443434534346343473434834349343503435134352343533435434355343563435734358343593436034361343623436334364343653436634367343683436934370343713437234373343743437534376343773437834379343803438134382343833438434385343863438734388343893439034391343923439334394343953439634397343983439934400344013440234403344043440534406344073440834409344103441134412344133441434415344163441734418344193442034421344223442334424344253442634427344283442934430344313443234433344343443534436344373443834439344403444134442344433444434445344463444734448344493445034451344523445334454344553445634457344583445934460344613446234463344643446534466344673446834469344703447134472344733447434475344763447734478344793448034481344823448334484344853448634487344883448934490344913449234493344943449534496344973449834499345003450134502345033450434505345063450734508345093451034511345123451334514345153451634517345183451934520345213452234523345243452534526345273452834529345303453134532345333453434535345363453734538345393454034541345423454334544345453454634547345483454934550345513455234553345543455534556345573455834559345603456134562345633456434565345663456734568345693457034571345723457334574345753457634577345783457934580345813458234583345843458534586345873458834589345903459134592345933459434595345963459734598345993460034601346023460334604346053460634607346083460934610346113461234613346143461534616346173461834619346203462134622346233462434625346263462734628346293463034631346323463334634346353463634637346383463934640346413464234643346443464534646346473464834649346503465134652346533465434655346563465734658346593466034661346623466334664346653466634667346683466934670346713467234673346743467534676346773467834679346803468134682346833468434685346863468734688346893469034691346923469334694346953469634697346983469934700347013470234703347043470534706347073470834709347103471134712347133471434715347163471734718347193472034721347223472334724347253472634727347283472934730347313473234733347343473534736347373473834739347403474134742347433474434745347463474734748347493475034751347523475334754347553475634757347583475934760347613476234763347643476534766347673476834769347703477134772347733477434775347763477734778347793478034781347823478334784347853478634787347883478934790347913479234793347943479534796347973479834799348003480134802348033480434805348063480734808348093481034811348123481334814348153481634817348183481934820348213482234823348243482534826348273482834829348303483134832348333483434835348363483734838348393484034841348423484334844348453484634847348483484934850348513485234853348543485534856348573485834859348603486134862348633486434865348663486734868348693487034871348723487334874348753487634877348783487934880348813488234883348843488534886348873488834889348903489134892348933489434895348963489734898348993490034901349023490334904349053490634907349083490934910349113491234913349143491534916349173491834919349203492134922349233492434925349263492734928349293493034931349323493334934349353493634937349383493934940349413494234943349443494534946349473494834949349503495134952349533495434955349563495734958349593496034961349623496334964349653496634967349683496934970349713497234973349743497534976349773497834979349803498134982349833498434985349863498734988349893499034991349923499334994349953499634997349983499935000350013500235003350043500535006350073500835009350103501135012350133501435015350163501735018350193502035021350223502335024350253502635027350283502935030350313503235033350343503535036350373503835039350403504135042350433504435045350463504735048350493505035051350523505335054350553505635057350583505935060350613506235063350643506535066350673506835069350703507135072350733507435075350763507735078350793508035081350823508335084350853508635087350883508935090350913509235093350943509535096350973509835099351003510135102351033510435105351063510735108351093511035111351123511335114351153511635117351183511935120351213512235123351243512535126351273512835129351303513135132351333513435135351363513735138351393514035141351423514335144351453514635147351483514935150351513515235153351543515535156351573515835159351603516135162351633516435165351663516735168351693517035171351723517335174351753517635177351783517935180351813518235183351843518535186351873518835189351903519135192351933519435195351963519735198351993520035201352023520335204352053520635207352083520935210352113521235213352143521535216352173521835219352203522135222352233522435225352263522735228352293523035231352323523335234352353523635237352383523935240352413524235243352443524535246352473524835249352503525135252352533525435255352563525735258352593526035261352623526335264352653526635267352683526935270352713527235273352743527535276352773527835279352803528135282352833528435285352863528735288352893529035291352923529335294352953529635297352983529935300353013530235303353043530535306353073530835309353103531135312353133531435315353163531735318353193532035321353223532335324353253532635327353283532935330353313533235333353343533535336353373533835339353403534135342353433534435345353463534735348353493535035351353523535335354353553535635357353583535935360353613536235363353643536535366353673536835369353703537135372353733537435375353763537735378353793538035381353823538335384353853538635387353883538935390353913539235393353943539535396353973539835399354003540135402354033540435405354063540735408354093541035411354123541335414354153541635417354183541935420354213542235423354243542535426354273542835429354303543135432354333543435435354363543735438354393544035441354423544335444354453544635447354483544935450354513545235453354543545535456354573545835459354603546135462354633546435465354663546735468354693547035471354723547335474354753547635477354783547935480354813548235483354843548535486354873548835489354903549135492354933549435495354963549735498354993550035501355023550335504355053550635507355083550935510355113551235513355143551535516355173551835519355203552135522355233552435525355263552735528355293553035531355323553335534355353553635537355383553935540355413554235543355443554535546355473554835549355503555135552355533555435555355563555735558355593556035561355623556335564355653556635567355683556935570355713557235573355743557535576355773557835579355803558135582355833558435585355863558735588355893559035591355923559335594355953559635597355983559935600356013560235603356043560535606356073560835609356103561135612356133561435615356163561735618356193562035621356223562335624356253562635627356283562935630356313563235633356343563535636356373563835639356403564135642356433564435645356463564735648356493565035651356523565335654356553565635657356583565935660356613566235663356643566535666356673566835669356703567135672356733567435675356763567735678356793568035681356823568335684356853568635687356883568935690356913569235693356943569535696356973569835699357003570135702357033570435705357063570735708357093571035711357123571335714357153571635717357183571935720357213572235723357243572535726357273572835729357303573135732357333573435735357363573735738357393574035741357423574335744357453574635747357483574935750357513575235753357543575535756357573575835759357603576135762357633576435765357663576735768357693577035771357723577335774357753577635777357783577935780357813578235783357843578535786357873578835789357903579135792357933579435795357963579735798357993580035801358023580335804358053580635807358083580935810358113581235813358143581535816358173581835819358203582135822358233582435825358263582735828358293583035831358323583335834358353583635837358383583935840358413584235843358443584535846358473584835849358503585135852358533585435855358563585735858358593586035861358623586335864358653586635867358683586935870358713587235873358743587535876358773587835879358803588135882358833588435885358863588735888358893589035891358923589335894358953589635897358983589935900359013590235903359043590535906359073590835909359103591135912359133591435915359163591735918359193592035921359223592335924359253592635927359283592935930359313593235933359343593535936359373593835939359403594135942359433594435945359463594735948359493595035951359523595335954359553595635957359583595935960359613596235963359643596535966359673596835969359703597135972359733597435975359763597735978359793598035981359823598335984359853598635987359883598935990359913599235993359943599535996359973599835999360003600136002360033600436005360063600736008360093601036011360123601336014360153601636017360183601936020360213602236023360243602536026360273602836029360303603136032360333603436035360363603736038360393604036041360423604336044360453604636047360483604936050360513605236053360543605536056360573605836059360603606136062360633606436065360663606736068360693607036071360723607336074360753607636077360783607936080360813608236083360843608536086360873608836089360903609136092360933609436095360963609736098360993610036101361023610336104361053610636107361083610936110361113611236113361143611536116361173611836119361203612136122361233612436125361263612736128361293613036131361323613336134361353613636137361383613936140361413614236143361443614536146361473614836149361503615136152361533615436155361563615736158361593616036161361623616336164361653616636167361683616936170361713617236173361743617536176361773617836179361803618136182361833618436185361863618736188361893619036191361923619336194361953619636197361983619936200362013620236203362043620536206362073620836209362103621136212362133621436215362163621736218362193622036221362223622336224362253622636227362283622936230362313623236233362343623536236362373623836239362403624136242362433624436245362463624736248362493625036251362523625336254362553625636257362583625936260362613626236263362643626536266362673626836269362703627136272362733627436275362763627736278362793628036281362823628336284362853628636287362883628936290362913629236293362943629536296362973629836299363003630136302363033630436305363063630736308363093631036311363123631336314363153631636317363183631936320363213632236323363243632536326363273632836329363303633136332363333633436335363363633736338363393634036341363423634336344363453634636347363483634936350363513635236353363543635536356363573635836359363603636136362363633636436365363663636736368363693637036371363723637336374363753637636377363783637936380363813638236383363843638536386363873638836389363903639136392363933639436395363963639736398363993640036401364023640336404364053640636407364083640936410364113641236413364143641536416364173641836419364203642136422364233642436425364263642736428364293643036431364323643336434364353643636437364383643936440364413644236443364443644536446364473644836449364503645136452364533645436455364563645736458364593646036461364623646336464364653646636467364683646936470364713647236473364743647536476364773647836479364803648136482364833648436485364863648736488364893649036491364923649336494364953649636497364983649936500365013650236503365043650536506365073650836509365103651136512365133651436515365163651736518365193652036521365223652336524365253652636527365283652936530365313653236533365343653536536365373653836539365403654136542365433654436545365463654736548365493655036551365523655336554365553655636557365583655936560365613656236563365643656536566365673656836569365703657136572365733657436575365763657736578365793658036581365823658336584365853658636587365883658936590365913659236593365943659536596365973659836599366003660136602366033660436605366063660736608366093661036611366123661336614366153661636617366183661936620366213662236623366243662536626366273662836629366303663136632366333663436635366363663736638366393664036641366423664336644366453664636647366483664936650366513665236653366543665536656366573665836659366603666136662366633666436665366663666736668366693667036671366723667336674366753667636677366783667936680366813668236683366843668536686366873668836689366903669136692366933669436695366963669736698366993670036701367023670336704367053670636707367083670936710367113671236713367143671536716367173671836719367203672136722367233672436725367263672736728367293673036731367323673336734367353673636737367383673936740367413674236743367443674536746367473674836749367503675136752367533675436755367563675736758367593676036761367623676336764367653676636767367683676936770367713677236773367743677536776367773677836779367803678136782367833678436785367863678736788367893679036791367923679336794367953679636797367983679936800368013680236803368043680536806368073680836809368103681136812368133681436815368163681736818368193682036821368223682336824368253682636827368283682936830368313683236833368343683536836368373683836839368403684136842368433684436845368463684736848368493685036851368523685336854368553685636857368583685936860368613686236863368643686536866368673686836869368703687136872368733687436875368763687736878368793688036881368823688336884368853688636887368883688936890368913689236893368943689536896368973689836899369003690136902369033690436905369063690736908369093691036911369123691336914369153691636917369183691936920369213692236923369243692536926369273692836929369303693136932369333693436935369363693736938369393694036941369423694336944369453694636947369483694936950369513695236953369543695536956369573695836959369603696136962369633696436965369663696736968369693697036971369723697336974369753697636977369783697936980369813698236983369843698536986369873698836989369903699136992369933699436995369963699736998369993700037001370023700337004370053700637007370083700937010370113701237013370143701537016370173701837019370203702137022370233702437025370263702737028370293703037031370323703337034370353703637037370383703937040370413704237043370443704537046370473704837049370503705137052370533705437055370563705737058370593706037061370623706337064370653706637067370683706937070370713707237073370743707537076370773707837079370803708137082370833708437085370863708737088370893709037091370923709337094370953709637097370983709937100371013710237103371043710537106371073710837109371103711137112371133711437115371163711737118371193712037121371223712337124371253712637127371283712937130371313713237133371343713537136371373713837139371403714137142371433714437145371463714737148371493715037151371523715337154371553715637157371583715937160371613716237163371643716537166371673716837169371703717137172371733717437175371763717737178371793718037181371823718337184371853718637187371883718937190371913719237193371943719537196371973719837199372003720137202372033720437205372063720737208372093721037211372123721337214372153721637217372183721937220372213722237223372243722537226372273722837229372303723137232372333723437235372363723737238372393724037241372423724337244372453724637247372483724937250372513725237253372543725537256372573725837259372603726137262372633726437265372663726737268372693727037271372723727337274372753727637277372783727937280372813728237283372843728537286372873728837289372903729137292372933729437295372963729737298372993730037301373023730337304373053730637307373083730937310373113731237313373143731537316373173731837319373203732137322373233732437325373263732737328373293733037331373323733337334373353733637337373383733937340373413734237343373443734537346373473734837349373503735137352373533735437355373563735737358373593736037361373623736337364373653736637367373683736937370373713737237373373743737537376373773737837379373803738137382373833738437385373863738737388373893739037391373923739337394373953739637397373983739937400374013740237403374043740537406374073740837409374103741137412374133741437415374163741737418374193742037421374223742337424374253742637427374283742937430374313743237433374343743537436374373743837439374403744137442374433744437445374463744737448374493745037451374523745337454374553745637457374583745937460374613746237463374643746537466374673746837469374703747137472374733747437475374763747737478374793748037481374823748337484374853748637487374883748937490374913749237493374943749537496374973749837499375003750137502375033750437505375063750737508375093751037511375123751337514375153751637517375183751937520375213752237523375243752537526375273752837529375303753137532375333753437535375363753737538375393754037541375423754337544375453754637547375483754937550375513755237553375543755537556375573755837559375603756137562375633756437565375663756737568375693757037571375723757337574375753757637577375783757937580375813758237583375843758537586375873758837589375903759137592375933759437595375963759737598375993760037601376023760337604376053760637607376083760937610376113761237613376143761537616376173761837619376203762137622376233762437625376263762737628376293763037631376323763337634376353763637637376383763937640376413764237643376443764537646376473764837649376503765137652376533765437655376563765737658376593766037661376623766337664376653766637667376683766937670376713767237673376743767537676376773767837679376803768137682376833768437685376863768737688376893769037691376923769337694376953769637697376983769937700377013770237703377043770537706377073770837709377103771137712377133771437715377163771737718377193772037721377223772337724377253772637727377283772937730377313773237733377343773537736377373773837739377403774137742377433774437745377463774737748377493775037751377523775337754377553775637757377583775937760377613776237763377643776537766377673776837769377703777137772377733777437775377763777737778377793778037781377823778337784377853778637787377883778937790377913779237793377943779537796377973779837799378003780137802378033780437805378063780737808378093781037811378123781337814378153781637817378183781937820378213782237823378243782537826378273782837829378303783137832378333783437835378363783737838378393784037841378423784337844378453784637847378483784937850378513785237853378543785537856378573785837859378603786137862378633786437865378663786737868378693787037871378723787337874378753787637877378783787937880378813788237883378843788537886378873788837889378903789137892378933789437895378963789737898378993790037901379023790337904379053790637907379083790937910379113791237913379143791537916379173791837919379203792137922379233792437925379263792737928379293793037931379323793337934379353793637937379383793937940379413794237943379443794537946379473794837949379503795137952379533795437955379563795737958379593796037961379623796337964379653796637967379683796937970379713797237973379743797537976379773797837979379803798137982379833798437985379863798737988379893799037991379923799337994379953799637997379983799938000380013800238003380043800538006380073800838009380103801138012380133801438015380163801738018380193802038021380223802338024380253802638027380283802938030380313803238033380343803538036380373803838039380403804138042380433804438045380463804738048380493805038051380523805338054380553805638057380583805938060380613806238063380643806538066380673806838069380703807138072380733807438075380763807738078380793808038081380823808338084380853808638087380883808938090380913809238093380943809538096380973809838099381003810138102381033810438105381063810738108381093811038111381123811338114381153811638117381183811938120381213812238123381243812538126381273812838129381303813138132381333813438135381363813738138381393814038141381423814338144381453814638147381483814938150381513815238153381543815538156381573815838159381603816138162381633816438165381663816738168381693817038171381723817338174381753817638177381783817938180381813818238183381843818538186381873818838189381903819138192381933819438195381963819738198381993820038201382023820338204382053820638207382083820938210382113821238213382143821538216382173821838219382203822138222382233822438225382263822738228382293823038231382323823338234382353823638237382383823938240382413824238243382443824538246382473824838249382503825138252382533825438255382563825738258382593826038261382623826338264382653826638267382683826938270382713827238273382743827538276382773827838279382803828138282382833828438285382863828738288382893829038291382923829338294382953829638297382983829938300383013830238303383043830538306383073830838309383103831138312383133831438315383163831738318383193832038321383223832338324383253832638327383283832938330383313833238333383343833538336383373833838339383403834138342383433834438345383463834738348383493835038351383523835338354383553835638357383583835938360383613836238363383643836538366383673836838369383703837138372383733837438375383763837738378383793838038381383823838338384383853838638387383883838938390383913839238393383943839538396383973839838399384003840138402384033840438405384063840738408384093841038411384123841338414384153841638417384183841938420384213842238423384243842538426384273842838429384303843138432384333843438435384363843738438384393844038441384423844338444384453844638447384483844938450384513845238453384543845538456384573845838459384603846138462384633846438465384663846738468384693847038471384723847338474384753847638477384783847938480384813848238483384843848538486384873848838489384903849138492384933849438495384963849738498384993850038501385023850338504385053850638507385083850938510385113851238513385143851538516385173851838519385203852138522385233852438525385263852738528385293853038531385323853338534385353853638537385383853938540385413854238543385443854538546385473854838549385503855138552385533855438555385563855738558385593856038561385623856338564385653856638567385683856938570385713857238573385743857538576385773857838579385803858138582385833858438585385863858738588385893859038591385923859338594385953859638597385983859938600386013860238603386043860538606386073860838609386103861138612386133861438615386163861738618386193862038621386223862338624386253862638627386283862938630386313863238633386343863538636386373863838639386403864138642386433864438645386463864738648386493865038651386523865338654386553865638657386583865938660386613866238663386643866538666386673866838669386703867138672386733867438675386763867738678386793868038681386823868338684386853868638687386883868938690386913869238693386943869538696386973869838699387003870138702387033870438705387063870738708387093871038711387123871338714387153871638717387183871938720387213872238723387243872538726387273872838729387303873138732387333873438735387363873738738387393874038741387423874338744387453874638747387483874938750387513875238753387543875538756387573875838759387603876138762387633876438765387663876738768387693877038771387723877338774387753877638777387783877938780387813878238783387843878538786387873878838789387903879138792387933879438795387963879738798387993880038801388023880338804388053880638807388083880938810388113881238813388143881538816388173881838819388203882138822388233882438825388263882738828388293883038831388323883338834388353883638837388383883938840388413884238843388443884538846388473884838849388503885138852388533885438855388563885738858388593886038861388623886338864388653886638867388683886938870388713887238873388743887538876388773887838879388803888138882388833888438885388863888738888388893889038891388923889338894388953889638897388983889938900389013890238903389043890538906389073890838909389103891138912389133891438915389163891738918389193892038921389223892338924389253892638927389283892938930389313893238933389343893538936389373893838939389403894138942389433894438945389463894738948389493895038951389523895338954389553895638957389583895938960389613896238963389643896538966389673896838969389703897138972389733897438975389763897738978389793898038981389823898338984389853898638987389883898938990389913899238993389943899538996389973899838999390003900139002390033900439005390063900739008390093901039011390123901339014390153901639017390183901939020390213902239023390243902539026390273902839029390303903139032390333903439035390363903739038390393904039041390423904339044390453904639047390483904939050390513905239053390543905539056390573905839059390603906139062390633906439065390663906739068390693907039071390723907339074390753907639077390783907939080390813908239083390843908539086390873908839089390903909139092390933909439095390963909739098390993910039101391023910339104391053910639107391083910939110391113911239113391143911539116391173911839119391203912139122391233912439125391263912739128391293913039131391323913339134391353913639137391383913939140391413914239143391443914539146391473914839149391503915139152391533915439155391563915739158391593916039161391623916339164391653916639167391683916939170391713917239173391743917539176391773917839179391803918139182391833918439185391863918739188391893919039191391923919339194391953919639197391983919939200392013920239203392043920539206392073920839209392103921139212392133921439215392163921739218392193922039221392223922339224392253922639227392283922939230392313923239233392343923539236392373923839239392403924139242392433924439245392463924739248392493925039251392523925339254392553925639257392583925939260392613926239263392643926539266392673926839269392703927139272392733927439275392763927739278392793928039281392823928339284392853928639287392883928939290392913929239293392943929539296392973929839299393003930139302393033930439305393063930739308393093931039311393123931339314393153931639317393183931939320393213932239323393243932539326393273932839329393303933139332393333933439335393363933739338393393934039341393423934339344393453934639347393483934939350393513935239353393543935539356393573935839359393603936139362393633936439365393663936739368393693937039371393723937339374393753937639377393783937939380393813938239383393843938539386393873938839389393903939139392393933939439395393963939739398393993940039401394023940339404394053940639407394083940939410394113941239413394143941539416394173941839419394203942139422394233942439425394263942739428394293943039431394323943339434394353943639437394383943939440394413944239443394443944539446394473944839449394503945139452394533945439455394563945739458394593946039461394623946339464394653946639467394683946939470394713947239473394743947539476394773947839479394803948139482394833948439485394863948739488394893949039491394923949339494
  1. /* RetroArch - A frontend for libretro.
  2. * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
  3. * Copyright (C) 2011-2017 - 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/Discord 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. #ifdef _WIN32
  22. #ifdef _XBOX
  23. #include <xtl.h>
  24. #else
  25. #define WIN32_LEAN_AND_MEAN
  26. #include <windows.h>
  27. #endif
  28. #if defined(DEBUG) && defined(HAVE_DRMINGW)
  29. #include "exchndl.h"
  30. #endif
  31. #endif
  32. #if defined(DINGUX)
  33. #include <sys/types.h>
  34. #include <unistd.h>
  35. #endif
  36. #if (defined(__linux__) || defined(__unix__) || defined(DINGUX)) && !defined(EMSCRIPTEN)
  37. #include <signal.h>
  38. #endif
  39. #if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
  40. #ifndef LEGACY_WIN32
  41. #define LEGACY_WIN32
  42. #endif
  43. #endif
  44. #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
  45. #include <objbase.h>
  46. #include <process.h>
  47. #endif
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <stdarg.h>
  51. #include <stdint.h>
  52. #include <string.h>
  53. #include <ctype.h>
  54. #include <errno.h>
  55. #include <setjmp.h>
  56. #include <math.h>
  57. #include <locale.h>
  58. #include <boolean.h>
  59. #include <clamping.h>
  60. #include <string/stdstring.h>
  61. #include <streams/stdin_stream.h>
  62. #include <dynamic/dylib.h>
  63. #include <file/config_file.h>
  64. #include <lists/string_list.h>
  65. #include <memalign.h>
  66. #include <retro_math.h>
  67. #include <retro_timers.h>
  68. #include <encodings/utf.h>
  69. #include <time/rtime.h>
  70. #include <gfx/scaler/pixconv.h>
  71. #include <gfx/scaler/scaler.h>
  72. #include <gfx/video_frame.h>
  73. #include <libretro.h>
  74. #define VFS_FRONTEND
  75. #include <vfs/vfs_implementation.h>
  76. #include <features/features_cpu.h>
  77. #include <compat/strl.h>
  78. #include <compat/strcasestr.h>
  79. #include <compat/getopt.h>
  80. #include <audio/conversion/float_to_s16.h>
  81. #include <audio/conversion/s16_to_float.h>
  82. #ifdef HAVE_AUDIOMIXER
  83. #include <audio/audio_mixer.h>
  84. #endif
  85. #ifdef HAVE_DSP_FILTER
  86. #include <audio/dsp_filter.h>
  87. #endif
  88. #include <compat/posix_string.h>
  89. #include <streams/file_stream.h>
  90. #include <streams/interface_stream.h>
  91. #include <file/file_path.h>
  92. #include <retro_assert.h>
  93. #include <retro_miscellaneous.h>
  94. #include <queues/message_queue.h>
  95. #include <queues/task_queue.h>
  96. #include <lists/dir_list.h>
  97. #ifdef HAVE_NETWORKING
  98. #include <net/net_http.h>
  99. #endif
  100. #ifdef WIIU
  101. #include <wiiu/os/energy.h>
  102. #endif
  103. #ifdef EMSCRIPTEN
  104. #include <emscripten/emscripten.h>
  105. #endif
  106. #ifdef HAVE_LIBNX
  107. #include <switch.h>
  108. #include "switch_performance_profiles.h"
  109. #endif
  110. #if defined(ANDROID)
  111. #include "play_feature_delivery/play_feature_delivery.h"
  112. #endif
  113. #ifdef HAVE_DISCORD
  114. #include <discord_rpc.h>
  115. #include "deps/discord-rpc/include/discord_rpc.h"
  116. #include "network/discord.h"
  117. #endif
  118. #include "config.def.h"
  119. #include "config.def.keybinds.h"
  120. #include "runtime_file.h"
  121. #ifdef HAVE_CONFIG_H
  122. #include "config.h"
  123. #endif
  124. #ifdef HAVE_NETWORKING
  125. #include <net/net_compat.h>
  126. #include <net/net_socket.h>
  127. #endif
  128. #include <audio/audio_resampler.h>
  129. #include "gfx/gfx_animation.h"
  130. #include "gfx/gfx_display.h"
  131. #include "gfx/gfx_thumbnail.h"
  132. #include "gfx/video_filter.h"
  133. #include "input/input_osk.h"
  134. #ifdef HAVE_MENU
  135. #include "menu/menu_cbs.h"
  136. #include "menu/menu_driver.h"
  137. #include "menu/menu_input.h"
  138. #include "menu/menu_dialog.h"
  139. #include "menu/menu_input_bind_dialog.h"
  140. #endif
  141. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  142. #include "menu/menu_shader.h"
  143. #endif
  144. #ifdef HAVE_GFX_WIDGETS
  145. #include "gfx/gfx_widgets.h"
  146. #endif
  147. #include "input/input_keymaps.h"
  148. #include "input/input_remapping.h"
  149. #ifdef HAVE_CHEEVOS
  150. #include "cheevos/cheevos.h"
  151. #endif
  152. #ifdef HAVE_TRANSLATE
  153. #include <encodings/base64.h>
  154. #include <formats/rbmp.h>
  155. #include <formats/rpng.h>
  156. #include <formats/rjson.h>
  157. #include "translation_defines.h"
  158. #endif
  159. #ifdef HAVE_DISCORD
  160. #include "network/discord.h"
  161. #endif
  162. #ifdef HAVE_NETWORKING
  163. #include "network/netplay/netplay.h"
  164. #include "network/netplay/netplay_private.h"
  165. #include "network/netplay/netplay_discovery.h"
  166. #endif
  167. #ifdef HAVE_THREADS
  168. #include <rthreads/rthreads.h>
  169. #endif
  170. #if defined(HAVE_OPENGL)
  171. #include "gfx/common/gl_common.h"
  172. #elif defined(HAVE_OPENGL_CORE)
  173. #include "gfx/common/gl_core_common.h"
  174. #endif
  175. #include "autosave.h"
  176. #include "command.h"
  177. #include "config.features.h"
  178. #include "cores/internal_cores.h"
  179. #include "content.h"
  180. #include "core_type.h"
  181. #include "core_info.h"
  182. #include "dynamic.h"
  183. #include "defaults.h"
  184. #include "driver.h"
  185. #include "msg_hash.h"
  186. #include "paths.h"
  187. #include "file_path_special.h"
  188. #include "ui/ui_companion_driver.h"
  189. #include "verbosity.h"
  190. #include "frontend/frontend_driver.h"
  191. #ifdef HAVE_THREADS
  192. #include "gfx/video_thread_wrapper.h"
  193. #endif
  194. #include "gfx/video_display_server.h"
  195. #include "gfx/video_crt_switch.h"
  196. #include "bluetooth/bluetooth_driver.h"
  197. #include "wifi/wifi_driver.h"
  198. #include "led/led_driver.h"
  199. #include "midi/midi_driver.h"
  200. #include "core.h"
  201. #include "configuration.h"
  202. #include "list_special.h"
  203. #include "core_option_manager.h"
  204. #ifdef HAVE_CHEATS
  205. #include "cheat_manager.h"
  206. #endif
  207. #ifdef HAVE_REWIND
  208. #include "state_manager.h"
  209. #endif
  210. #ifdef HAVE_AUDIOMIXER
  211. #include "tasks/task_audio_mixer.h"
  212. #endif
  213. #include "tasks/task_content.h"
  214. #include "tasks/task_file_transfer.h"
  215. #include "tasks/task_powerstate.h"
  216. #include "tasks/tasks_internal.h"
  217. #include "performance_counters.h"
  218. #include "version.h"
  219. #include "version_git.h"
  220. #include "retroarch.h"
  221. #ifdef HAVE_ACCESSIBILITY
  222. #include "accessibility.h"
  223. #endif
  224. #ifdef HAVE_THREADS
  225. #include "audio/audio_thread_wrapper.h"
  226. #endif
  227. #ifdef HAVE_LANGEXTRA
  228. /* This file has a UTF8 BOM, we assume HAVE_LANGEXTRA
  229. * is only enabled for compilers that can support this. */
  230. #include "input/input_osk_utf8_pages.h"
  231. #endif
  232. /* RetroArch global state / macros */
  233. #include "retroarch_data.h"
  234. /* Forward declarations */
  235. #include "retroarch_fwd_decls.h"
  236. /* GLOBAL POINTER GETTERS */
  237. #ifdef HAVE_NETWORKING
  238. struct netplay_room* netplay_get_host_room(void)
  239. {
  240. struct rarch_state *p_rarch = &rarch_st;
  241. return &p_rarch->netplay_host_room;
  242. }
  243. #endif
  244. #ifdef HAVE_REWIND
  245. bool state_manager_frame_is_reversed(void)
  246. {
  247. struct rarch_state *p_rarch = &rarch_st;
  248. struct state_manager_rewind_state
  249. *rewind_st = &p_rarch->rewind_st;
  250. return rewind_st->frame_is_reversed;
  251. }
  252. #endif
  253. gfx_animation_t *anim_get_ptr(void)
  254. {
  255. struct rarch_state *p_rarch = &rarch_st;
  256. return &p_rarch->anim;
  257. }
  258. content_state_t *content_state_get_ptr(void)
  259. {
  260. struct rarch_state *p_rarch = &rarch_st;
  261. return &p_rarch->content_st;
  262. }
  263. /* Get the current subsystem rom id */
  264. unsigned content_get_subsystem_rom_id(void)
  265. {
  266. struct rarch_state *p_rarch = &rarch_st;
  267. content_state_t *p_content = &p_rarch->content_st;
  268. return p_content->pending_subsystem_rom_id;
  269. }
  270. /* Get the current subsystem */
  271. int content_get_subsystem(void)
  272. {
  273. struct rarch_state *p_rarch = &rarch_st;
  274. content_state_t *p_content = &p_rarch->content_st;
  275. return p_content->pending_subsystem_id;
  276. }
  277. int input_event_get_osk_ptr(void)
  278. {
  279. struct rarch_state *p_rarch = &rarch_st;
  280. return p_rarch->osk_ptr;
  281. }
  282. char **input_event_get_osk_grid(void)
  283. {
  284. struct rarch_state *p_rarch = &rarch_st;
  285. return p_rarch->osk_grid;
  286. }
  287. core_info_state_t *coreinfo_get_ptr(void)
  288. {
  289. struct rarch_state *p_rarch = &rarch_st;
  290. return &p_rarch->core_info_st;
  291. }
  292. gfx_thumbnail_state_t *gfx_thumb_get_ptr(void)
  293. {
  294. struct rarch_state *p_rarch = &rarch_st;
  295. return &p_rarch->gfx_thumb_state;
  296. }
  297. #ifdef HAVE_MENU
  298. menu_handle_t *menu_driver_get_ptr(void)
  299. {
  300. struct rarch_state *p_rarch = &rarch_st;
  301. return p_rarch->menu_driver_data;
  302. }
  303. size_t menu_navigation_get_selection(void)
  304. {
  305. struct rarch_state *p_rarch = &rarch_st;
  306. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  307. return menu_st->selection_ptr;
  308. }
  309. #endif
  310. struct retro_hw_render_callback *video_driver_get_hw_context(void)
  311. {
  312. struct rarch_state *p_rarch = &rarch_st;
  313. return VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
  314. }
  315. struct retro_system_av_info *video_viewport_get_system_av_info(void)
  316. {
  317. struct rarch_state *p_rarch = &rarch_st;
  318. return &p_rarch->video_driver_av_info;
  319. }
  320. gfx_display_t *disp_get_ptr(void)
  321. {
  322. struct rarch_state *p_rarch = &rarch_st;
  323. return &p_rarch->dispgfx;
  324. }
  325. #ifdef HAVE_GFX_WIDGETS
  326. void *dispwidget_get_ptr(void)
  327. {
  328. struct rarch_state *p_rarch = &rarch_st;
  329. return &p_rarch->dispwidget_st;
  330. }
  331. #endif
  332. settings_t *config_get_ptr(void)
  333. {
  334. struct rarch_state *p_rarch = &rarch_st;
  335. return p_rarch->configuration_settings;
  336. }
  337. global_t *global_get_ptr(void)
  338. {
  339. struct rarch_state *p_rarch = &rarch_st;
  340. return &p_rarch->g_extern;
  341. }
  342. #ifdef HAVE_THREADS
  343. /**
  344. * video_thread_get_ptr:
  345. * @drv : Found driver.
  346. *
  347. * Gets the underlying video driver associated with the
  348. * threaded video wrapper. Sets @drv to the found
  349. * video driver.
  350. *
  351. * Returns: Video driver data of the video driver associated
  352. * with the threaded wrapper (if successful). If not successful,
  353. * NULL.
  354. **/
  355. static void *video_thread_get_ptr(struct rarch_state *p_rarch)
  356. {
  357. void *data = VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch, true);
  358. const thread_video_t *thr = (const thread_video_t*)data;
  359. if (thr)
  360. return thr->driver_data;
  361. return NULL;
  362. }
  363. #endif
  364. /**
  365. * video_driver_get_ptr:
  366. *
  367. * Use this if you need the real video driver
  368. * and driver data pointers.
  369. *
  370. * Returns: video driver's userdata.
  371. **/
  372. void *video_driver_get_ptr(bool force_nonthreaded_data)
  373. {
  374. struct rarch_state *p_rarch = &rarch_st;
  375. return VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch, force_nonthreaded_data);
  376. }
  377. static int16_t input_state_wrap(
  378. input_driver_t *current_input,
  379. void *data,
  380. const input_device_driver_t *joypad,
  381. const input_device_driver_t *sec_joypad,
  382. rarch_joypad_info_t *joypad_info,
  383. const struct retro_keybind **binds,
  384. bool keyboard_mapping_blocked,
  385. unsigned port,
  386. unsigned device,
  387. unsigned idx,
  388. unsigned id)
  389. {
  390. int16_t ret = 0;
  391. /* Do a bitwise OR to combine input states together */
  392. if (device == RETRO_DEVICE_JOYPAD)
  393. {
  394. if (id == RETRO_DEVICE_ID_JOYPAD_MASK)
  395. {
  396. ret |= joypad->state(
  397. joypad_info, binds[port], port);
  398. #ifdef HAVE_MFI
  399. if (sec_joypad)
  400. ret |= sec_joypad->state(
  401. joypad_info, binds[port], port);
  402. #endif
  403. }
  404. else
  405. {
  406. /* Do a bitwise OR to combine both input
  407. * states together */
  408. if (binds[port][id].valid)
  409. {
  410. if (button_is_pressed(
  411. joypad,
  412. joypad_info, binds[port], port, id))
  413. return 1;
  414. #ifdef HAVE_MFI
  415. else if (sec_joypad &&
  416. button_is_pressed(
  417. sec_joypad,
  418. joypad_info, binds[port], port, id))
  419. return 1;
  420. #endif
  421. }
  422. }
  423. }
  424. if (current_input->input_state)
  425. ret |= current_input->input_state(
  426. data,
  427. joypad,
  428. sec_joypad,
  429. joypad_info,
  430. binds,
  431. keyboard_mapping_blocked,
  432. port,
  433. device,
  434. idx,
  435. id);
  436. return ret;
  437. }
  438. /* DRIVERS */
  439. /**
  440. * driver_find_index:
  441. * @label : string of driver type to be found.
  442. * @drv : identifier of driver to be found.
  443. *
  444. * Find index of the driver, based on @label.
  445. *
  446. * Returns: -1 if no driver based on @label and @drv found, otherwise
  447. * index number of the driver found in the array.
  448. **/
  449. static int driver_find_index(const char *label, const char *drv)
  450. {
  451. unsigned i;
  452. char str[256];
  453. str[0] = '\0';
  454. for (i = 0;
  455. find_driver_nonempty(label, i, str, sizeof(str)) != NULL; i++)
  456. {
  457. if (string_is_empty(str))
  458. break;
  459. if (string_is_equal_noncase(drv, str))
  460. return i;
  461. }
  462. return -1;
  463. }
  464. /**
  465. * driver_find_last:
  466. * @label : string of driver type to be found.
  467. * @s : identifier of driver to be found.
  468. * @len : size of @s.
  469. *
  470. * Find last driver in driver array.
  471. **/
  472. static void driver_find_last(const char *label, char *s, size_t len)
  473. {
  474. unsigned i;
  475. for (i = 0;
  476. find_driver_nonempty(label, i, s, len) != NULL; i++) { }
  477. if (i)
  478. i = i - 1;
  479. else
  480. i = 0;
  481. find_driver_nonempty(label, i, s, len);
  482. }
  483. /**
  484. * driver_find_prev:
  485. * @label : string of driver type to be found.
  486. * @s : identifier of driver to be found.
  487. * @len : size of @s.
  488. *
  489. * Find previous driver in driver array.
  490. **/
  491. static bool driver_find_prev(const char *label, char *s, size_t len)
  492. {
  493. int i = driver_find_index(label, s);
  494. if (i > 0)
  495. {
  496. find_driver_nonempty(label, i - 1, s, len);
  497. return true;
  498. }
  499. RARCH_WARN(
  500. "Couldn't find any previous driver (current one: \"%s\").\n", s);
  501. return false;
  502. }
  503. /**
  504. * driver_find_next:
  505. * @label : string of driver type to be found.
  506. * @s : identifier of driver to be found.
  507. * @len : size of @s.
  508. *
  509. * Find next driver in driver array.
  510. **/
  511. static bool driver_find_next(const char *label, char *s, size_t len)
  512. {
  513. int i = driver_find_index(label, s);
  514. if (i >= 0 && string_is_not_equal(s, "null"))
  515. {
  516. find_driver_nonempty(label, i + 1, s, len);
  517. return true;
  518. }
  519. RARCH_WARN("%s (current one: \"%s\").\n",
  520. msg_hash_to_str(MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER),
  521. s);
  522. return false;
  523. }
  524. #ifdef HAVE_MENU
  525. static int menu_dialog_iterate(
  526. menu_dialog_t *p_dialog,
  527. char *s, size_t len,
  528. retro_time_t current_time)
  529. {
  530. switch (p_dialog->current_type)
  531. {
  532. case MENU_DIALOG_WELCOME:
  533. {
  534. static rarch_timer_t timer;
  535. if (!timer.timer_begin)
  536. {
  537. RARCH_TIMER_BEGIN_NEW_TIME_USEC(timer,
  538. cpu_features_get_time_usec(),
  539. 3 * 1000000);
  540. timer.timer_begin = true;
  541. timer.timer_end = false;
  542. }
  543. RARCH_TIMER_TICK(timer, current_time);
  544. msg_hash_get_help_enum(
  545. MENU_ENUM_LABEL_WELCOME_TO_RETROARCH,
  546. s, len);
  547. if (!timer.timer_end && RARCH_TIMER_HAS_EXPIRED(timer))
  548. {
  549. RARCH_TIMER_END(timer);
  550. p_dialog->current_type = MENU_DIALOG_NONE;
  551. return 1;
  552. }
  553. }
  554. break;
  555. case MENU_DIALOG_HELP_CONTROLS:
  556. {
  557. unsigned i;
  558. char s2[PATH_MAX_LENGTH];
  559. const unsigned binds[] = {
  560. RETRO_DEVICE_ID_JOYPAD_UP,
  561. RETRO_DEVICE_ID_JOYPAD_DOWN,
  562. RETRO_DEVICE_ID_JOYPAD_A,
  563. RETRO_DEVICE_ID_JOYPAD_B,
  564. RETRO_DEVICE_ID_JOYPAD_SELECT,
  565. RETRO_DEVICE_ID_JOYPAD_START,
  566. RARCH_MENU_TOGGLE,
  567. RARCH_QUIT_KEY,
  568. RETRO_DEVICE_ID_JOYPAD_X,
  569. RETRO_DEVICE_ID_JOYPAD_Y,
  570. };
  571. char desc[ARRAY_SIZE(binds)][64];
  572. for (i = 0; i < ARRAY_SIZE(binds); i++)
  573. desc[i][0] = '\0';
  574. for (i = 0; i < ARRAY_SIZE(binds); i++)
  575. {
  576. const struct retro_keybind *keybind = &input_config_binds[0][binds[i]];
  577. const struct retro_keybind *auto_bind =
  578. (const struct retro_keybind*)
  579. input_config_get_bind_auto(0, binds[i]);
  580. input_config_get_bind_string(desc[i],
  581. keybind, auto_bind, sizeof(desc[i]));
  582. }
  583. s2[0] = '\0';
  584. msg_hash_get_help_enum(
  585. MENU_ENUM_LABEL_VALUE_MENU_ENUM_CONTROLS_PROLOG,
  586. s2, sizeof(s2));
  587. snprintf(s, len,
  588. "%s"
  589. "[%s]: "
  590. "%-20s\n"
  591. "[%s]: "
  592. "%-20s\n"
  593. "[%s]: "
  594. "%-20s\n"
  595. "[%s]: "
  596. "%-20s\n"
  597. "[%s]: "
  598. "%-20s\n"
  599. "[%s]: "
  600. "%-20s\n"
  601. "[%s]: "
  602. "%-20s\n"
  603. "[%s]: "
  604. "%-20s\n"
  605. "[%s]: "
  606. "%-20s\n",
  607. s2,
  608. msg_hash_to_str(
  609. MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP),
  610. desc[0],
  611. msg_hash_to_str(
  612. MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN),
  613. desc[1],
  614. msg_hash_to_str(
  615. MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM),
  616. desc[2],
  617. msg_hash_to_str(
  618. MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK),
  619. desc[3],
  620. msg_hash_to_str(
  621. MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO),
  622. desc[4],
  623. msg_hash_to_str(
  624. MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START),
  625. desc[5],
  626. msg_hash_to_str(
  627. MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU),
  628. desc[6],
  629. msg_hash_to_str(
  630. MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT),
  631. desc[7],
  632. msg_hash_to_str(
  633. MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD),
  634. desc[8]
  635. );
  636. }
  637. break;
  638. #ifdef HAVE_CHEEVOS
  639. case MENU_DIALOG_HELP_CHEEVOS_DESCRIPTION:
  640. {
  641. rcheevos_ctx_desc_t desc_info;
  642. desc_info.idx = p_dialog->current_id;
  643. desc_info.s = s;
  644. desc_info.len = len;
  645. rcheevos_get_description((rcheevos_ctx_desc_t*) &desc_info);
  646. }
  647. break;
  648. #endif
  649. case MENU_DIALOG_HELP_WHAT_IS_A_CORE:
  650. msg_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_WHAT_IS_A_CORE_DESC,
  651. s, len);
  652. break;
  653. case MENU_DIALOG_HELP_LOADING_CONTENT:
  654. msg_hash_get_help_enum(MENU_ENUM_LABEL_LOAD_CONTENT_LIST,
  655. s, len);
  656. break;
  657. case MENU_DIALOG_HELP_CHANGE_VIRTUAL_GAMEPAD:
  658. msg_hash_get_help_enum(
  659. MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD_DESC,
  660. s, len);
  661. break;
  662. case MENU_DIALOG_HELP_AUDIO_VIDEO_TROUBLESHOOTING:
  663. msg_hash_get_help_enum(
  664. MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING_DESC,
  665. s, len);
  666. break;
  667. case MENU_DIALOG_HELP_SEND_DEBUG_INFO:
  668. msg_hash_get_help_enum(
  669. MENU_ENUM_LABEL_VALUE_HELP_SEND_DEBUG_INFO_DESC,
  670. s, len);
  671. break;
  672. case MENU_DIALOG_HELP_SCANNING_CONTENT:
  673. msg_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT_DESC,
  674. s, len);
  675. break;
  676. case MENU_DIALOG_HELP_EXTRACT:
  677. {
  678. struct rarch_state *p_rarch = &rarch_st;
  679. settings_t *settings = p_rarch->configuration_settings;
  680. bool bundle_finished = settings->bools.bundle_finished;
  681. msg_hash_get_help_enum(
  682. MENU_ENUM_LABEL_VALUE_EXTRACTING_PLEASE_WAIT,
  683. s, len);
  684. if (bundle_finished)
  685. {
  686. configuration_set_bool(settings,
  687. settings->bools.bundle_finished, false);
  688. p_dialog->current_type = MENU_DIALOG_NONE;
  689. return 1;
  690. }
  691. }
  692. break;
  693. case MENU_DIALOG_QUIT_CONFIRM:
  694. case MENU_DIALOG_INFORMATION:
  695. case MENU_DIALOG_QUESTION:
  696. case MENU_DIALOG_WARNING:
  697. case MENU_DIALOG_ERROR:
  698. msg_hash_get_help_enum(MSG_UNKNOWN,
  699. s, len);
  700. break;
  701. case MENU_DIALOG_NONE:
  702. default:
  703. break;
  704. }
  705. return 0;
  706. }
  707. void menu_dialog_unset_pending_push(void)
  708. {
  709. struct rarch_state *p_rarch = &rarch_st;
  710. menu_dialog_t *p_dialog = &p_rarch->dialog_st;
  711. p_dialog->pending_push = false;
  712. }
  713. void menu_dialog_push_pending(enum menu_dialog_type type)
  714. {
  715. struct rarch_state *p_rarch = &rarch_st;
  716. menu_dialog_t *p_dialog = &p_rarch->dialog_st;
  717. p_dialog->current_type = type;
  718. p_dialog->pending_push = true;
  719. }
  720. void menu_dialog_set_current_id(unsigned id)
  721. {
  722. struct rarch_state *p_rarch = &rarch_st;
  723. menu_dialog_t *p_dialog = &p_rarch->dialog_st;
  724. p_dialog->current_id = id;
  725. }
  726. void input_keyboard_mapping_bits(unsigned mode, unsigned key)
  727. {
  728. struct rarch_state *p_rarch = &rarch_st;
  729. switch (mode)
  730. {
  731. case 0:
  732. BIT512_CLEAR_PTR(&p_rarch->keyboard_mapping_bits, key);
  733. break;
  734. case 1:
  735. BIT512_SET_PTR(&p_rarch->keyboard_mapping_bits, key);
  736. break;
  737. default:
  738. break;
  739. }
  740. }
  741. static bool menu_input_key_bind_custom_bind_keyboard_cb(
  742. void *data, unsigned code)
  743. {
  744. uint64_t current_usec;
  745. struct rarch_state *p_rarch = &rarch_st;
  746. settings_t *settings = p_rarch->configuration_settings;
  747. struct menu_bind_state *binds = &p_rarch->menu_input_binds;
  748. uint64_t input_bind_hold_us = settings->uints.input_bind_hold * 1000000;
  749. uint64_t input_bind_timeout_us = settings->uints.input_bind_timeout * 1000000;
  750. /* Clear old mapping bit */
  751. input_keyboard_mapping_bits(0, binds->buffer.key);
  752. /* store key in bind */
  753. binds->buffer.key = (enum retro_key)code;
  754. /* Store new mapping bit */
  755. input_keyboard_mapping_bits(1, binds->buffer.key);
  756. /* write out the bind */
  757. *(binds->output) = binds->buffer;
  758. /* next bind */
  759. binds->begin++;
  760. binds->output++;
  761. binds->buffer =* (binds->output);
  762. current_usec = cpu_features_get_time_usec();
  763. RARCH_TIMER_BEGIN_NEW_TIME_USEC(
  764. binds->timer_hold,
  765. current_usec,
  766. input_bind_hold_us);
  767. RARCH_TIMER_BEGIN_NEW_TIME_USEC(
  768. binds->timer_timeout,
  769. current_usec, input_bind_timeout_us);
  770. return (binds->begin <= binds->last);
  771. }
  772. static int menu_input_key_bind_set_mode_common(
  773. struct menu_state *menu_st,
  774. struct menu_bind_state *binds,
  775. enum menu_input_binds_ctl_state state,
  776. rarch_setting_t *setting)
  777. {
  778. menu_displaylist_info_t info;
  779. unsigned bind_type = 0;
  780. struct retro_keybind *keybind = NULL;
  781. unsigned index_offset = setting->index_offset;
  782. menu_list_t *menu_list = menu_st->entries.list;
  783. file_list_t *menu_stack = menu_list ? MENU_LIST_GET(menu_list, (unsigned)0) : NULL;
  784. size_t selection = menu_st->selection_ptr;
  785. menu_displaylist_info_init(&info);
  786. switch (state)
  787. {
  788. case MENU_INPUT_BINDS_CTL_BIND_SINGLE:
  789. keybind = (struct retro_keybind*)setting->value.target.keybind;
  790. if (!keybind)
  791. return -1;
  792. bind_type = setting_get_bind_type(setting);
  793. binds->begin = bind_type;
  794. binds->last = bind_type;
  795. binds->output = keybind;
  796. binds->buffer = *(binds->output);
  797. binds->user = index_offset;
  798. info.list = menu_stack;
  799. info.type = MENU_SETTINGS_CUSTOM_BIND_KEYBOARD;
  800. info.directory_ptr = selection;
  801. info.enum_idx = MENU_ENUM_LABEL_CUSTOM_BIND;
  802. info.label = strdup(
  803. msg_hash_to_str(MENU_ENUM_LABEL_CUSTOM_BIND));
  804. break;
  805. case MENU_INPUT_BINDS_CTL_BIND_ALL:
  806. binds->output = &input_config_binds[index_offset][0];
  807. binds->buffer = *(binds->output);
  808. binds->begin = MENU_SETTINGS_BIND_BEGIN;
  809. binds->last = MENU_SETTINGS_BIND_LAST;
  810. info.list = menu_stack;
  811. info.type = MENU_SETTINGS_CUSTOM_BIND_KEYBOARD;
  812. info.directory_ptr = selection;
  813. info.enum_idx = MENU_ENUM_LABEL_CUSTOM_BIND_ALL;
  814. info.label = strdup(
  815. msg_hash_to_str(MENU_ENUM_LABEL_CUSTOM_BIND_ALL));
  816. break;
  817. default:
  818. case MENU_INPUT_BINDS_CTL_BIND_NONE:
  819. return 0;
  820. }
  821. if (menu_displaylist_ctl(DISPLAYLIST_INFO, &info))
  822. menu_displaylist_process(&info);
  823. menu_displaylist_info_free(&info);
  824. return 0;
  825. }
  826. static void menu_input_key_bind_poll_bind_get_rested_axes(
  827. const input_device_driver_t *joypad,
  828. const input_device_driver_t *sec_joypad,
  829. struct menu_bind_state *state)
  830. {
  831. unsigned a;
  832. unsigned port = state->port;
  833. if (joypad)
  834. {
  835. /* poll only the relevant port */
  836. for (a = 0; a < MENU_MAX_AXES; a++)
  837. {
  838. if (AXIS_POS(a) != AXIS_NONE)
  839. state->axis_state[port].rested_axes[a] =
  840. joypad->axis(port, AXIS_POS(a));
  841. if (AXIS_NEG(a) != AXIS_NONE)
  842. state->axis_state[port].rested_axes[a] +=
  843. joypad->axis(port, AXIS_NEG(a));
  844. }
  845. }
  846. if (sec_joypad)
  847. {
  848. /* poll only the relevant port */
  849. for (a = 0; a < MENU_MAX_AXES; a++)
  850. {
  851. if (AXIS_POS(a) != AXIS_NONE)
  852. state->axis_state[port].rested_axes[a] = sec_joypad->axis(port, AXIS_POS(a));
  853. if (AXIS_NEG(a) != AXIS_NONE)
  854. state->axis_state[port].rested_axes[a] += sec_joypad->axis(port, AXIS_NEG(a));
  855. }
  856. }
  857. }
  858. static void menu_input_key_bind_poll_bind_state_internal(
  859. const input_device_driver_t *joypad,
  860. struct menu_bind_state *state,
  861. unsigned port,
  862. bool timed_out)
  863. {
  864. unsigned i;
  865. /* poll only the relevant port */
  866. for (i = 0; i < MENU_MAX_BUTTONS; i++)
  867. state->state[port].buttons[i] = joypad->button(port, i);
  868. for (i = 0; i < MENU_MAX_AXES; i++)
  869. {
  870. if (AXIS_POS(i) != AXIS_NONE)
  871. state->state[port].axes[i] = joypad->axis(port, AXIS_POS(i));
  872. if (AXIS_NEG(i) != AXIS_NONE)
  873. state->state[port].axes[i] += joypad->axis(port, AXIS_NEG(i));
  874. }
  875. for (i = 0; i < MENU_MAX_HATS; i++)
  876. {
  877. if (joypad->button(port, HAT_MAP(i, HAT_UP_MASK)))
  878. state->state[port].hats[i] |= HAT_UP_MASK;
  879. if (joypad->button(port, HAT_MAP(i, HAT_DOWN_MASK)))
  880. state->state[port].hats[i] |= HAT_DOWN_MASK;
  881. if (joypad->button(port, HAT_MAP(i, HAT_LEFT_MASK)))
  882. state->state[port].hats[i] |= HAT_LEFT_MASK;
  883. if (joypad->button(port, HAT_MAP(i, HAT_RIGHT_MASK)))
  884. state->state[port].hats[i] |= HAT_RIGHT_MASK;
  885. }
  886. }
  887. static void menu_input_key_bind_poll_bind_state(
  888. struct rarch_state *p_rarch,
  889. struct menu_bind_state *state,
  890. bool timed_out)
  891. {
  892. unsigned b;
  893. rarch_joypad_info_t joypad_info;
  894. input_driver_t *current_input = p_rarch->current_input;
  895. void *input_data = p_rarch->current_input_data;
  896. unsigned port = state->port;
  897. const input_device_driver_t *joypad = p_rarch->joypad;
  898. #ifdef HAVE_MFI
  899. const input_device_driver_t *sec_joypad = p_rarch->sec_joypad;
  900. #else
  901. const input_device_driver_t *sec_joypad = NULL;
  902. #endif
  903. memset(state->state, 0, sizeof(state->state));
  904. /* poll mouse (on the relevant port) */
  905. for (b = 0; b < MENU_MAX_MBUTTONS; b++)
  906. state->state[port].mouse_buttons[b] =
  907. input_mouse_button_raw(p_rarch,
  908. p_rarch->configuration_settings, port, b);
  909. joypad_info.joy_idx = 0;
  910. joypad_info.auto_binds = NULL;
  911. joypad_info.axis_threshold = 0.0f;
  912. state->skip = timed_out;
  913. if (current_input->input_state)
  914. state->skip |=
  915. current_input->input_state(
  916. input_data,
  917. joypad,
  918. sec_joypad,
  919. &joypad_info,
  920. NULL,
  921. p_rarch->keyboard_mapping_blocked,
  922. 0,
  923. RETRO_DEVICE_KEYBOARD,
  924. 0,
  925. RETROK_RETURN);
  926. if (joypad)
  927. {
  928. if (joypad->poll)
  929. joypad->poll();
  930. menu_input_key_bind_poll_bind_state_internal(
  931. joypad, state, port, timed_out);
  932. }
  933. if (sec_joypad)
  934. {
  935. if (sec_joypad->poll)
  936. sec_joypad->poll();
  937. menu_input_key_bind_poll_bind_state_internal(
  938. sec_joypad, state, port, timed_out);
  939. }
  940. }
  941. static bool menu_input_key_bind_poll_find_trigger_pad(
  942. struct menu_bind_state *state,
  943. struct menu_bind_state *new_state,
  944. struct retro_keybind * output,
  945. unsigned p)
  946. {
  947. unsigned a, b, h;
  948. const struct menu_bind_state_port *n = (const struct menu_bind_state_port*)
  949. &new_state->state[p];
  950. const struct menu_bind_state_port *o = (const struct menu_bind_state_port*)
  951. &state->state[p];
  952. for (b = 0; b < MENU_MAX_MBUTTONS; b++)
  953. {
  954. bool iterate = n->mouse_buttons[b] && !o->mouse_buttons[b];
  955. if (!iterate)
  956. continue;
  957. switch (b)
  958. {
  959. case RETRO_DEVICE_ID_MOUSE_LEFT:
  960. case RETRO_DEVICE_ID_MOUSE_RIGHT:
  961. case RETRO_DEVICE_ID_MOUSE_MIDDLE:
  962. case RETRO_DEVICE_ID_MOUSE_BUTTON_4:
  963. case RETRO_DEVICE_ID_MOUSE_BUTTON_5:
  964. case RETRO_DEVICE_ID_MOUSE_WHEELUP:
  965. case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
  966. case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
  967. case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
  968. output->mbutton = b;
  969. return true;
  970. }
  971. }
  972. for (b = 0; b < MENU_MAX_BUTTONS; b++)
  973. {
  974. bool iterate = n->buttons[b] && !o->buttons[b];
  975. if (!iterate)
  976. continue;
  977. output->joykey = b;
  978. output->joyaxis = AXIS_NONE;
  979. return true;
  980. }
  981. /* Axes are a bit tricky ... */
  982. for (a = 0; a < MENU_MAX_AXES; a++)
  983. {
  984. int locked_distance = abs(n->axes[a] -
  985. new_state->axis_state[p].locked_axes[a]);
  986. int rested_distance = abs(n->axes[a] -
  987. new_state->axis_state[p].rested_axes[a]);
  988. if (abs(n->axes[a]) >= 20000 &&
  989. locked_distance >= 20000 &&
  990. rested_distance >= 20000)
  991. {
  992. /* Take care of case where axis rests on +/- 0x7fff
  993. * (e.g. 360 controller on Linux) */
  994. output->joyaxis = n->axes[a] > 0
  995. ? AXIS_POS(a) : AXIS_NEG(a);
  996. output->joykey = NO_BTN;
  997. /* Lock the current axis */
  998. new_state->axis_state[p].locked_axes[a] =
  999. n->axes[a] > 0 ?
  1000. 0x7fff : -0x7fff;
  1001. return true;
  1002. }
  1003. if (locked_distance >= 20000) /* Unlock the axis. */
  1004. new_state->axis_state[p].locked_axes[a] = 0;
  1005. }
  1006. for (h = 0; h < MENU_MAX_HATS; h++)
  1007. {
  1008. uint16_t trigged = n->hats[h] & (~o->hats[h]);
  1009. uint16_t sane_trigger = 0;
  1010. if (trigged & HAT_UP_MASK)
  1011. sane_trigger = HAT_UP_MASK;
  1012. else if (trigged & HAT_DOWN_MASK)
  1013. sane_trigger = HAT_DOWN_MASK;
  1014. else if (trigged & HAT_LEFT_MASK)
  1015. sane_trigger = HAT_LEFT_MASK;
  1016. else if (trigged & HAT_RIGHT_MASK)
  1017. sane_trigger = HAT_RIGHT_MASK;
  1018. if (sane_trigger)
  1019. {
  1020. output->joykey = HAT_MAP(h, sane_trigger);
  1021. output->joyaxis = AXIS_NONE;
  1022. return true;
  1023. }
  1024. }
  1025. return false;
  1026. }
  1027. #ifdef ANDROID
  1028. static bool menu_input_key_bind_poll_find_hold_pad(
  1029. struct menu_bind_state *new_state,
  1030. struct retro_keybind * output,
  1031. unsigned p)
  1032. {
  1033. unsigned a, b, h;
  1034. const struct menu_bind_state_port *n =
  1035. (const struct menu_bind_state_port*)
  1036. &new_state->state[p];
  1037. for (b = 0; b < MENU_MAX_MBUTTONS; b++)
  1038. {
  1039. bool iterate = n->mouse_buttons[b];
  1040. if (!iterate)
  1041. continue;
  1042. switch (b)
  1043. {
  1044. case RETRO_DEVICE_ID_MOUSE_LEFT:
  1045. case RETRO_DEVICE_ID_MOUSE_RIGHT:
  1046. case RETRO_DEVICE_ID_MOUSE_MIDDLE:
  1047. case RETRO_DEVICE_ID_MOUSE_BUTTON_4:
  1048. case RETRO_DEVICE_ID_MOUSE_BUTTON_5:
  1049. case RETRO_DEVICE_ID_MOUSE_WHEELUP:
  1050. case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
  1051. case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
  1052. case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
  1053. output->mbutton = b;
  1054. return true;
  1055. }
  1056. }
  1057. for (b = 0; b < MENU_MAX_BUTTONS; b++)
  1058. {
  1059. bool iterate = n->buttons[b];
  1060. if (!iterate)
  1061. continue;
  1062. output->joykey = b;
  1063. output->joyaxis = AXIS_NONE;
  1064. return true;
  1065. }
  1066. /* Axes are a bit tricky ... */
  1067. for (a = 0; a < MENU_MAX_AXES; a++)
  1068. {
  1069. if (abs(n->axes[a]) >= 20000)
  1070. {
  1071. /* Take care of case where axis rests on +/- 0x7fff
  1072. * (e.g. 360 controller on Linux) */
  1073. output->joyaxis = n->axes[a] > 0
  1074. ? AXIS_POS(a) : AXIS_NEG(a);
  1075. output->joykey = NO_BTN;
  1076. return true;
  1077. }
  1078. }
  1079. for (h = 0; h < MENU_MAX_HATS; h++)
  1080. {
  1081. uint16_t trigged = n->hats[h];
  1082. uint16_t sane_trigger = 0;
  1083. if (trigged & HAT_UP_MASK)
  1084. sane_trigger = HAT_UP_MASK;
  1085. else if (trigged & HAT_DOWN_MASK)
  1086. sane_trigger = HAT_DOWN_MASK;
  1087. else if (trigged & HAT_LEFT_MASK)
  1088. sane_trigger = HAT_LEFT_MASK;
  1089. else if (trigged & HAT_RIGHT_MASK)
  1090. sane_trigger = HAT_RIGHT_MASK;
  1091. if (sane_trigger)
  1092. {
  1093. output->joykey = HAT_MAP(h, sane_trigger);
  1094. output->joyaxis = AXIS_NONE;
  1095. return true;
  1096. }
  1097. }
  1098. return false;
  1099. }
  1100. #endif
  1101. static bool menu_input_key_bind_poll_find_trigger(
  1102. unsigned max_users,
  1103. struct menu_bind_state *state,
  1104. struct menu_bind_state *new_state,
  1105. struct retro_keybind * output)
  1106. {
  1107. if (state && new_state)
  1108. {
  1109. unsigned i;
  1110. for (i = 0; i < max_users; i++)
  1111. {
  1112. if (menu_input_key_bind_poll_find_trigger_pad(
  1113. state, new_state, output, i))
  1114. return true;
  1115. }
  1116. }
  1117. return false;
  1118. }
  1119. #ifdef ANDROID
  1120. static bool menu_input_key_bind_poll_find_hold(
  1121. unsigned max_users,
  1122. struct menu_bind_state *new_state,
  1123. struct retro_keybind * output)
  1124. {
  1125. if (new_state)
  1126. {
  1127. unsigned i;
  1128. for (i = 0; i < max_users; i++)
  1129. {
  1130. if (menu_input_key_bind_poll_find_hold_pad(new_state, output, i))
  1131. return true;
  1132. }
  1133. }
  1134. return false;
  1135. }
  1136. #endif
  1137. bool menu_input_key_bind_set_mode(
  1138. enum menu_input_binds_ctl_state state, void *data)
  1139. {
  1140. uint64_t current_usec;
  1141. unsigned index_offset;
  1142. rarch_setting_t *setting = (rarch_setting_t*)data;
  1143. struct rarch_state *p_rarch = &rarch_st;
  1144. menu_handle_t *menu = p_rarch->menu_driver_data;
  1145. menu_input_t *menu_input = &p_rarch->menu_input_state;
  1146. settings_t *settings = p_rarch->configuration_settings;
  1147. struct menu_bind_state *binds = &p_rarch->menu_input_binds;
  1148. uint64_t input_bind_hold_us = settings->uints.input_bind_hold
  1149. * 1000000;
  1150. uint64_t input_bind_timeout_us = settings->uints.input_bind_timeout
  1151. * 1000000;
  1152. if (!setting || !menu)
  1153. return false;
  1154. if (menu_input_key_bind_set_mode_common(&p_rarch->menu_driver_state,
  1155. binds, state, setting) == -1)
  1156. return false;
  1157. index_offset = setting->index_offset;
  1158. binds->port = settings->uints.input_joypad_map[index_offset];
  1159. menu_input_key_bind_poll_bind_get_rested_axes(
  1160. p_rarch->joypad,
  1161. #ifdef HAVE_MFI
  1162. p_rarch->sec_joypad,
  1163. #else
  1164. NULL,
  1165. #endif
  1166. binds);
  1167. menu_input_key_bind_poll_bind_state(p_rarch,
  1168. binds, false);
  1169. current_usec = cpu_features_get_time_usec();
  1170. RARCH_TIMER_BEGIN_NEW_TIME_USEC(
  1171. binds->timer_hold,
  1172. current_usec,
  1173. input_bind_hold_us);
  1174. RARCH_TIMER_BEGIN_NEW_TIME_USEC(
  1175. binds->timer_timeout,
  1176. current_usec,
  1177. input_bind_timeout_us);
  1178. p_rarch->keyboard_press_cb =
  1179. menu_input_key_bind_custom_bind_keyboard_cb;
  1180. p_rarch->keyboard_press_data = menu;
  1181. /* While waiting for input, we have to block all hotkeys. */
  1182. p_rarch->keyboard_mapping_blocked = true;
  1183. /* Upon triggering an input bind operation,
  1184. * pointer input must be inhibited - otherwise
  1185. * attempting to bind mouse buttons will cause
  1186. * spurious menu actions */
  1187. menu_input->select_inhibit = true;
  1188. menu_input->cancel_inhibit = true;
  1189. return true;
  1190. }
  1191. bool menu_input_key_bind_set_min_max(menu_input_ctx_bind_limits_t *lim)
  1192. {
  1193. struct rarch_state *p_rarch = &rarch_st;
  1194. struct menu_bind_state *binds = &p_rarch->menu_input_binds;
  1195. if (!lim)
  1196. return false;
  1197. binds->begin = lim->min;
  1198. binds->last = lim->max;
  1199. return true;
  1200. }
  1201. static bool menu_input_key_bind_iterate(
  1202. struct rarch_state *p_rarch,
  1203. menu_input_ctx_bind_t *bind,
  1204. retro_time_t current_time)
  1205. {
  1206. bool timed_out = false;
  1207. settings_t *settings = p_rarch->configuration_settings;
  1208. struct menu_bind_state *_binds = &p_rarch->menu_input_binds;
  1209. menu_input_t *menu_input = &p_rarch->menu_input_state;
  1210. uint64_t input_bind_hold_us = settings->uints.input_bind_hold * 1000000;
  1211. uint64_t input_bind_timeout_us = settings->uints.input_bind_timeout * 1000000;
  1212. snprintf(bind->s, bind->len,
  1213. "[%s]\nPress keyboard, mouse or joypad\n(Timeout %d %s)",
  1214. input_config_bind_map_get_desc(
  1215. _binds->begin - MENU_SETTINGS_BIND_BEGIN),
  1216. RARCH_TIMER_GET_TIMEOUT(_binds->timer_timeout),
  1217. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SECONDS));
  1218. /* Tick main timers */
  1219. RARCH_TIMER_TICK(_binds->timer_timeout, current_time);
  1220. RARCH_TIMER_TICK(_binds->timer_hold, current_time);
  1221. if (RARCH_TIMER_HAS_EXPIRED(_binds->timer_timeout))
  1222. {
  1223. uint64_t current_usec = cpu_features_get_time_usec();
  1224. p_rarch->keyboard_mapping_blocked = false;
  1225. /*skip to next bind*/
  1226. _binds->begin++;
  1227. _binds->output++;
  1228. RARCH_TIMER_BEGIN_NEW_TIME_USEC(_binds->timer_hold,
  1229. current_usec,
  1230. input_bind_hold_us);
  1231. RARCH_TIMER_BEGIN_NEW_TIME_USEC(_binds->timer_timeout,
  1232. current_usec,
  1233. input_bind_timeout_us);
  1234. timed_out = true;
  1235. }
  1236. /* binds.begin is updated in keyboard_press callback. */
  1237. if (_binds->begin > _binds->last)
  1238. {
  1239. /* Avoid new binds triggering things right away. */
  1240. /* Inhibits input for 2 frames
  1241. * > Required, since input is ignored for 1 frame
  1242. * after certain events - e.g. closing the OSK */
  1243. p_rarch->input_driver_flushing_input = 2;
  1244. /* We won't be getting any key events, so just cancel early. */
  1245. if (timed_out)
  1246. {
  1247. p_rarch->keyboard_press_cb = NULL;
  1248. p_rarch->keyboard_press_data = NULL;
  1249. p_rarch->keyboard_mapping_blocked = false;
  1250. }
  1251. return true;
  1252. }
  1253. {
  1254. bool complete = false;
  1255. struct menu_bind_state new_binds = *_binds;
  1256. p_rarch->keyboard_mapping_blocked = false;
  1257. menu_input_key_bind_poll_bind_state(p_rarch,
  1258. &new_binds, timed_out);
  1259. #ifdef ANDROID
  1260. /* Keep resetting bind during the hold period,
  1261. * or we'll potentially bind joystick and mouse, etc.*/
  1262. new_binds.buffer = *(new_binds.output);
  1263. if (menu_input_key_bind_poll_find_hold(
  1264. p_rarch->input_driver_max_users,
  1265. &new_binds, &new_binds.buffer))
  1266. {
  1267. uint64_t current_usec = cpu_features_get_time_usec();
  1268. /* Inhibit timeout*/
  1269. RARCH_TIMER_BEGIN_NEW_TIME_USEC(
  1270. new_binds.timer_timeout,
  1271. current_usec,
  1272. input_bind_timeout_us);
  1273. /* Run hold timer*/
  1274. RARCH_TIMER_TICK(new_binds.timer_hold, current_time);
  1275. snprintf(bind->s, bind->len,
  1276. "[%s]\npress keyboard, mouse or joypad\nand hold ...",
  1277. input_config_bind_map_get_desc(
  1278. _binds->begin - MENU_SETTINGS_BIND_BEGIN));
  1279. /* Hold complete? */
  1280. if (RARCH_TIMER_HAS_EXPIRED(new_binds.timer_hold))
  1281. complete = true;
  1282. }
  1283. else
  1284. {
  1285. uint64_t current_usec = cpu_features_get_time_usec();
  1286. /* Reset hold countdown*/
  1287. RARCH_TIMER_BEGIN_NEW_TIME_USEC(new_binds.timer_hold,
  1288. current_usec,
  1289. input_bind_hold_us);
  1290. }
  1291. #else
  1292. if ((new_binds.skip && !_binds->skip) ||
  1293. menu_input_key_bind_poll_find_trigger(
  1294. p_rarch->input_driver_max_users,
  1295. _binds, &new_binds, &(new_binds.buffer)))
  1296. complete = true;
  1297. #endif
  1298. if (complete)
  1299. {
  1300. uint64_t current_usec = cpu_features_get_time_usec();
  1301. /* Update bind */
  1302. *(new_binds.output) = new_binds.buffer;
  1303. p_rarch->keyboard_mapping_blocked = false;
  1304. /* Avoid new binds triggering things right away. */
  1305. /* Inhibits input for 2 frames
  1306. * > Required, since input is ignored for 1 frame
  1307. * after certain events - e.g. closing the OSK */
  1308. p_rarch->input_driver_flushing_input = 2;
  1309. new_binds.begin++;
  1310. if (new_binds.begin > new_binds.last)
  1311. {
  1312. p_rarch->keyboard_press_cb = NULL;
  1313. p_rarch->keyboard_press_data = NULL;
  1314. p_rarch->keyboard_mapping_blocked = false;
  1315. return true;
  1316. }
  1317. /*next bind*/
  1318. new_binds.output++;
  1319. new_binds.buffer = *(new_binds.output);
  1320. RARCH_TIMER_BEGIN_NEW_TIME_USEC(new_binds.timer_hold,
  1321. current_usec, input_bind_hold_us);
  1322. RARCH_TIMER_BEGIN_NEW_TIME_USEC(new_binds.timer_timeout,
  1323. current_usec, input_bind_timeout_us);
  1324. }
  1325. *(_binds) = new_binds;
  1326. }
  1327. /* Pointer input must be inhibited on each
  1328. * frame that the bind operation is active -
  1329. * otherwise attempting to bind mouse buttons
  1330. * will cause spurious menu actions */
  1331. menu_input->select_inhibit = true;
  1332. menu_input->cancel_inhibit = true;
  1333. return false;
  1334. }
  1335. /* This sets up all the callback functions for a menu entry.
  1336. *
  1337. * OK : When we press the 'OK' button on an entry.
  1338. * Cancel : When we press the 'Cancel' button on an entry.
  1339. * Scan : When we press the 'Scan' button on an entry.
  1340. * Start : When we press the 'Start' button on an entry.
  1341. * Select : When we press the 'Select' button on an entry.
  1342. * Info : When we press the 'Info' button on an entry.
  1343. * Content Switch : ??? (TODO/FIXME - Kivutar should document this)
  1344. * Up : when we press 'Up' on the D-pad while this entry is selected.
  1345. * Down : when we press 'Down' on the D-pad while this entry is selected.
  1346. * Left : when we press 'Left' on the D-pad while this entry is selected.
  1347. * Right : when we press 'Right' on the D-pad while this entry is selected.
  1348. * Deferred push : When pressing an entry results in spawning a new list, it waits until the next
  1349. * frame to push this onto the stack. This function callback will then be invoked.
  1350. * Refresh : What happens when the screen has to be refreshed. Does an entry have internal state
  1351. * that needs to be rebuild?
  1352. * Get value: Each entry has associated 'text', which we call the value. This function callback
  1353. * lets us render that text.
  1354. * Get title: Each entry can have a custom 'title'.
  1355. * Label: Each entry has a label name. This function callback lets us render that label text.
  1356. * Sublabel: each entry has a sublabel, which consists of one or more lines of additional information.
  1357. * This function callback lets us render that text.
  1358. */
  1359. static void menu_cbs_init(
  1360. struct menu_state *menu_st,
  1361. const menu_ctx_driver_t *menu_driver_ctx,
  1362. file_list_t *list,
  1363. menu_file_list_cbs_t *cbs,
  1364. const char *path, const char *label,
  1365. unsigned type, size_t idx)
  1366. {
  1367. const char *menu_label = NULL;
  1368. file_list_t *menu_list = MENU_LIST_GET(menu_st->entries.list, 0);
  1369. #ifdef DEBUG_LOG
  1370. menu_file_list_cbs_t *menu_cbs = (menu_file_list_cbs_t*)
  1371. menu_list->list[list->size - 1].actiondata;
  1372. enum msg_hash_enums enum_idx = menu_cbs ? menu_cbs->enum_idx : MSG_UNKNOWN;
  1373. #endif
  1374. if (menu_list && menu_list->size)
  1375. file_list_get_at_offset(menu_list, menu_list->size - 1, NULL, &menu_label, NULL, NULL);
  1376. if (!label || !menu_label)
  1377. return;
  1378. #ifdef DEBUG_LOG
  1379. RARCH_LOG("\n");
  1380. if (cbs && cbs->enum_idx != MSG_UNKNOWN)
  1381. RARCH_LOG("\t\t\tenum_idx %d [%s]\n", cbs->enum_idx, msg_hash_to_str(cbs->enum_idx));
  1382. #endif
  1383. /* It will try to find a corresponding callback function inside
  1384. * menu_cbs_ok.c, then map this callback to the entry. */
  1385. menu_cbs_init_bind_ok(cbs, path, label, type, idx, menu_label);
  1386. /* It will try to find a corresponding callback function inside
  1387. * menu_cbs_cancel.c, then map this callback to the entry. */
  1388. menu_cbs_init_bind_cancel(cbs, path, label, type, idx);
  1389. /* It will try to find a corresponding callback function inside
  1390. * menu_cbs_scan.c, then map this callback to the entry. */
  1391. menu_cbs_init_bind_scan(cbs, path, label, type, idx);
  1392. /* It will try to find a corresponding callback function inside
  1393. * menu_cbs_start.c, then map this callback to the entry. */
  1394. menu_cbs_init_bind_start(cbs, path, label, type, idx);
  1395. /* It will try to find a corresponding callback function inside
  1396. * menu_cbs_select.c, then map this callback to the entry. */
  1397. menu_cbs_init_bind_select(cbs, path, label, type, idx);
  1398. /* It will try to find a corresponding callback function inside
  1399. * menu_cbs_info.c, then map this callback to the entry. */
  1400. menu_cbs_init_bind_info(cbs, path, label, type, idx);
  1401. /* It will try to find a corresponding callback function inside
  1402. * menu_cbs_left.c, then map this callback to the entry. */
  1403. menu_cbs_init_bind_left(cbs, path, label, type, idx, menu_label);
  1404. /* It will try to find a corresponding callback function inside
  1405. * menu_cbs_right.c, then map this callback to the entry. */
  1406. menu_cbs_init_bind_right(cbs, path, label, type, idx, menu_label);
  1407. /* It will try to find a corresponding callback function inside
  1408. * menu_cbs_deferred_push.c, then map this callback to the entry. */
  1409. menu_cbs_init_bind_deferred_push(cbs, path, label, type, idx);
  1410. /* It will try to find a corresponding callback function inside
  1411. * menu_cbs_get_string_representation.c, then map this callback to the entry. */
  1412. menu_cbs_init_bind_get_string_representation(cbs, path, label, type, idx);
  1413. /* It will try to find a corresponding callback function inside
  1414. * menu_cbs_title.c, then map this callback to the entry. */
  1415. menu_cbs_init_bind_title(cbs, path, label, type, idx);
  1416. /* It will try to find a corresponding callback function inside
  1417. * menu_cbs_label.c, then map this callback to the entry. */
  1418. menu_cbs_init_bind_label(cbs, path, label, type, idx);
  1419. /* It will try to find a corresponding callback function inside
  1420. * menu_cbs_sublabel.c, then map this callback to the entry. */
  1421. menu_cbs_init_bind_sublabel(cbs, path, label, type, idx);
  1422. if (menu_driver_ctx && menu_driver_ctx->bind_init)
  1423. menu_driver_ctx->bind_init(
  1424. cbs,
  1425. path,
  1426. label,
  1427. type,
  1428. idx);
  1429. }
  1430. /* Pretty much a stub function. TODO/FIXME - Might as well remove this. */
  1431. int menu_cbs_exit(void)
  1432. {
  1433. return -1;
  1434. }
  1435. static enum action_iterate_type action_iterate_type(const char *label)
  1436. {
  1437. if (string_is_equal(label, "info_screen"))
  1438. return ITERATE_TYPE_INFO;
  1439. if (string_starts_with_size(label, "help", STRLEN_CONST("help")))
  1440. if (
  1441. string_is_equal(label, "help") ||
  1442. string_is_equal(label, "help_controls") ||
  1443. string_is_equal(label, "help_what_is_a_core") ||
  1444. string_is_equal(label, "help_loading_content") ||
  1445. string_is_equal(label, "help_scanning_content") ||
  1446. string_is_equal(label, "help_change_virtual_gamepad") ||
  1447. string_is_equal(label, "help_audio_video_troubleshooting") ||
  1448. string_is_equal(label, "help_send_debug_info")
  1449. )
  1450. return ITERATE_TYPE_HELP;
  1451. if (string_is_equal(label, "cheevos_description"))
  1452. return ITERATE_TYPE_HELP;
  1453. if (string_starts_with_size(label, "custom_bind", STRLEN_CONST("custom_bind")))
  1454. if (
  1455. string_is_equal(label, "custom_bind") ||
  1456. string_is_equal(label, "custom_bind_all") ||
  1457. string_is_equal(label, "custom_bind_defaults")
  1458. )
  1459. return ITERATE_TYPE_BIND;
  1460. return ITERATE_TYPE_DEFAULT;
  1461. }
  1462. #ifdef HAVE_ACCESSIBILITY
  1463. static void get_current_menu_value(struct menu_state *menu_st,
  1464. char *s, size_t len)
  1465. {
  1466. menu_entry_t entry;
  1467. const char* entry_label;
  1468. MENU_ENTRY_INIT(entry);
  1469. entry.path_enabled = false;
  1470. entry.label_enabled = false;
  1471. entry.rich_label_enabled = false;
  1472. entry.sublabel_enabled = false;
  1473. menu_entry_get(&entry, 0, menu_st->selection_ptr, NULL, true);
  1474. if (entry.enum_idx == MENU_ENUM_LABEL_CHEEVOS_PASSWORD)
  1475. entry_label = entry.password_value;
  1476. else
  1477. entry_label = entry.value;
  1478. strlcpy(s, entry_label, len);
  1479. }
  1480. static void get_current_menu_label(struct menu_state *menu_st,
  1481. char *s, size_t len)
  1482. {
  1483. menu_entry_t entry;
  1484. const char* entry_label;
  1485. MENU_ENTRY_INIT(entry);
  1486. menu_entry_get(&entry, 0, menu_st->selection_ptr, NULL, true);
  1487. if (!string_is_empty(entry.rich_label))
  1488. entry_label = entry.rich_label;
  1489. else
  1490. entry_label = entry.path;
  1491. strlcpy(s, entry_label, len);
  1492. }
  1493. static void get_current_menu_sublabel(struct menu_state *menu_st,
  1494. char *s, size_t len)
  1495. {
  1496. menu_entry_t entry;
  1497. MENU_ENTRY_INIT(entry);
  1498. entry.path_enabled = false;
  1499. entry.label_enabled = false;
  1500. entry.rich_label_enabled = false;
  1501. entry.value_enabled = false;
  1502. menu_entry_get(&entry, 0, menu_st->selection_ptr, NULL, true);
  1503. strlcpy(s, entry.sublabel, len);
  1504. }
  1505. #endif
  1506. static void menu_input_set_pointer_visibility(
  1507. menu_input_pointer_hw_state_t *pointer_hw_state,
  1508. menu_input_t *menu_input,
  1509. retro_time_t current_time)
  1510. {
  1511. static bool cursor_shown = false;
  1512. static bool cursor_hidden = false;
  1513. static retro_time_t end_time = 0;
  1514. /* Ensure that mouse cursor is hidden when not in use */
  1515. if ((menu_input->pointer.type == MENU_POINTER_MOUSE)
  1516. && pointer_hw_state->active)
  1517. {
  1518. /* Show cursor */
  1519. if ((current_time > end_time) && !cursor_shown)
  1520. {
  1521. menu_ctx_environment_t menu_environ;
  1522. menu_environ.type = MENU_ENVIRON_ENABLE_MOUSE_CURSOR;
  1523. menu_environ.data = NULL;
  1524. menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ);
  1525. cursor_shown = true;
  1526. cursor_hidden = false;
  1527. }
  1528. end_time = current_time + MENU_INPUT_HIDE_CURSOR_DELAY;
  1529. }
  1530. else
  1531. {
  1532. /* Hide cursor */
  1533. if ((current_time > end_time) && !cursor_hidden)
  1534. {
  1535. menu_ctx_environment_t menu_environ;
  1536. menu_environ.type = MENU_ENVIRON_DISABLE_MOUSE_CURSOR;
  1537. menu_environ.data = NULL;
  1538. menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ);
  1539. cursor_shown = false;
  1540. cursor_hidden = true;
  1541. }
  1542. }
  1543. }
  1544. /**
  1545. * menu_iterate:
  1546. * @input : input sample for this frame
  1547. * @old_input : input sample of the previous frame
  1548. * @trigger_input : difference' input sample - difference
  1549. * between 'input' and 'old_input'
  1550. *
  1551. * Runs RetroArch menu for one frame.
  1552. *
  1553. * Returns: 0 on success, -1 if we need to quit out of the loop.
  1554. **/
  1555. static int generic_menu_iterate(
  1556. struct rarch_state *p_rarch,
  1557. menu_handle_t *menu,
  1558. void *userdata, enum menu_action action,
  1559. retro_time_t current_time)
  1560. {
  1561. #ifdef HAVE_ACCESSIBILITY
  1562. static enum action_iterate_type
  1563. last_iterate_type = ITERATE_TYPE_DEFAULT;
  1564. #endif
  1565. enum action_iterate_type iterate_type;
  1566. unsigned file_type = 0;
  1567. int ret = 0;
  1568. const char *label = NULL;
  1569. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  1570. gfx_display_t *p_disp = &p_rarch->dispgfx;
  1571. gfx_animation_t *p_anim = &p_rarch->anim;
  1572. file_list_t *list = MENU_LIST_GET(menu_st->entries.list, 0);
  1573. if (list && list->size)
  1574. file_list_get_at_offset(list, list->size - 1, NULL, &label, &file_type, NULL);
  1575. menu->menu_state_msg[0] = '\0';
  1576. iterate_type = action_iterate_type(label);
  1577. p_rarch->menu_driver_is_binding = false;
  1578. if ( action != MENU_ACTION_NOOP
  1579. || MENU_ENTRIES_NEEDS_REFRESH(menu_st)
  1580. || GFX_DISPLAY_GET_UPDATE_PENDING(p_anim, p_disp))
  1581. {
  1582. BIT64_SET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER);
  1583. }
  1584. switch (iterate_type)
  1585. {
  1586. case ITERATE_TYPE_HELP:
  1587. ret = menu_dialog_iterate(
  1588. &p_rarch->dialog_st,
  1589. menu->menu_state_msg, sizeof(menu->menu_state_msg),
  1590. current_time);
  1591. #ifdef HAVE_ACCESSIBILITY
  1592. if ( (iterate_type != last_iterate_type)
  1593. && is_accessibility_enabled(p_rarch))
  1594. accessibility_speak_priority(p_rarch,
  1595. menu->menu_state_msg, 10);
  1596. #endif
  1597. BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX);
  1598. BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);
  1599. {
  1600. bool pop_stack = false;
  1601. if ( ret == 1 ||
  1602. action == MENU_ACTION_OK ||
  1603. action == MENU_ACTION_CANCEL
  1604. )
  1605. pop_stack = true;
  1606. if (pop_stack)
  1607. BIT64_SET(menu->state, MENU_STATE_POP_STACK);
  1608. }
  1609. break;
  1610. case ITERATE_TYPE_BIND:
  1611. {
  1612. menu_input_ctx_bind_t bind;
  1613. p_rarch->menu_driver_is_binding = true;
  1614. bind.s = menu->menu_state_msg;
  1615. bind.len = sizeof(menu->menu_state_msg);
  1616. if (menu_input_key_bind_iterate(p_rarch,
  1617. &bind, current_time))
  1618. {
  1619. size_t selection = menu_st->selection_ptr;
  1620. menu_entries_pop_stack(&selection, 0, 0);
  1621. menu_st->selection_ptr = selection;
  1622. }
  1623. else
  1624. BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX);
  1625. }
  1626. break;
  1627. case ITERATE_TYPE_INFO:
  1628. {
  1629. menu_list_t *menu_list = menu_st->entries.list;
  1630. file_list_t *selection_buf = menu_list ? MENU_LIST_GET_SELECTION(menu_list, (unsigned)0) : NULL;
  1631. size_t selection = menu_st->selection_ptr;
  1632. menu_file_list_cbs_t *cbs = selection_buf ?
  1633. (menu_file_list_cbs_t*)selection_buf->list[selection].actiondata
  1634. : NULL;
  1635. if (cbs && cbs->enum_idx != MSG_UNKNOWN)
  1636. {
  1637. /* Core updater/manager entries require special treatment */
  1638. switch (cbs->enum_idx)
  1639. {
  1640. #ifdef HAVE_NETWORKING
  1641. case MENU_ENUM_LABEL_CORE_UPDATER_ENTRY:
  1642. {
  1643. core_updater_list_t *core_list =
  1644. core_updater_list_get_cached();
  1645. const core_updater_list_entry_t *entry = NULL;
  1646. const char *path =
  1647. selection_buf->list[selection].path;
  1648. /* Search for specified core */
  1649. if (
  1650. core_list
  1651. && path
  1652. && core_updater_list_get_filename(core_list,
  1653. path, &entry)
  1654. && !string_is_empty(entry->description)
  1655. )
  1656. strlcpy(menu->menu_state_msg, entry->description,
  1657. sizeof(menu->menu_state_msg));
  1658. else
  1659. strlcpy(menu->menu_state_msg,
  1660. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE),
  1661. sizeof(menu->menu_state_msg));
  1662. ret = 0;
  1663. }
  1664. break;
  1665. #endif
  1666. case MENU_ENUM_LABEL_CORE_MANAGER_ENTRY:
  1667. {
  1668. core_info_ctx_find_t core_info;
  1669. const char *path = selection_buf->list[selection].path;
  1670. /* Search for specified core */
  1671. core_info.inf = NULL;
  1672. core_info.path = path;
  1673. if ( path
  1674. && core_info_find(&core_info)
  1675. && !string_is_empty(core_info.inf->description))
  1676. strlcpy(menu->menu_state_msg,
  1677. core_info.inf->description,
  1678. sizeof(menu->menu_state_msg));
  1679. else
  1680. strlcpy(menu->menu_state_msg,
  1681. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE),
  1682. sizeof(menu->menu_state_msg));
  1683. ret = 0;
  1684. }
  1685. break;
  1686. default:
  1687. ret = msg_hash_get_help_enum(cbs->enum_idx,
  1688. menu->menu_state_msg, sizeof(menu->menu_state_msg));
  1689. break;
  1690. }
  1691. #ifdef HAVE_ACCESSIBILITY
  1692. if ( (iterate_type != last_iterate_type) &&
  1693. is_accessibility_enabled(p_rarch))
  1694. {
  1695. if (string_is_equal(menu->menu_state_msg,
  1696. msg_hash_to_str(
  1697. MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE)))
  1698. {
  1699. char current_sublabel[255];
  1700. get_current_menu_sublabel(
  1701. &p_rarch->menu_driver_state,
  1702. current_sublabel, sizeof(current_sublabel));
  1703. if (string_is_equal(current_sublabel, ""))
  1704. accessibility_speak_priority(p_rarch,
  1705. menu->menu_state_msg, 10);
  1706. else
  1707. accessibility_speak_priority(p_rarch,
  1708. current_sublabel, 10);
  1709. }
  1710. else
  1711. accessibility_speak_priority(p_rarch,
  1712. menu->menu_state_msg, 10);
  1713. }
  1714. #endif
  1715. }
  1716. else
  1717. {
  1718. enum msg_hash_enums enum_idx = MSG_UNKNOWN;
  1719. size_t selection = menu_st->selection_ptr;
  1720. unsigned type = selection_buf->list[selection].type;
  1721. switch (type)
  1722. {
  1723. case FILE_TYPE_FONT:
  1724. case FILE_TYPE_VIDEO_FONT:
  1725. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_FONT;
  1726. break;
  1727. case FILE_TYPE_RDB:
  1728. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_RDB;
  1729. break;
  1730. case FILE_TYPE_OVERLAY:
  1731. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_OVERLAY;
  1732. break;
  1733. #ifdef HAVE_VIDEO_LAYOUT
  1734. case FILE_TYPE_VIDEO_LAYOUT:
  1735. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_VIDEO_LAYOUT;
  1736. break;
  1737. #endif
  1738. case FILE_TYPE_CHEAT:
  1739. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CHEAT;
  1740. break;
  1741. case FILE_TYPE_SHADER_PRESET:
  1742. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_SHADER_PRESET;
  1743. break;
  1744. case FILE_TYPE_SHADER:
  1745. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_SHADER;
  1746. break;
  1747. case FILE_TYPE_REMAP:
  1748. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_REMAP;
  1749. break;
  1750. case FILE_TYPE_RECORD_CONFIG:
  1751. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_RECORD_CONFIG;
  1752. break;
  1753. case FILE_TYPE_CURSOR:
  1754. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CURSOR;
  1755. break;
  1756. case FILE_TYPE_CONFIG:
  1757. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CONFIG;
  1758. break;
  1759. case FILE_TYPE_CARCHIVE:
  1760. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_COMPRESSED_ARCHIVE;
  1761. break;
  1762. case FILE_TYPE_DIRECTORY:
  1763. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY;
  1764. break;
  1765. case FILE_TYPE_VIDEOFILTER: /* TODO/FIXME */
  1766. case FILE_TYPE_AUDIOFILTER: /* TODO/FIXME */
  1767. case FILE_TYPE_SHADER_SLANG: /* TODO/FIXME */
  1768. case FILE_TYPE_SHADER_GLSL: /* TODO/FIXME */
  1769. case FILE_TYPE_SHADER_HLSL: /* TODO/FIXME */
  1770. case FILE_TYPE_SHADER_CG: /* TODO/FIXME */
  1771. case FILE_TYPE_SHADER_PRESET_GLSLP: /* TODO/FIXME */
  1772. case FILE_TYPE_SHADER_PRESET_HLSLP: /* TODO/FIXME */
  1773. case FILE_TYPE_SHADER_PRESET_CGP: /* TODO/FIXME */
  1774. case FILE_TYPE_SHADER_PRESET_SLANGP: /* TODO/FIXME */
  1775. case FILE_TYPE_PLAIN:
  1776. enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_PLAIN_FILE;
  1777. break;
  1778. default:
  1779. break;
  1780. }
  1781. if (enum_idx != MSG_UNKNOWN)
  1782. ret = msg_hash_get_help_enum(enum_idx,
  1783. menu->menu_state_msg, sizeof(menu->menu_state_msg));
  1784. else
  1785. {
  1786. strlcpy(menu->menu_state_msg,
  1787. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE),
  1788. sizeof(menu->menu_state_msg));
  1789. ret = 0;
  1790. }
  1791. }
  1792. }
  1793. BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX);
  1794. BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);
  1795. if (action == MENU_ACTION_OK || action == MENU_ACTION_CANCEL)
  1796. {
  1797. BIT64_SET(menu->state, MENU_STATE_POP_STACK);
  1798. }
  1799. break;
  1800. case ITERATE_TYPE_DEFAULT:
  1801. {
  1802. menu_entry_t entry;
  1803. menu_list_t *menu_list = menu_st->entries.list;
  1804. size_t selection = menu_st->selection_ptr;
  1805. size_t menu_list_size = menu_st->entries.list ? MENU_LIST_GET_SELECTION(menu_st->entries.list, 0)->size : 0;
  1806. /* FIXME: Crappy hack, needed for mouse controls
  1807. * to not be completely broken in case we press back.
  1808. *
  1809. * We need to fix this entire mess, mouse controls
  1810. * should not rely on a hack like this in order to work. */
  1811. selection = MAX(MIN(selection, (menu_list_size - 1)), 0);
  1812. MENU_ENTRY_INIT(entry);
  1813. /* NOTE: If menu_entry_action() is modified,
  1814. * will have to verify that these parameters
  1815. * remain unused... */
  1816. entry.rich_label_enabled = false;
  1817. entry.value_enabled = false;
  1818. entry.sublabel_enabled = false;
  1819. menu_entry_get(&entry, 0, selection, NULL, false);
  1820. ret = menu_entry_action(&entry,
  1821. selection, (enum menu_action)action);
  1822. if (ret)
  1823. return -1;
  1824. BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);
  1825. /* Have to defer it so we let settings refresh. */
  1826. if (p_rarch->dialog_st.pending_push)
  1827. {
  1828. const char *label;
  1829. menu_displaylist_info_t info;
  1830. menu_displaylist_info_init(&info);
  1831. info.list = menu_list ? MENU_LIST_GET(menu_list, (unsigned)0) : NULL;
  1832. info.enum_idx = MENU_ENUM_LABEL_HELP;
  1833. /* Set the label string, if it exists. */
  1834. label = msg_hash_to_str(MENU_ENUM_LABEL_HELP);
  1835. if (label)
  1836. info.label = strdup(label);
  1837. menu_displaylist_ctl(DISPLAYLIST_HELP, &info);
  1838. }
  1839. }
  1840. break;
  1841. }
  1842. #ifdef HAVE_ACCESSIBILITY
  1843. if ((last_iterate_type == ITERATE_TYPE_HELP
  1844. || last_iterate_type == ITERATE_TYPE_INFO)
  1845. && last_iterate_type != iterate_type
  1846. && is_accessibility_enabled(p_rarch))
  1847. accessibility_speak_priority(p_rarch,
  1848. "Closed dialog.", 10);
  1849. last_iterate_type = iterate_type;
  1850. #endif
  1851. BIT64_SET(menu->state, MENU_STATE_BLIT);
  1852. if (BIT64_GET(menu->state, MENU_STATE_POP_STACK))
  1853. {
  1854. size_t selection = menu_st->selection_ptr;
  1855. size_t new_selection_ptr = selection;
  1856. menu_entries_pop_stack(&new_selection_ptr, 0, 0);
  1857. menu_st->selection_ptr = selection;
  1858. }
  1859. if (BIT64_GET(menu->state, MENU_STATE_POST_ITERATE))
  1860. {
  1861. menu_input_t *menu_input = &p_rarch->menu_input_state;
  1862. /* If pointer devices are disabled, just ensure mouse
  1863. * cursor is hidden */
  1864. if (menu_input->pointer.type == MENU_POINTER_DISABLED)
  1865. ret = 0;
  1866. else
  1867. ret = menu_input_post_iterate(p_rarch, action,
  1868. current_time);
  1869. menu_input_set_pointer_visibility(
  1870. &p_rarch->menu_input_pointer_hw_state, menu_input, current_time);
  1871. }
  1872. if (ret)
  1873. return -1;
  1874. return 0;
  1875. }
  1876. static bool menu_driver_displaylist_push_internal(
  1877. const char *label,
  1878. menu_displaylist_info_t *info)
  1879. {
  1880. if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HISTORY_TAB)))
  1881. {
  1882. if (menu_displaylist_ctl(DISPLAYLIST_HISTORY, info))
  1883. return true;
  1884. }
  1885. else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB)))
  1886. {
  1887. if (menu_displaylist_ctl(DISPLAYLIST_FAVORITES, info))
  1888. return true;
  1889. }
  1890. else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SETTINGS_TAB)))
  1891. {
  1892. if (menu_displaylist_ctl(DISPLAYLIST_SETTINGS_ALL, info))
  1893. return true;
  1894. }
  1895. #ifdef HAVE_CHEATS
  1896. else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CHEAT_SEARCH_SETTINGS)))
  1897. {
  1898. if (menu_displaylist_ctl(DISPLAYLIST_CHEAT_SEARCH_SETTINGS_LIST, info))
  1899. return true;
  1900. }
  1901. #endif
  1902. else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_MUSIC_TAB)))
  1903. {
  1904. filebrowser_clear_type();
  1905. info->type = 42;
  1906. if (!string_is_empty(info->exts))
  1907. free(info->exts);
  1908. if (!string_is_empty(info->label))
  1909. free(info->label);
  1910. info->exts = strdup("lpl");
  1911. info->label = strdup(
  1912. msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB));
  1913. menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
  1914. menu_displaylist_ctl(DISPLAYLIST_MUSIC_HISTORY, info);
  1915. return true;
  1916. }
  1917. else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_TAB)))
  1918. {
  1919. filebrowser_clear_type();
  1920. info->type = 42;
  1921. if (!string_is_empty(info->exts))
  1922. free(info->exts);
  1923. if (!string_is_empty(info->label))
  1924. free(info->label);
  1925. info->exts = strdup("lpl");
  1926. info->label = strdup(
  1927. msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB));
  1928. menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
  1929. menu_displaylist_ctl(DISPLAYLIST_VIDEO_HISTORY, info);
  1930. return true;
  1931. }
  1932. else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_IMAGES_TAB)))
  1933. {
  1934. filebrowser_clear_type();
  1935. info->type = 42;
  1936. if (!string_is_empty(info->exts))
  1937. free(info->exts);
  1938. if (!string_is_empty(info->label))
  1939. free(info->label);
  1940. info->exts = strdup("lpl");
  1941. info->label = strdup(
  1942. msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB));
  1943. menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
  1944. #if 0
  1945. #ifdef HAVE_SCREENSHOTS
  1946. if (!rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
  1947. menu_entries_append_enum(info->list,
  1948. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT),
  1949. msg_hash_to_str(MENU_ENUM_LABEL_TAKE_SCREENSHOT),
  1950. MENU_ENUM_LABEL_TAKE_SCREENSHOT,
  1951. MENU_SETTING_ACTION_SCREENSHOT, 0, 0);
  1952. else
  1953. info->need_push_no_playlist_entries = true;
  1954. #endif
  1955. #endif
  1956. menu_displaylist_ctl(DISPLAYLIST_IMAGES_HISTORY, info);
  1957. return true;
  1958. }
  1959. else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB)))
  1960. {
  1961. struct rarch_state *p_rarch = &rarch_st;
  1962. settings_t *settings = p_rarch->configuration_settings;
  1963. const char *dir_playlist = settings->paths.directory_playlist;
  1964. filebrowser_clear_type();
  1965. info->type = 42;
  1966. if (!string_is_empty(info->exts))
  1967. free(info->exts);
  1968. if (!string_is_empty(info->label))
  1969. free(info->label);
  1970. info->exts = strdup("lpl");
  1971. info->label = strdup(
  1972. msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB));
  1973. if (string_is_empty(dir_playlist))
  1974. {
  1975. menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
  1976. info->need_refresh = true;
  1977. info->need_push_no_playlist_entries = true;
  1978. info->need_push = true;
  1979. return true;
  1980. }
  1981. if (!string_is_empty(info->path))
  1982. free(info->path);
  1983. info->path = strdup(dir_playlist);
  1984. if (menu_displaylist_ctl(
  1985. DISPLAYLIST_DATABASE_PLAYLISTS, info))
  1986. return true;
  1987. }
  1988. else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ADD_TAB)))
  1989. {
  1990. if (menu_displaylist_ctl(DISPLAYLIST_SCAN_DIRECTORY_LIST, info))
  1991. return true;
  1992. }
  1993. #if defined(HAVE_LIBRETRODB)
  1994. else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_EXPLORE_TAB)))
  1995. {
  1996. if (menu_displaylist_ctl(DISPLAYLIST_EXPLORE, info))
  1997. return true;
  1998. }
  1999. #endif
  2000. else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB)))
  2001. {
  2002. if (menu_displaylist_ctl(DISPLAYLIST_NETPLAY_ROOM_LIST, info))
  2003. return true;
  2004. }
  2005. else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HORIZONTAL_MENU)))
  2006. {
  2007. if (menu_displaylist_ctl(DISPLAYLIST_HORIZONTAL, info))
  2008. return true;
  2009. }
  2010. return false;
  2011. }
  2012. static bool menu_driver_displaylist_push(
  2013. struct rarch_state *p_rarch,
  2014. struct menu_state *menu_st,
  2015. file_list_t *entry_list,
  2016. file_list_t *entry_stack)
  2017. {
  2018. menu_displaylist_info_t info;
  2019. const char *path = NULL;
  2020. const char *label = NULL;
  2021. unsigned type = 0;
  2022. bool ret = false;
  2023. enum msg_hash_enums enum_idx = MSG_UNKNOWN;
  2024. file_list_t *list = MENU_LIST_GET(menu_st->entries.list, 0);
  2025. menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)
  2026. list->list[list->size - 1].actiondata;
  2027. menu_displaylist_info_init(&info);
  2028. if (list && list->size)
  2029. file_list_get_at_offset(list, list->size - 1, &path, &label, &type, NULL);
  2030. if (cbs)
  2031. enum_idx = cbs->enum_idx;
  2032. info.list = entry_list;
  2033. info.menu_list = entry_stack;
  2034. info.type = type;
  2035. info.enum_idx = enum_idx;
  2036. if (!string_is_empty(path))
  2037. info.path = strdup(path);
  2038. if (!string_is_empty(label))
  2039. info.label = strdup(label);
  2040. if (!info.list)
  2041. goto error;
  2042. if (menu_driver_displaylist_push_internal(label, &info))
  2043. {
  2044. ret = menu_displaylist_process(&info);
  2045. goto end;
  2046. }
  2047. cbs = (menu_file_list_cbs_t*)list->list[list->size - 1].actiondata;
  2048. if (cbs && cbs->action_deferred_push)
  2049. if (cbs->action_deferred_push(&info) != 0)
  2050. goto error;
  2051. ret = true;
  2052. end:
  2053. menu_displaylist_info_free(&info);
  2054. return ret;
  2055. error:
  2056. menu_displaylist_info_free(&info);
  2057. return false;
  2058. }
  2059. int generic_menu_entry_action(
  2060. void *userdata, menu_entry_t *entry, size_t i, enum menu_action action)
  2061. {
  2062. int ret = 0;
  2063. struct rarch_state *p_rarch = &rarch_st;
  2064. const menu_ctx_driver_t
  2065. *menu_driver_ctx = p_rarch->menu_driver_ctx;
  2066. settings_t *settings = p_rarch->configuration_settings;
  2067. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  2068. menu_list_t *menu_list = menu_st->entries.list;
  2069. file_list_t *selection_buf = menu_list ? MENU_LIST_GET_SELECTION(menu_list, (unsigned)0) : NULL;
  2070. file_list_t *menu_stack = menu_list ? MENU_LIST_GET(menu_list, (unsigned)0) : NULL;
  2071. size_t selection_buf_size = selection_buf ? selection_buf->size : 0;
  2072. menu_file_list_cbs_t *cbs = selection_buf ?
  2073. (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL;
  2074. switch (action)
  2075. {
  2076. case MENU_ACTION_UP:
  2077. if (selection_buf_size > 0)
  2078. {
  2079. size_t scroll_accel = menu_st->scroll.acceleration;
  2080. unsigned scroll_speed = (unsigned)((MAX(scroll_accel, 2) - 2) / 4 + 1);
  2081. bool wraparound_enable = settings->bools.menu_navigation_wraparound_enable;
  2082. if (!(menu_st->selection_ptr == 0 && !wraparound_enable))
  2083. {
  2084. size_t idx = 0;
  2085. if (menu_st->selection_ptr >= scroll_speed)
  2086. idx = menu_st->selection_ptr - scroll_speed;
  2087. else
  2088. {
  2089. idx = selection_buf_size - 1;
  2090. if (!wraparound_enable)
  2091. idx = 0;
  2092. }
  2093. menu_st->selection_ptr = idx;
  2094. menu_driver_navigation_set(true);
  2095. if (menu_driver_ctx->navigation_decrement)
  2096. menu_driver_ctx->navigation_decrement(p_rarch->menu_userdata);
  2097. }
  2098. }
  2099. break;
  2100. case MENU_ACTION_DOWN:
  2101. if (selection_buf_size > 0)
  2102. {
  2103. size_t scroll_accel = menu_st->scroll.acceleration;
  2104. unsigned scroll_speed = (unsigned)((MAX(scroll_accel, 2) - 2) / 4 + 1);
  2105. bool wraparound_enable = settings->bools.menu_navigation_wraparound_enable;
  2106. if (!(menu_st->selection_ptr >= selection_buf_size - 1
  2107. && !wraparound_enable))
  2108. {
  2109. if ((menu_st->selection_ptr + scroll_speed) < selection_buf_size)
  2110. {
  2111. size_t idx = menu_st->selection_ptr + scroll_speed;
  2112. menu_st->selection_ptr = idx;
  2113. menu_driver_navigation_set(true);
  2114. }
  2115. else
  2116. {
  2117. if (wraparound_enable)
  2118. {
  2119. bool pending_push = false;
  2120. menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
  2121. }
  2122. else if (selection_buf_size > 0)
  2123. menu_driver_ctl(MENU_NAVIGATION_CTL_SET_LAST, NULL);
  2124. }
  2125. if (menu_driver_ctx->navigation_increment)
  2126. menu_driver_ctx->navigation_increment(p_rarch->menu_userdata);
  2127. }
  2128. }
  2129. break;
  2130. case MENU_ACTION_SCROLL_UP:
  2131. if (
  2132. menu_st->scroll.index_size
  2133. && menu_st->selection_ptr != 0
  2134. )
  2135. {
  2136. size_t i = menu_st->scroll.index_size - 1;
  2137. while (i
  2138. && menu_st->scroll.index_list[i - 1]
  2139. >= menu_st->selection_ptr)
  2140. i--;
  2141. if (i > 0)
  2142. menu_st->selection_ptr = menu_st->scroll.index_list[i - 1];
  2143. if (menu_driver_ctx->navigation_descend_alphabet)
  2144. menu_driver_ctx->navigation_descend_alphabet(
  2145. p_rarch->menu_userdata, &menu_st->selection_ptr);
  2146. }
  2147. break;
  2148. case MENU_ACTION_SCROLL_DOWN:
  2149. if (menu_st->scroll.index_size)
  2150. {
  2151. if (menu_st->selection_ptr == menu_st->scroll.index_list[menu_st->scroll.index_size - 1])
  2152. menu_st->selection_ptr = selection_buf_size - 1;
  2153. else
  2154. {
  2155. size_t i = 0;
  2156. while (i < menu_st->scroll.index_size - 1
  2157. && menu_st->scroll.index_list[i + 1] <= menu_st->selection_ptr)
  2158. i++;
  2159. menu_st->selection_ptr = menu_st->scroll.index_list[i + 1];
  2160. if (menu_st->selection_ptr >= selection_buf_size)
  2161. menu_st->selection_ptr = selection_buf_size - 1;
  2162. }
  2163. if (menu_driver_ctx->navigation_ascend_alphabet)
  2164. menu_driver_ctx->navigation_ascend_alphabet(
  2165. p_rarch->menu_userdata, &menu_st->selection_ptr);
  2166. }
  2167. break;
  2168. case MENU_ACTION_CANCEL:
  2169. if (cbs && cbs->action_cancel)
  2170. ret = cbs->action_cancel(entry->path,
  2171. entry->label, entry->type, i);
  2172. break;
  2173. case MENU_ACTION_OK:
  2174. if (cbs && cbs->action_ok)
  2175. ret = cbs->action_ok(entry->path,
  2176. entry->label, entry->type, i, entry->entry_idx);
  2177. break;
  2178. case MENU_ACTION_START:
  2179. if (cbs && cbs->action_start)
  2180. ret = cbs->action_start(entry->path,
  2181. entry->label, entry->type, i, entry->entry_idx);
  2182. break;
  2183. case MENU_ACTION_LEFT:
  2184. if (cbs && cbs->action_left)
  2185. ret = cbs->action_left(entry->type, entry->label, false);
  2186. break;
  2187. case MENU_ACTION_RIGHT:
  2188. if (cbs && cbs->action_right)
  2189. ret = cbs->action_right(entry->type, entry->label, false);
  2190. break;
  2191. case MENU_ACTION_INFO:
  2192. if (cbs && cbs->action_info)
  2193. ret = cbs->action_info(entry->type, entry->label);
  2194. break;
  2195. case MENU_ACTION_SELECT:
  2196. if (cbs && cbs->action_select)
  2197. ret = cbs->action_select(entry->path,
  2198. entry->label, entry->type, i, entry->entry_idx);
  2199. break;
  2200. case MENU_ACTION_SEARCH:
  2201. menu_input_dialog_start_search();
  2202. break;
  2203. case MENU_ACTION_SCAN:
  2204. if (cbs && cbs->action_scan)
  2205. ret = cbs->action_scan(entry->path,
  2206. entry->label, entry->type, i);
  2207. break;
  2208. default:
  2209. break;
  2210. }
  2211. if (MENU_ENTRIES_NEEDS_REFRESH(menu_st))
  2212. {
  2213. bool refresh = false;
  2214. menu_driver_displaylist_push(
  2215. p_rarch,
  2216. menu_st,
  2217. selection_buf,
  2218. menu_stack);
  2219. menu_entries_ctl(MENU_ENTRIES_CTL_UNSET_REFRESH, &refresh);
  2220. }
  2221. #ifdef HAVE_ACCESSIBILITY
  2222. if ( action != 0
  2223. && is_accessibility_enabled(p_rarch)
  2224. && !menu_input_dialog_get_display_kb())
  2225. {
  2226. char current_label[255];
  2227. char current_value[255];
  2228. char title_name[255];
  2229. char speak_string[512];
  2230. strlcpy(title_name, "", sizeof(title_name));
  2231. strlcpy(current_label, "", sizeof(current_label));
  2232. get_current_menu_value(&p_rarch->menu_driver_state, current_value, sizeof(current_value));
  2233. switch (action)
  2234. {
  2235. case MENU_ACTION_ACCESSIBILITY_SPEAK_TITLE:
  2236. menu_entries_get_title(title_name, sizeof(title_name));
  2237. break;
  2238. case MENU_ACTION_START:
  2239. /* if equal to '..' we break, else we fall-through */
  2240. if (string_is_equal(current_value, "..."))
  2241. break;
  2242. /* fall-through */
  2243. case MENU_ACTION_ACCESSIBILITY_SPEAK_TITLE_LABEL:
  2244. case MENU_ACTION_OK:
  2245. case MENU_ACTION_LEFT:
  2246. case MENU_ACTION_RIGHT:
  2247. case MENU_ACTION_CANCEL:
  2248. menu_entries_get_title(title_name, sizeof(title_name));
  2249. get_current_menu_label(&p_rarch->menu_driver_state, current_label, sizeof(current_label));
  2250. break;
  2251. case MENU_ACTION_UP:
  2252. case MENU_ACTION_DOWN:
  2253. case MENU_ACTION_SCROLL_UP:
  2254. case MENU_ACTION_SCROLL_DOWN:
  2255. case MENU_ACTION_SELECT:
  2256. case MENU_ACTION_SEARCH:
  2257. case MENU_ACTION_ACCESSIBILITY_SPEAK_LABEL:
  2258. get_current_menu_label(&p_rarch->menu_driver_state, current_label, sizeof(current_label));
  2259. break;
  2260. case MENU_ACTION_SCAN:
  2261. case MENU_ACTION_INFO:
  2262. default:
  2263. break;
  2264. }
  2265. strlcpy(speak_string, "", sizeof(speak_string));
  2266. if (!string_is_equal(title_name, ""))
  2267. {
  2268. strlcpy(speak_string, title_name, sizeof(speak_string));
  2269. strlcat(speak_string, " ", sizeof(speak_string));
  2270. }
  2271. strlcat(speak_string, current_label, sizeof(speak_string));
  2272. if (!string_is_equal(current_value, "..."))
  2273. {
  2274. strlcat(speak_string, " ", sizeof(speak_string));
  2275. strlcat(speak_string, current_value, sizeof(speak_string));
  2276. }
  2277. if (!string_is_equal(speak_string, ""))
  2278. accessibility_speak_priority(p_rarch,
  2279. speak_string, 10);
  2280. }
  2281. #endif
  2282. if (p_rarch->menu_driver_state.pending_close_content)
  2283. {
  2284. menu_handle_t *menu = p_rarch->menu_driver_data;
  2285. const char *content_path = path_get(RARCH_PATH_CONTENT);
  2286. const char *menu_flush_to = msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU);
  2287. /* Flush to playlist entry menu if launched via playlist */
  2288. if (menu &&
  2289. !string_is_empty(menu->deferred_path) &&
  2290. !string_is_empty(content_path) &&
  2291. string_is_equal(menu->deferred_path, content_path))
  2292. menu_flush_to = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RPL_ENTRY_ACTIONS);
  2293. command_event(CMD_EVENT_UNLOAD_CORE, NULL);
  2294. menu_entries_flush_stack(menu_flush_to, 0);
  2295. menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL);
  2296. menu_st->selection_ptr = 0;
  2297. p_rarch->menu_driver_state.pending_close_content = false;
  2298. }
  2299. return ret;
  2300. }
  2301. void menu_navigation_set_selection(size_t val)
  2302. {
  2303. struct rarch_state *p_rarch = &rarch_st;
  2304. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  2305. menu_st->selection_ptr = val;
  2306. }
  2307. void menu_entry_get(menu_entry_t *entry, size_t stack_idx,
  2308. size_t i, void *userdata, bool use_representation)
  2309. {
  2310. char newpath[255];
  2311. const char *path = NULL;
  2312. const char *entry_label = NULL;
  2313. menu_file_list_cbs_t *cbs = NULL;
  2314. struct rarch_state *p_rarch = &rarch_st;
  2315. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  2316. file_list_t *selection_buf = MENU_ENTRIES_GET_SELECTION_BUF_PTR_INTERNAL(menu_st, stack_idx);
  2317. file_list_t *list = (userdata) ? (file_list_t*)userdata : selection_buf;
  2318. bool path_enabled = entry->path_enabled;
  2319. newpath[0] = '\0';
  2320. if (!list)
  2321. return;
  2322. path = list->list[i].path;
  2323. entry_label = list->list[i].label;
  2324. entry->type = list->list[i].type;
  2325. entry->entry_idx = list->list[i].entry_idx;
  2326. cbs = (menu_file_list_cbs_t*)list->list[i].actiondata;
  2327. entry->idx = (unsigned)i;
  2328. if (entry->label_enabled && !string_is_empty(entry_label))
  2329. strlcpy(entry->label, entry_label, sizeof(entry->label));
  2330. if (cbs)
  2331. {
  2332. const char *label = NULL;
  2333. entry->enum_idx = cbs->enum_idx;
  2334. entry->checked = cbs->checked;
  2335. file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
  2336. NULL, &label, NULL, NULL);
  2337. if (entry->rich_label_enabled && cbs->action_label)
  2338. {
  2339. cbs->action_label(list,
  2340. entry->type, (unsigned)i,
  2341. label, path,
  2342. entry->rich_label,
  2343. sizeof(entry->rich_label));
  2344. if (string_is_empty(entry->rich_label))
  2345. path_enabled = true;
  2346. }
  2347. if ((path_enabled || entry->value_enabled) &&
  2348. cbs->action_get_value &&
  2349. use_representation)
  2350. {
  2351. cbs->action_get_value(list,
  2352. &entry->spacing, entry->type,
  2353. (unsigned)i, label,
  2354. entry->value,
  2355. entry->value_enabled ? sizeof(entry->value) : 0,
  2356. path,
  2357. newpath,
  2358. path_enabled ? sizeof(newpath) : 0);
  2359. if (!string_is_empty(entry->value))
  2360. {
  2361. if (entry->enum_idx == MENU_ENUM_LABEL_CHEEVOS_PASSWORD)
  2362. {
  2363. size_t i;
  2364. size_t size = strlcpy(entry->password_value, entry->value,
  2365. sizeof(entry->password_value));
  2366. for (i = 0; i < size; i++)
  2367. entry->password_value[i] = '*';
  2368. }
  2369. }
  2370. }
  2371. if (entry->sublabel_enabled)
  2372. {
  2373. if (!string_is_empty(cbs->action_sublabel_cache))
  2374. strlcpy(entry->sublabel,
  2375. cbs->action_sublabel_cache, sizeof(entry->sublabel));
  2376. else if (cbs->action_sublabel)
  2377. {
  2378. /* If this function callback returns true,
  2379. * we know that the value won't change - so we
  2380. * can cache it instead. */
  2381. if (cbs->action_sublabel(list,
  2382. entry->type, (unsigned)i,
  2383. label, path,
  2384. entry->sublabel,
  2385. sizeof(entry->sublabel)) > 0)
  2386. strlcpy(cbs->action_sublabel_cache,
  2387. entry->sublabel,
  2388. sizeof(cbs->action_sublabel_cache));
  2389. }
  2390. }
  2391. }
  2392. if (path_enabled)
  2393. {
  2394. if (!string_is_empty(path) && !use_representation)
  2395. strlcpy(entry->path, path, sizeof(entry->path));
  2396. else if (
  2397. cbs
  2398. && cbs->setting
  2399. && cbs->setting->enum_value_idx != MSG_UNKNOWN
  2400. && !cbs->setting->dont_use_enum_idx_representation)
  2401. strlcpy(entry->path,
  2402. msg_hash_to_str(cbs->setting->enum_value_idx),
  2403. sizeof(entry->path));
  2404. else
  2405. if (!string_is_empty(newpath))
  2406. strlcpy(entry->path, newpath, sizeof(entry->path));
  2407. }
  2408. }
  2409. int menu_entry_action(
  2410. menu_entry_t *entry, size_t i, enum menu_action action)
  2411. {
  2412. struct rarch_state *p_rarch = &rarch_st;
  2413. if ( p_rarch->menu_driver_ctx
  2414. && p_rarch->menu_driver_ctx->entry_action)
  2415. return p_rarch->menu_driver_ctx->entry_action(
  2416. p_rarch->menu_userdata, entry, i, action);
  2417. return -1;
  2418. }
  2419. static void menu_list_free_list(
  2420. const menu_ctx_driver_t *menu_driver_ctx,
  2421. file_list_t *list)
  2422. {
  2423. unsigned i;
  2424. for (i = 0; i < list->size; i++)
  2425. {
  2426. menu_ctx_list_t list_info;
  2427. list_info.list = list;
  2428. list_info.idx = i;
  2429. list_info.list_size = list->size;
  2430. menu_driver_list_free(menu_driver_ctx, &list_info);
  2431. }
  2432. file_list_free(list);
  2433. }
  2434. static void menu_list_free(
  2435. const menu_ctx_driver_t *menu_driver_ctx,
  2436. menu_list_t *menu_list)
  2437. {
  2438. if (!menu_list)
  2439. return;
  2440. if (menu_list->menu_stack)
  2441. {
  2442. unsigned i;
  2443. for (i = 0; i < menu_list->menu_stack_size; i++)
  2444. {
  2445. if (!menu_list->menu_stack[i])
  2446. continue;
  2447. menu_list_free_list(menu_driver_ctx,
  2448. menu_list->menu_stack[i]);
  2449. menu_list->menu_stack[i] = NULL;
  2450. }
  2451. free(menu_list->menu_stack);
  2452. }
  2453. if (menu_list->selection_buf)
  2454. {
  2455. unsigned i;
  2456. for (i = 0; i < menu_list->selection_buf_size; i++)
  2457. {
  2458. if (!menu_list->selection_buf[i])
  2459. continue;
  2460. menu_list_free_list(menu_driver_ctx,
  2461. menu_list->selection_buf[i]);
  2462. menu_list->selection_buf[i] = NULL;
  2463. }
  2464. free(menu_list->selection_buf);
  2465. }
  2466. free(menu_list);
  2467. }
  2468. static menu_list_t *menu_list_new(const menu_ctx_driver_t *menu_driver_ctx)
  2469. {
  2470. unsigned i;
  2471. menu_list_t *list = (menu_list_t*)malloc(sizeof(*list));
  2472. if (!list)
  2473. return NULL;
  2474. list->menu_stack_size = 1;
  2475. list->selection_buf_size = 1;
  2476. list->selection_buf = NULL;
  2477. list->menu_stack = (file_list_t**)
  2478. calloc(list->menu_stack_size, sizeof(*list->menu_stack));
  2479. if (!list->menu_stack)
  2480. goto error;
  2481. list->selection_buf = (file_list_t**)
  2482. calloc(list->selection_buf_size, sizeof(*list->selection_buf));
  2483. if (!list->selection_buf)
  2484. goto error;
  2485. for (i = 0; i < list->menu_stack_size; i++)
  2486. {
  2487. list->menu_stack[i] = (file_list_t*)
  2488. malloc(sizeof(*list->menu_stack[i]));
  2489. list->menu_stack[i]->list = NULL;
  2490. list->menu_stack[i]->capacity = 0;
  2491. list->menu_stack[i]->size = 0;
  2492. }
  2493. for (i = 0; i < list->selection_buf_size; i++)
  2494. {
  2495. list->selection_buf[i] = (file_list_t*)
  2496. malloc(sizeof(*list->selection_buf[i]));
  2497. list->selection_buf[i]->list = NULL;
  2498. list->selection_buf[i]->capacity = 0;
  2499. list->selection_buf[i]->size = 0;
  2500. }
  2501. return list;
  2502. error:
  2503. menu_list_free(menu_driver_ctx, list);
  2504. return NULL;
  2505. }
  2506. static int menu_list_flush_stack_type(const char *needle, const char *label,
  2507. unsigned type, unsigned final_type)
  2508. {
  2509. return needle ? !string_is_equal(needle, label) : (type != final_type);
  2510. }
  2511. static bool menu_list_pop_stack(
  2512. const menu_ctx_driver_t *menu_driver_ctx,
  2513. void *menu_userdata,
  2514. menu_list_t *list,
  2515. size_t idx,
  2516. size_t *directory_ptr)
  2517. {
  2518. file_list_t *menu_list = MENU_LIST_GET(list, (unsigned)idx);
  2519. if (menu_list->size != 0)
  2520. {
  2521. menu_ctx_list_t list_info;
  2522. list_info.list = menu_list;
  2523. list_info.idx = menu_list->size - 1;
  2524. list_info.list_size = menu_list->size - 1;
  2525. menu_driver_list_free(menu_driver_ctx, &list_info);
  2526. }
  2527. file_list_pop(menu_list, directory_ptr);
  2528. if ( menu_driver_ctx &&
  2529. menu_driver_ctx->list_set_selection)
  2530. menu_driver_ctx->list_set_selection(menu_userdata,
  2531. menu_list);
  2532. return true;
  2533. }
  2534. static void menu_list_flush_stack(
  2535. const menu_ctx_driver_t *menu_driver_ctx,
  2536. void *menu_userdata,
  2537. struct menu_state *menu_st,
  2538. menu_list_t *list,
  2539. size_t idx, const char *needle, unsigned final_type)
  2540. {
  2541. bool refresh = false;
  2542. const char *path = NULL;
  2543. const char *label = NULL;
  2544. unsigned type = 0;
  2545. size_t entry_idx = 0;
  2546. file_list_t *menu_list = MENU_LIST_GET(list, (unsigned)idx);
  2547. menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
  2548. if (menu_list && menu_list->size)
  2549. file_list_get_at_offset(menu_list, menu_list->size - 1, &path, &label, &type, &entry_idx);
  2550. while (menu_list_flush_stack_type(
  2551. needle, label, type, final_type) != 0)
  2552. {
  2553. bool refresh = false;
  2554. size_t new_selection_ptr = menu_st->selection_ptr;
  2555. bool wont_pop_stack = (MENU_LIST_GET_STACK_SIZE(list, idx) <= 1);
  2556. if (wont_pop_stack)
  2557. break;
  2558. if (menu_driver_ctx->list_cache)
  2559. menu_driver_ctx->list_cache(menu_userdata,
  2560. MENU_LIST_PLAIN, 0);
  2561. menu_list_pop_stack(menu_driver_ctx,
  2562. menu_userdata,
  2563. list, idx, &new_selection_ptr);
  2564. menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
  2565. menu_st->selection_ptr = new_selection_ptr;
  2566. menu_list = MENU_LIST_GET(list, (unsigned)idx);
  2567. if (menu_list && menu_list->size)
  2568. file_list_get_at_offset(menu_list, menu_list->size - 1, &path, &label, &type, &entry_idx);
  2569. }
  2570. }
  2571. /**
  2572. * menu_entries_elem_get_first_char:
  2573. * @list : File list handle.
  2574. * @offset : Offset index of element.
  2575. *
  2576. * Gets the first character of an element in the
  2577. * file list.
  2578. *
  2579. * Returns: first character of element in file list.
  2580. **/
  2581. static int menu_entries_elem_get_first_char(
  2582. file_list_t *list, unsigned offset)
  2583. {
  2584. const char *path = list->list[offset].alt
  2585. ? list->list[offset].alt
  2586. : list->list[offset].path;
  2587. int ret = path ? TOLOWER((int)*path) : 0;
  2588. /* "Normalize" non-alphabetical entries so they
  2589. * are lumped together for purposes of jumping. */
  2590. if (ret < 'a')
  2591. return ('a' - 1);
  2592. else if (ret > 'z')
  2593. return ('z' + 1);
  2594. return ret;
  2595. }
  2596. static void menu_entries_build_scroll_indices(
  2597. struct menu_state *menu_st,
  2598. file_list_t *list)
  2599. {
  2600. bool current_is_dir = false;
  2601. size_t i = 0;
  2602. int current = menu_entries_elem_get_first_char(list, 0);
  2603. unsigned type = list->list[0].type;
  2604. menu_st->scroll.index_list[0] = 0;
  2605. menu_st->scroll.index_size = 1;
  2606. if (type == FILE_TYPE_DIRECTORY)
  2607. current_is_dir = true;
  2608. for (i = 1; i < list->size; i++)
  2609. {
  2610. int first = menu_entries_elem_get_first_char(list, (unsigned)i);
  2611. bool is_dir = false;
  2612. unsigned idx = (unsigned)i;
  2613. type = list->list[idx].type;
  2614. if (type == FILE_TYPE_DIRECTORY)
  2615. is_dir = true;
  2616. if ((current_is_dir && !is_dir) || (first > current))
  2617. {
  2618. /* Add scroll index */
  2619. menu_st->scroll.index_list[menu_st->scroll.index_size] = i;
  2620. if (!((menu_st->scroll.index_size + 1) >= SCROLL_INDEX_SIZE))
  2621. menu_st->scroll.index_size++;
  2622. }
  2623. current = first;
  2624. current_is_dir = is_dir;
  2625. }
  2626. /* Add scroll index */
  2627. menu_st->scroll.index_list[menu_st->scroll.index_size] = list->size - 1;
  2628. if (!((menu_st->scroll.index_size + 1) >= SCROLL_INDEX_SIZE))
  2629. menu_st->scroll.index_size++;
  2630. }
  2631. menu_file_list_cbs_t *menu_entries_get_last_stack_actiondata(void)
  2632. {
  2633. struct rarch_state *p_rarch = &rarch_st;
  2634. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  2635. if (menu_st->entries.list)
  2636. {
  2637. const file_list_t *list = MENU_LIST_GET(menu_st->entries.list, 0);
  2638. return (menu_file_list_cbs_t*)list->list[list->size - 1].actiondata;
  2639. }
  2640. return NULL;
  2641. }
  2642. /* Sets title to what the name of the current menu should be. */
  2643. int menu_entries_get_title(char *s, size_t len)
  2644. {
  2645. unsigned menu_type = 0;
  2646. const char *path = NULL;
  2647. const char *label = NULL;
  2648. struct rarch_state *p_rarch = &rarch_st;
  2649. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  2650. const file_list_t *list = menu_st->entries.list ?
  2651. MENU_LIST_GET(menu_st->entries.list, 0) : NULL;
  2652. menu_file_list_cbs_t *cbs = list
  2653. ? (menu_file_list_cbs_t*)list->list[list->size - 1].actiondata
  2654. : NULL;
  2655. if (!cbs)
  2656. return -1;
  2657. if (cbs && cbs->action_get_title)
  2658. {
  2659. int ret;
  2660. if (!string_is_empty(cbs->action_title_cache))
  2661. {
  2662. strlcpy(s, cbs->action_title_cache, len);
  2663. return 0;
  2664. }
  2665. file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
  2666. &path, &label, &menu_type, NULL);
  2667. ret = cbs->action_get_title(path, label, menu_type, s, len);
  2668. if (ret == 1)
  2669. strlcpy(cbs->action_title_cache, s, sizeof(cbs->action_title_cache));
  2670. return ret;
  2671. }
  2672. return 0;
  2673. }
  2674. /* Sets 's' to the name of the current core
  2675. * (shown at the top of the UI). */
  2676. int menu_entries_get_core_title(char *s, size_t len)
  2677. {
  2678. struct rarch_state *p_rarch = &rarch_st;
  2679. struct retro_system_info *system = &p_rarch->runloop_system.info;
  2680. const char *core_name = (system && !string_is_empty(system->library_name))
  2681. ? system->library_name
  2682. : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE);
  2683. const char *core_version = (system && system->library_version) ? system->library_version : "";
  2684. #if _MSC_VER == 1200
  2685. strcpy_literal(s, PACKAGE_VERSION " msvc6" " - ");
  2686. #elif _MSC_VER == 1300
  2687. strcpy_literal(s, PACKAGE_VERSION " msvc2002" " - ");
  2688. #elif _MSC_VER == 1310
  2689. strcpy_literal(s, PACKAGE_VERSION " msvc2003" " - ");
  2690. #elif _MSC_VER == 1400
  2691. strcpy_literal(s, PACKAGE_VERSION " msvc2005" " - ");
  2692. #elif _MSC_VER == 1500
  2693. strcpy_literal(s, PACKAGE_VERSION " msvc2008" " - ");
  2694. #elif _MSC_VER == 1600
  2695. strcpy_literal(s, PACKAGE_VERSION " msvc2010" " - ");
  2696. #elif _MSC_VER == 1700
  2697. strcpy_literal(s, PACKAGE_VERSION " msvc2012" " - ");
  2698. #elif _MSC_VER == 1800
  2699. strcpy_literal(s, PACKAGE_VERSION " msvc2013" " - ");
  2700. #elif _MSC_VER == 1900
  2701. strcpy_literal(s, PACKAGE_VERSION " msvc2015" " - ");
  2702. #elif _MSC_VER >= 1910 && _MSC_VER < 1920
  2703. strcpy_literal(s, PACKAGE_VERSION " msvc2017" " - ");
  2704. #elif _MSC_VER >= 1920 && _MSC_VER < 2000
  2705. strcpy_literal(s, PACKAGE_VERSION " msvc2019" " - ");
  2706. #else
  2707. strcpy_literal(s, PACKAGE_VERSION " - ");
  2708. #endif
  2709. strlcat(s, core_name, len);
  2710. if (!string_is_empty(core_version))
  2711. {
  2712. strlcat(s, " (", len);
  2713. strlcat(s, core_version, len);
  2714. strlcat(s, ")", len);
  2715. }
  2716. return 0;
  2717. }
  2718. file_list_t *menu_entries_get_menu_stack_ptr(size_t idx)
  2719. {
  2720. struct rarch_state *p_rarch = &rarch_st;
  2721. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  2722. menu_list_t *menu_list = menu_st->entries.list;
  2723. if (!menu_list)
  2724. return NULL;
  2725. return MENU_LIST_GET(menu_list, (unsigned)idx);
  2726. }
  2727. file_list_t *menu_entries_get_selection_buf_ptr(size_t idx)
  2728. {
  2729. struct rarch_state *p_rarch = &rarch_st;
  2730. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  2731. menu_list_t *menu_list = menu_st->entries.list;
  2732. if (!menu_list)
  2733. return NULL;
  2734. return MENU_LIST_GET_SELECTION(menu_list, (unsigned)idx);
  2735. }
  2736. static void menu_entries_list_deinit(
  2737. const menu_ctx_driver_t *menu_driver_ctx,
  2738. struct menu_state *menu_st)
  2739. {
  2740. if (menu_st->entries.list)
  2741. menu_list_free(menu_driver_ctx, menu_st->entries.list);
  2742. menu_st->entries.list = NULL;
  2743. }
  2744. static void menu_entries_settings_deinit(struct menu_state *menu_st)
  2745. {
  2746. menu_setting_free(menu_st->entries.list_settings);
  2747. if (menu_st->entries.list_settings)
  2748. free(menu_st->entries.list_settings);
  2749. menu_st->entries.list_settings = NULL;
  2750. }
  2751. static bool menu_entries_init(
  2752. struct menu_state *menu_st,
  2753. const menu_ctx_driver_t *menu_driver_ctx
  2754. )
  2755. {
  2756. if (!(menu_st->entries.list = (menu_list_t*)menu_list_new(menu_driver_ctx)))
  2757. return false;
  2758. if (!(menu_st->entries.list_settings = menu_setting_new()))
  2759. return false;
  2760. return true;
  2761. }
  2762. void menu_entries_append(
  2763. file_list_t *list,
  2764. const char *path,
  2765. const char *label,
  2766. unsigned type,
  2767. size_t directory_ptr,
  2768. size_t entry_idx)
  2769. {
  2770. menu_ctx_list_t list_info;
  2771. size_t idx;
  2772. const char *menu_path = NULL;
  2773. menu_file_list_cbs_t *cbs = NULL;
  2774. struct rarch_state *p_rarch = &rarch_st;
  2775. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  2776. if (!list || !label)
  2777. return;
  2778. file_list_append(list, path, label, type, directory_ptr, entry_idx);
  2779. file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
  2780. &menu_path, NULL, NULL, NULL);
  2781. idx = list->size - 1;
  2782. list_info.list = list;
  2783. list_info.path = path;
  2784. list_info.fullpath = NULL;
  2785. if (!string_is_empty(menu_path))
  2786. list_info.fullpath = strdup(menu_path);
  2787. list_info.label = label;
  2788. list_info.idx = idx;
  2789. list_info.entry_type = type;
  2790. if ( p_rarch->menu_driver_ctx &&
  2791. p_rarch->menu_driver_ctx->list_insert)
  2792. p_rarch->menu_driver_ctx->list_insert(
  2793. p_rarch->menu_userdata,
  2794. list_info.list,
  2795. list_info.path,
  2796. list_info.fullpath,
  2797. list_info.label,
  2798. list_info.idx,
  2799. list_info.entry_type);
  2800. if (list_info.fullpath)
  2801. free(list_info.fullpath);
  2802. file_list_free_actiondata(list, idx);
  2803. cbs = (menu_file_list_cbs_t*)
  2804. malloc(sizeof(menu_file_list_cbs_t));
  2805. if (!cbs)
  2806. return;
  2807. cbs->action_sublabel_cache[0] = '\0';
  2808. cbs->action_title_cache[0] = '\0';
  2809. cbs->enum_idx = MSG_UNKNOWN;
  2810. cbs->checked = false;
  2811. cbs->setting = menu_setting_find(label);
  2812. cbs->action_iterate = NULL;
  2813. cbs->action_deferred_push = NULL;
  2814. cbs->action_select = NULL;
  2815. cbs->action_get_title = NULL;
  2816. cbs->action_ok = NULL;
  2817. cbs->action_cancel = NULL;
  2818. cbs->action_scan = NULL;
  2819. cbs->action_start = NULL;
  2820. cbs->action_info = NULL;
  2821. cbs->action_left = NULL;
  2822. cbs->action_right = NULL;
  2823. cbs->action_label = NULL;
  2824. cbs->action_sublabel = NULL;
  2825. cbs->action_get_value = NULL;
  2826. list->list[idx].actiondata = cbs;
  2827. menu_cbs_init(&p_rarch->menu_driver_state,
  2828. p_rarch->menu_driver_ctx,
  2829. list, cbs, path, label, type, idx);
  2830. }
  2831. bool menu_entries_append_enum(
  2832. file_list_t *list,
  2833. const char *path,
  2834. const char *label,
  2835. enum msg_hash_enums enum_idx,
  2836. unsigned type,
  2837. size_t directory_ptr,
  2838. size_t entry_idx)
  2839. {
  2840. menu_ctx_list_t list_info;
  2841. size_t idx;
  2842. const char *menu_path = NULL;
  2843. menu_file_list_cbs_t *cbs = NULL;
  2844. struct rarch_state *p_rarch = &rarch_st;
  2845. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  2846. if (!list || !label)
  2847. return false;
  2848. file_list_append(list, path, label, type, directory_ptr, entry_idx);
  2849. file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
  2850. &menu_path, NULL, NULL, NULL);
  2851. idx = list->size - 1;
  2852. list_info.fullpath = NULL;
  2853. if (!string_is_empty(menu_path))
  2854. list_info.fullpath = strdup(menu_path);
  2855. list_info.list = list;
  2856. list_info.path = path;
  2857. list_info.label = label;
  2858. list_info.idx = idx;
  2859. list_info.entry_type = type;
  2860. if ( p_rarch->menu_driver_ctx &&
  2861. p_rarch->menu_driver_ctx->list_insert)
  2862. p_rarch->menu_driver_ctx->list_insert(
  2863. p_rarch->menu_userdata,
  2864. list_info.list,
  2865. list_info.path,
  2866. list_info.fullpath,
  2867. list_info.label,
  2868. list_info.idx,
  2869. list_info.entry_type);
  2870. if (list_info.fullpath)
  2871. free(list_info.fullpath);
  2872. file_list_free_actiondata(list, idx);
  2873. cbs = (menu_file_list_cbs_t*)
  2874. malloc(sizeof(menu_file_list_cbs_t));
  2875. if (!cbs)
  2876. return false;
  2877. cbs->action_sublabel_cache[0] = '\0';
  2878. cbs->action_title_cache[0] = '\0';
  2879. cbs->enum_idx = enum_idx;
  2880. cbs->checked = false;
  2881. cbs->setting = NULL;
  2882. cbs->action_iterate = NULL;
  2883. cbs->action_deferred_push = NULL;
  2884. cbs->action_select = NULL;
  2885. cbs->action_get_title = NULL;
  2886. cbs->action_ok = NULL;
  2887. cbs->action_cancel = NULL;
  2888. cbs->action_scan = NULL;
  2889. cbs->action_start = NULL;
  2890. cbs->action_info = NULL;
  2891. cbs->action_left = NULL;
  2892. cbs->action_right = NULL;
  2893. cbs->action_label = NULL;
  2894. cbs->action_sublabel = NULL;
  2895. cbs->action_get_value = NULL;
  2896. list->list[idx].actiondata = cbs;
  2897. if ( enum_idx != MENU_ENUM_LABEL_PLAYLIST_ENTRY
  2898. && enum_idx != MENU_ENUM_LABEL_PLAYLIST_COLLECTION_ENTRY
  2899. && enum_idx != MENU_ENUM_LABEL_EXPLORE_ITEM
  2900. && enum_idx != MENU_ENUM_LABEL_RDB_ENTRY)
  2901. cbs->setting = menu_setting_find_enum(enum_idx);
  2902. menu_cbs_init(&p_rarch->menu_driver_state,
  2903. p_rarch->menu_driver_ctx,
  2904. list, cbs, path, label, type, idx);
  2905. return true;
  2906. }
  2907. void menu_entries_prepend(file_list_t *list,
  2908. const char *path, const char *label,
  2909. enum msg_hash_enums enum_idx,
  2910. unsigned type, size_t directory_ptr, size_t entry_idx)
  2911. {
  2912. menu_ctx_list_t list_info;
  2913. size_t idx = 0;
  2914. const char *menu_path = NULL;
  2915. menu_file_list_cbs_t *cbs = NULL;
  2916. struct rarch_state *p_rarch = &rarch_st;
  2917. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  2918. if (!list || !label)
  2919. return;
  2920. file_list_prepend(list, path, label, type, directory_ptr, entry_idx);
  2921. file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
  2922. &menu_path, NULL, NULL, NULL);
  2923. list_info.fullpath = NULL;
  2924. if (!string_is_empty(menu_path))
  2925. list_info.fullpath = strdup(menu_path);
  2926. list_info.list = list;
  2927. list_info.path = path;
  2928. list_info.label = label;
  2929. list_info.idx = idx;
  2930. list_info.entry_type = type;
  2931. if ( p_rarch->menu_driver_ctx &&
  2932. p_rarch->menu_driver_ctx->list_insert)
  2933. p_rarch->menu_driver_ctx->list_insert(
  2934. p_rarch->menu_userdata,
  2935. list_info.list,
  2936. list_info.path,
  2937. list_info.fullpath,
  2938. list_info.label,
  2939. list_info.idx,
  2940. list_info.entry_type);
  2941. if (list_info.fullpath)
  2942. free(list_info.fullpath);
  2943. file_list_free_actiondata(list, idx);
  2944. cbs = (menu_file_list_cbs_t*)
  2945. malloc(sizeof(menu_file_list_cbs_t));
  2946. if (!cbs)
  2947. return;
  2948. cbs->action_sublabel_cache[0] = '\0';
  2949. cbs->action_title_cache[0] = '\0';
  2950. cbs->enum_idx = enum_idx;
  2951. cbs->checked = false;
  2952. cbs->setting = menu_setting_find_enum(cbs->enum_idx);
  2953. cbs->action_iterate = NULL;
  2954. cbs->action_deferred_push = NULL;
  2955. cbs->action_select = NULL;
  2956. cbs->action_get_title = NULL;
  2957. cbs->action_ok = NULL;
  2958. cbs->action_cancel = NULL;
  2959. cbs->action_scan = NULL;
  2960. cbs->action_start = NULL;
  2961. cbs->action_info = NULL;
  2962. cbs->action_left = NULL;
  2963. cbs->action_right = NULL;
  2964. cbs->action_label = NULL;
  2965. cbs->action_sublabel = NULL;
  2966. cbs->action_get_value = NULL;
  2967. list->list[idx].actiondata = cbs;
  2968. menu_cbs_init(&p_rarch->menu_driver_state,
  2969. p_rarch->menu_driver_ctx,
  2970. list, cbs, path, label, type, idx);
  2971. }
  2972. void menu_entries_get_last_stack(const char **path, const char **label,
  2973. unsigned *file_type, enum msg_hash_enums *enum_idx, size_t *entry_idx)
  2974. {
  2975. file_list_t *list = NULL;
  2976. struct rarch_state *p_rarch = &rarch_st;
  2977. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  2978. if (!menu_st->entries.list)
  2979. return;
  2980. list = MENU_LIST_GET(menu_st->entries.list, 0);
  2981. if (list && list->size)
  2982. file_list_get_at_offset(list, list->size - 1, path, label, file_type, entry_idx);
  2983. if (enum_idx)
  2984. {
  2985. menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)
  2986. list->list[list->size - 1].actiondata;
  2987. if (cbs)
  2988. *enum_idx = cbs->enum_idx;
  2989. }
  2990. }
  2991. void menu_entries_flush_stack(const char *needle, unsigned final_type)
  2992. {
  2993. struct rarch_state *p_rarch = &rarch_st;
  2994. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  2995. menu_list_t *menu_list = menu_st->entries.list;
  2996. if (menu_list)
  2997. menu_list_flush_stack(
  2998. p_rarch->menu_driver_ctx,
  2999. p_rarch->menu_userdata,
  3000. menu_st,
  3001. menu_list, 0, needle, final_type);
  3002. }
  3003. void menu_entries_pop_stack(size_t *ptr, size_t idx, bool animate)
  3004. {
  3005. struct rarch_state *p_rarch = &rarch_st;
  3006. const menu_ctx_driver_t *menu_driver_ctx = p_rarch->menu_driver_ctx;
  3007. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  3008. menu_list_t *menu_list = menu_st->entries.list;
  3009. if (!menu_list)
  3010. return;
  3011. if (MENU_LIST_GET_STACK_SIZE(menu_list, idx) > 1)
  3012. {
  3013. bool refresh = false;
  3014. if (animate)
  3015. {
  3016. if (menu_driver_ctx->list_cache)
  3017. menu_driver_ctx->list_cache(p_rarch->menu_userdata,
  3018. MENU_LIST_PLAIN, 0);
  3019. }
  3020. menu_list_pop_stack(menu_driver_ctx,
  3021. p_rarch->menu_userdata, menu_list, idx, ptr);
  3022. if (animate)
  3023. menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
  3024. }
  3025. }
  3026. size_t menu_entries_get_stack_size(size_t idx)
  3027. {
  3028. struct rarch_state *p_rarch = &rarch_st;
  3029. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  3030. menu_list_t *menu_list = menu_st->entries.list;
  3031. if (!menu_list)
  3032. return 0;
  3033. return MENU_LIST_GET_STACK_SIZE(menu_list, idx);
  3034. }
  3035. size_t menu_entries_get_size(void)
  3036. {
  3037. struct rarch_state *p_rarch = &rarch_st;
  3038. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  3039. menu_list_t *menu_list = menu_st->entries.list;
  3040. if (!menu_list)
  3041. return 0;
  3042. return MENU_LIST_GET_SELECTION(menu_list, 0)->size;
  3043. }
  3044. bool menu_entries_ctl(enum menu_entries_ctl_state state, void *data)
  3045. {
  3046. struct rarch_state *p_rarch = &rarch_st;
  3047. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  3048. switch (state)
  3049. {
  3050. case MENU_ENTRIES_CTL_NEEDS_REFRESH:
  3051. return MENU_ENTRIES_NEEDS_REFRESH(menu_st);
  3052. case MENU_ENTRIES_CTL_SETTINGS_GET:
  3053. {
  3054. rarch_setting_t **settings = (rarch_setting_t**)data;
  3055. if (!settings)
  3056. return false;
  3057. *settings = menu_st->entries.list_settings;
  3058. }
  3059. break;
  3060. case MENU_ENTRIES_CTL_SET_REFRESH:
  3061. {
  3062. bool *nonblocking = (bool*)data;
  3063. if (*nonblocking)
  3064. menu_st->entries_nonblocking_refresh = true;
  3065. else
  3066. menu_st->entries_need_refresh = true;
  3067. }
  3068. break;
  3069. case MENU_ENTRIES_CTL_UNSET_REFRESH:
  3070. {
  3071. bool *nonblocking = (bool*)data;
  3072. if (*nonblocking)
  3073. menu_st->entries_nonblocking_refresh = false;
  3074. else
  3075. menu_st->entries_need_refresh = false;
  3076. }
  3077. break;
  3078. case MENU_ENTRIES_CTL_SET_START:
  3079. {
  3080. size_t *idx = (size_t*)data;
  3081. if (idx)
  3082. menu_st->entries.begin = *idx;
  3083. }
  3084. case MENU_ENTRIES_CTL_START_GET:
  3085. {
  3086. size_t *idx = (size_t*)data;
  3087. if (!idx)
  3088. return 0;
  3089. *idx = menu_st->entries.begin;
  3090. }
  3091. break;
  3092. case MENU_ENTRIES_CTL_REFRESH:
  3093. /**
  3094. * Before a refresh, we could have deleted a
  3095. * file on disk, causing selection_ptr to
  3096. * suddendly be out of range.
  3097. *
  3098. * Ensure it doesn't overflow.
  3099. **/
  3100. {
  3101. size_t list_size;
  3102. file_list_t *list = (file_list_t*)data;
  3103. if (!list)
  3104. return false;
  3105. if (list->size)
  3106. menu_entries_build_scroll_indices(menu_st, list);
  3107. list_size = menu_st->entries.list ? MENU_LIST_GET_SELECTION(menu_st->entries.list, 0)->size : 0;
  3108. if (list_size)
  3109. {
  3110. size_t selection = menu_st->selection_ptr;
  3111. if (selection >= list_size)
  3112. {
  3113. size_t idx = list_size - 1;
  3114. menu_st->selection_ptr = idx;
  3115. menu_driver_navigation_set(true);
  3116. }
  3117. }
  3118. else
  3119. {
  3120. bool pending_push = true;
  3121. menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
  3122. }
  3123. }
  3124. break;
  3125. case MENU_ENTRIES_CTL_CLEAR:
  3126. {
  3127. unsigned i;
  3128. file_list_t *list = (file_list_t*)data;
  3129. if (!list)
  3130. return false;
  3131. /* Clear all the menu lists. */
  3132. if (p_rarch->menu_driver_ctx->list_clear)
  3133. p_rarch->menu_driver_ctx->list_clear(list);
  3134. for (i = 0; i < list->size; i++)
  3135. {
  3136. if (list->list[i].actiondata)
  3137. free(list->list[i].actiondata);
  3138. list->list[i].actiondata = NULL;
  3139. }
  3140. file_list_clear(list);
  3141. }
  3142. break;
  3143. case MENU_ENTRIES_CTL_SHOW_BACK:
  3144. /* Returns true if a Back button should be shown
  3145. * (i.e. we are at least
  3146. * one level deep in the menu hierarchy). */
  3147. if (!menu_st->entries.list)
  3148. return false;
  3149. return (MENU_LIST_GET_STACK_SIZE(menu_st->entries.list, 0) > 1);
  3150. case MENU_ENTRIES_CTL_NONE:
  3151. default:
  3152. break;
  3153. }
  3154. return true;
  3155. }
  3156. static void menu_display_common_image_upload(
  3157. const menu_ctx_driver_t *menu_driver_ctx,
  3158. void *menu_userdata,
  3159. struct texture_image *img,
  3160. void *user_data,
  3161. unsigned type)
  3162. {
  3163. if ( menu_driver_ctx
  3164. && menu_driver_ctx->load_image)
  3165. menu_driver_ctx->load_image(menu_userdata,
  3166. img, (enum menu_image_type)type);
  3167. image_texture_free(img);
  3168. free(img);
  3169. free(user_data);
  3170. }
  3171. /* TODO/FIXME - seems only RGUI uses this - can this be
  3172. * refactored away or we can have one common function used
  3173. * across all menu drivers? */
  3174. #ifdef HAVE_RGUI
  3175. void menu_display_handle_thumbnail_upload(
  3176. retro_task_t *task,
  3177. void *task_data,
  3178. void *user_data, const char *err)
  3179. {
  3180. struct rarch_state *p_rarch = &rarch_st;
  3181. menu_display_common_image_upload(
  3182. p_rarch->menu_driver_ctx,
  3183. p_rarch->menu_userdata,
  3184. (struct texture_image*)task_data,
  3185. user_data,
  3186. MENU_IMAGE_THUMBNAIL);
  3187. }
  3188. void menu_display_handle_left_thumbnail_upload(
  3189. retro_task_t *task,
  3190. void *task_data,
  3191. void *user_data, const char *err)
  3192. {
  3193. struct rarch_state *p_rarch = &rarch_st;
  3194. menu_display_common_image_upload(
  3195. p_rarch->menu_driver_ctx,
  3196. p_rarch->menu_userdata,
  3197. (struct texture_image*)task_data,
  3198. user_data,
  3199. MENU_IMAGE_LEFT_THUMBNAIL);
  3200. }
  3201. #endif
  3202. void menu_display_handle_savestate_thumbnail_upload(
  3203. retro_task_t *task,
  3204. void *task_data,
  3205. void *user_data, const char *err)
  3206. {
  3207. struct rarch_state *p_rarch = &rarch_st;
  3208. menu_display_common_image_upload(
  3209. p_rarch->menu_driver_ctx,
  3210. p_rarch->menu_userdata,
  3211. (struct texture_image*)task_data,
  3212. user_data,
  3213. MENU_IMAGE_SAVESTATE_THUMBNAIL);
  3214. }
  3215. /* Function that gets called when we want to load in a
  3216. * new menu wallpaper.
  3217. */
  3218. void menu_display_handle_wallpaper_upload(
  3219. retro_task_t *task,
  3220. void *task_data,
  3221. void *user_data, const char *err)
  3222. {
  3223. struct rarch_state *p_rarch = &rarch_st;
  3224. menu_display_common_image_upload(
  3225. p_rarch->menu_driver_ctx,
  3226. p_rarch->menu_userdata,
  3227. (struct texture_image*)task_data,
  3228. user_data,
  3229. MENU_IMAGE_WALLPAPER);
  3230. }
  3231. /**
  3232. * config_get_menu_driver_options:
  3233. *
  3234. * Get an enumerated list of all menu driver names,
  3235. * separated by '|'.
  3236. *
  3237. * Returns: string listing of all menu driver names,
  3238. * separated by '|'.
  3239. **/
  3240. const char *config_get_menu_driver_options(void)
  3241. {
  3242. return char_list_new_special(STRING_LIST_MENU_DRIVERS, NULL);
  3243. }
  3244. #ifdef HAVE_COMPRESSION
  3245. /* This function gets called at first startup on Android/iOS
  3246. * when we need to extract the APK contents/zip file. This
  3247. * file contains assets which then get extracted to the
  3248. * user's asset directories. */
  3249. static void bundle_decompressed(retro_task_t *task,
  3250. void *task_data,
  3251. void *user_data, const char *err)
  3252. {
  3253. struct rarch_state *p_rarch = &rarch_st;
  3254. settings_t *settings = p_rarch->configuration_settings;
  3255. decompress_task_data_t *dec = (decompress_task_data_t*)task_data;
  3256. if (err)
  3257. RARCH_ERR("%s", err);
  3258. if (dec)
  3259. {
  3260. if (!err)
  3261. command_event(CMD_EVENT_REINIT, NULL);
  3262. /* delete bundle? */
  3263. free(dec->source_file);
  3264. free(dec);
  3265. }
  3266. configuration_set_uint(settings,
  3267. settings->uints.bundle_assets_extract_last_version,
  3268. settings->uints.bundle_assets_extract_version_current);
  3269. configuration_set_bool(settings, settings->bools.bundle_finished, true);
  3270. command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
  3271. }
  3272. #endif
  3273. /**
  3274. * menu_init:
  3275. * @data : Menu context handle.
  3276. *
  3277. * Create and initialize menu handle.
  3278. *
  3279. * Returns: menu handle on success, otherwise NULL.
  3280. **/
  3281. static bool menu_init(
  3282. struct menu_state *menu_st,
  3283. menu_dialog_t *p_dialog,
  3284. const menu_ctx_driver_t *menu_driver_ctx,
  3285. menu_input_t *menu_input,
  3286. menu_input_pointer_hw_state_t *pointer_hw_state,
  3287. settings_t *settings
  3288. )
  3289. {
  3290. #ifdef HAVE_CONFIGFILE
  3291. bool menu_show_start_screen = settings->bools.menu_show_start_screen;
  3292. bool config_save_on_exit = settings->bools.config_save_on_exit;
  3293. #endif
  3294. /* Ensure that menu pointer input is correctly
  3295. * initialised */
  3296. menu_input_reset(menu_input, pointer_hw_state);
  3297. if (!menu_entries_init(menu_st, menu_driver_ctx))
  3298. {
  3299. menu_entries_settings_deinit(menu_st);
  3300. menu_entries_list_deinit(menu_driver_ctx, menu_st);
  3301. return false;
  3302. }
  3303. #ifdef HAVE_CONFIGFILE
  3304. if (menu_show_start_screen)
  3305. {
  3306. /* We don't want the welcome dialog screen to show up
  3307. * again after the first startup, so we save to config
  3308. * file immediately. */
  3309. p_dialog->current_type = MENU_DIALOG_WELCOME;
  3310. configuration_set_bool(settings,
  3311. settings->bools.menu_show_start_screen, false);
  3312. if (config_save_on_exit)
  3313. command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
  3314. }
  3315. #endif
  3316. #ifdef HAVE_COMPRESSION
  3317. if ( settings->bools.bundle_assets_extract_enable
  3318. && !string_is_empty(settings->arrays.bundle_assets_src)
  3319. && !string_is_empty(settings->arrays.bundle_assets_dst)
  3320. && (settings->uints.bundle_assets_extract_version_current
  3321. != settings->uints.bundle_assets_extract_last_version)
  3322. )
  3323. {
  3324. p_dialog->current_type = MENU_DIALOG_HELP_EXTRACT;
  3325. task_push_decompress(
  3326. settings->arrays.bundle_assets_src,
  3327. settings->arrays.bundle_assets_dst,
  3328. NULL,
  3329. settings->arrays.bundle_assets_dst_subdir,
  3330. NULL,
  3331. bundle_decompressed,
  3332. NULL,
  3333. NULL,
  3334. false);
  3335. /* Support only 1 version - setting this would prevent the assets from being extracted every time */
  3336. configuration_set_int(settings,
  3337. settings->uints.bundle_assets_extract_last_version, 1);
  3338. }
  3339. #endif
  3340. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  3341. menu_shader_manager_init();
  3342. #endif
  3343. return true;
  3344. }
  3345. const char *menu_driver_ident(void)
  3346. {
  3347. struct rarch_state *p_rarch = &rarch_st;
  3348. if (p_rarch->menu_driver_alive)
  3349. if (p_rarch->menu_driver_ctx && p_rarch->menu_driver_ctx->ident)
  3350. return p_rarch->menu_driver_ctx->ident;
  3351. return NULL;
  3352. }
  3353. void menu_driver_frame(bool menu_is_alive, video_frame_info_t *video_info)
  3354. {
  3355. struct rarch_state *p_rarch = &rarch_st;
  3356. if (menu_is_alive && p_rarch->menu_driver_ctx->frame)
  3357. p_rarch->menu_driver_ctx->frame(p_rarch->menu_userdata, video_info);
  3358. }
  3359. /* Time format strings with AM-PM designation require special
  3360. * handling due to platform dependence */
  3361. static void strftime_am_pm(char* ptr, size_t maxsize, const char* format,
  3362. const struct tm* timeptr)
  3363. {
  3364. char *local = NULL;
  3365. /* Ensure correct locale is set
  3366. * > Required for localised AM/PM strings */
  3367. setlocale(LC_TIME, "");
  3368. strftime(ptr, maxsize, format, timeptr);
  3369. #if !(defined(__linux__) && !defined(ANDROID))
  3370. local = local_to_utf8_string_alloc(ptr);
  3371. if (!string_is_empty(local))
  3372. strlcpy(ptr, local, maxsize);
  3373. if (local)
  3374. {
  3375. free(local);
  3376. local = NULL;
  3377. }
  3378. #endif
  3379. }
  3380. /* Display the date and time - time_mode will influence how
  3381. * the time representation will look like.
  3382. * */
  3383. void menu_display_timedate(gfx_display_ctx_datetime_t *datetime)
  3384. {
  3385. struct rarch_state *p_rarch = &rarch_st;
  3386. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  3387. if (!datetime)
  3388. return;
  3389. /* Trigger an update, if required */
  3390. if (menu_st->current_time_us - menu_st->datetime_last_time_us >=
  3391. DATETIME_CHECK_INTERVAL)
  3392. {
  3393. time_t time_;
  3394. struct tm tm_;
  3395. bool has_am_pm = false;
  3396. const char *format_str = "";
  3397. menu_st->datetime_last_time_us = menu_st->current_time_us;
  3398. /* Get current time */
  3399. time(&time_);
  3400. rtime_localtime(&time_, &tm_);
  3401. /* Format string representation */
  3402. switch (datetime->time_mode)
  3403. {
  3404. case MENU_TIMEDATE_STYLE_YMD_HMS: /* YYYY-MM-DD HH:MM:SS */
  3405. /* Using switch statements to set the format
  3406. * string is verbose, but has far less performance
  3407. * impact than setting the date separator dynamically
  3408. * (i.e. no snprintf() or character replacement...) */
  3409. switch (datetime->date_separator)
  3410. {
  3411. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3412. format_str = "%Y/%m/%d %H:%M:%S";
  3413. break;
  3414. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3415. format_str = "%Y.%m.%d %H:%M:%S";
  3416. break;
  3417. default:
  3418. format_str = "%Y-%m-%d %H:%M:%S";
  3419. break;
  3420. }
  3421. break;
  3422. case MENU_TIMEDATE_STYLE_YMD_HM: /* YYYY-MM-DD HH:MM */
  3423. switch (datetime->date_separator)
  3424. {
  3425. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3426. format_str = "%Y/%m/%d %H:%M";
  3427. break;
  3428. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3429. format_str = "%Y.%m.%d %H:%M";
  3430. break;
  3431. default:
  3432. format_str = "%Y-%m-%d %H:%M";
  3433. break;
  3434. }
  3435. break;
  3436. case MENU_TIMEDATE_STYLE_YMD: /* YYYY-MM-DD */
  3437. switch (datetime->date_separator)
  3438. {
  3439. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3440. format_str = "%Y/%m/%d";
  3441. break;
  3442. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3443. format_str = "%Y.%m.%d";
  3444. break;
  3445. default:
  3446. format_str = "%Y-%m-%d";
  3447. break;
  3448. }
  3449. break;
  3450. case MENU_TIMEDATE_STYLE_YM: /* YYYY-MM */
  3451. switch (datetime->date_separator)
  3452. {
  3453. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3454. format_str = "%Y/%m";
  3455. break;
  3456. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3457. format_str = "%Y.%m";
  3458. break;
  3459. default:
  3460. format_str = "%Y-%m";
  3461. break;
  3462. }
  3463. break;
  3464. case MENU_TIMEDATE_STYLE_MDYYYY_HMS: /* MM-DD-YYYY HH:MM:SS */
  3465. switch (datetime->date_separator)
  3466. {
  3467. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3468. format_str = "%m/%d/%Y %H:%M:%S";
  3469. break;
  3470. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3471. format_str = "%m.%d.%Y %H:%M:%S";
  3472. break;
  3473. default:
  3474. format_str = "%m-%d-%Y %H:%M:%S";
  3475. break;
  3476. }
  3477. break;
  3478. case MENU_TIMEDATE_STYLE_MDYYYY_HM: /* MM-DD-YYYY HH:MM */
  3479. switch (datetime->date_separator)
  3480. {
  3481. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3482. format_str = "%m/%d/%Y %H:%M";
  3483. break;
  3484. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3485. format_str = "%m.%d.%Y %H:%M";
  3486. break;
  3487. default:
  3488. format_str = "%m-%d-%Y %H:%M";
  3489. break;
  3490. }
  3491. break;
  3492. case MENU_TIMEDATE_STYLE_MD_HM: /* MM-DD HH:MM */
  3493. switch (datetime->date_separator)
  3494. {
  3495. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3496. format_str = "%m/%d %H:%M";
  3497. break;
  3498. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3499. format_str = "%m.%d %H:%M";
  3500. break;
  3501. default:
  3502. format_str = "%m-%d %H:%M";
  3503. break;
  3504. }
  3505. break;
  3506. case MENU_TIMEDATE_STYLE_MDYYYY: /* MM-DD-YYYY */
  3507. switch (datetime->date_separator)
  3508. {
  3509. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3510. format_str = "%m/%d/%Y";
  3511. break;
  3512. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3513. format_str = "%m.%d.%Y";
  3514. break;
  3515. default:
  3516. format_str = "%m-%d-%Y";
  3517. break;
  3518. }
  3519. break;
  3520. case MENU_TIMEDATE_STYLE_MD: /* MM-DD */
  3521. switch (datetime->date_separator)
  3522. {
  3523. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3524. format_str = "%m/%d";
  3525. break;
  3526. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3527. format_str = "%m.%d";
  3528. break;
  3529. default:
  3530. format_str = "%m-%d";
  3531. break;
  3532. }
  3533. break;
  3534. case MENU_TIMEDATE_STYLE_DDMMYYYY_HMS: /* DD-MM-YYYY HH:MM:SS */
  3535. switch (datetime->date_separator)
  3536. {
  3537. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3538. format_str = "%d/%m/%Y %H:%M:%S";
  3539. break;
  3540. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3541. format_str = "%d.%m.%Y %H:%M:%S";
  3542. break;
  3543. default:
  3544. format_str = "%d-%m-%Y %H:%M:%S";
  3545. break;
  3546. }
  3547. break;
  3548. case MENU_TIMEDATE_STYLE_DDMMYYYY_HM: /* DD-MM-YYYY HH:MM */
  3549. switch (datetime->date_separator)
  3550. {
  3551. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3552. format_str = "%d/%m/%Y %H:%M";
  3553. break;
  3554. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3555. format_str = "%d.%m.%Y %H:%M";
  3556. break;
  3557. default:
  3558. format_str = "%d-%m-%Y %H:%M";
  3559. break;
  3560. }
  3561. break;
  3562. case MENU_TIMEDATE_STYLE_DDMM_HM: /* DD-MM HH:MM */
  3563. switch (datetime->date_separator)
  3564. {
  3565. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3566. format_str = "%d/%m %H:%M";
  3567. break;
  3568. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3569. format_str = "%d.%m %H:%M";
  3570. break;
  3571. default:
  3572. format_str = "%d-%m %H:%M";
  3573. break;
  3574. }
  3575. break;
  3576. case MENU_TIMEDATE_STYLE_DDMMYYYY: /* DD-MM-YYYY */
  3577. switch (datetime->date_separator)
  3578. {
  3579. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3580. format_str = "%d/%m/%Y";
  3581. break;
  3582. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3583. format_str = "%d.%m.%Y";
  3584. break;
  3585. default:
  3586. format_str = "%d-%m-%Y";
  3587. break;
  3588. }
  3589. break;
  3590. case MENU_TIMEDATE_STYLE_DDMM: /* DD-MM */
  3591. switch (datetime->date_separator)
  3592. {
  3593. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3594. format_str = "%d/%m";
  3595. break;
  3596. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3597. format_str = "%d.%m";
  3598. break;
  3599. default:
  3600. format_str = "%d-%m";
  3601. break;
  3602. }
  3603. break;
  3604. case MENU_TIMEDATE_STYLE_HMS: /* HH:MM:SS */
  3605. format_str = "%H:%M:%S";
  3606. break;
  3607. case MENU_TIMEDATE_STYLE_HM: /* HH:MM */
  3608. format_str = "%H:%M";
  3609. break;
  3610. case MENU_TIMEDATE_STYLE_YMD_HMS_AMPM: /* YYYY-MM-DD HH:MM:SS (AM/PM) */
  3611. has_am_pm = true;
  3612. switch (datetime->date_separator)
  3613. {
  3614. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3615. format_str = "%Y/%m/%d %I:%M:%S %p";
  3616. break;
  3617. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3618. format_str = "%Y.%m.%d %I:%M:%S %p";
  3619. break;
  3620. default:
  3621. format_str = "%Y-%m-%d %I:%M:%S %p";
  3622. break;
  3623. }
  3624. break;
  3625. case MENU_TIMEDATE_STYLE_YMD_HM_AMPM: /* YYYY-MM-DD HH:MM (AM/PM) */
  3626. has_am_pm = true;
  3627. switch (datetime->date_separator)
  3628. {
  3629. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3630. format_str = "%Y/%m/%d %I:%M %p";
  3631. break;
  3632. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3633. format_str = "%Y.%m.%d %I:%M %p";
  3634. break;
  3635. default:
  3636. format_str = "%Y-%m-%d %I:%M %p";
  3637. break;
  3638. }
  3639. break;
  3640. case MENU_TIMEDATE_STYLE_MDYYYY_HMS_AMPM: /* MM-DD-YYYY HH:MM:SS (AM/PM) */
  3641. has_am_pm = true;
  3642. switch (datetime->date_separator)
  3643. {
  3644. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3645. format_str = "%m/%d/%Y %I:%M:%S %p";
  3646. break;
  3647. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3648. format_str = "%m.%d.%Y %I:%M:%S %p";
  3649. break;
  3650. default:
  3651. format_str = "%m-%d-%Y %I:%M:%S %p";
  3652. break;
  3653. }
  3654. break;
  3655. case MENU_TIMEDATE_STYLE_MDYYYY_HM_AMPM: /* MM-DD-YYYY HH:MM (AM/PM) */
  3656. has_am_pm = true;
  3657. switch (datetime->date_separator)
  3658. {
  3659. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3660. format_str = "%m/%d/%Y %I:%M %p";
  3661. break;
  3662. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3663. format_str = "%m.%d.%Y %I:%M %p";
  3664. break;
  3665. default:
  3666. format_str = "%m-%d-%Y %I:%M %p";
  3667. break;
  3668. }
  3669. break;
  3670. case MENU_TIMEDATE_STYLE_MD_HM_AMPM: /* MM-DD HH:MM (AM/PM) */
  3671. has_am_pm = true;
  3672. switch (datetime->date_separator)
  3673. {
  3674. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3675. format_str = "%m/%d %I:%M %p";
  3676. break;
  3677. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3678. format_str = "%m.%d %I:%M %p";
  3679. break;
  3680. default:
  3681. format_str = "%m-%d %I:%M %p";
  3682. break;
  3683. }
  3684. break;
  3685. case MENU_TIMEDATE_STYLE_DDMMYYYY_HMS_AMPM: /* DD-MM-YYYY HH:MM:SS (AM/PM) */
  3686. has_am_pm = true;
  3687. switch (datetime->date_separator)
  3688. {
  3689. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3690. format_str = "%d/%m/%Y %I:%M:%S %p";
  3691. break;
  3692. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3693. format_str = "%d.%m.%Y %I:%M:%S %p";
  3694. break;
  3695. default:
  3696. format_str = "%d-%m-%Y %I:%M:%S %p";
  3697. break;
  3698. }
  3699. break;
  3700. case MENU_TIMEDATE_STYLE_DDMMYYYY_HM_AMPM: /* DD-MM-YYYY HH:MM (AM/PM) */
  3701. has_am_pm = true;
  3702. switch (datetime->date_separator)
  3703. {
  3704. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3705. format_str = "%d/%m/%Y %I:%M %p";
  3706. break;
  3707. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3708. format_str = "%d.%m.%Y %I:%M %p";
  3709. break;
  3710. default:
  3711. format_str = "%d-%m-%Y %I:%M %p";
  3712. break;
  3713. }
  3714. break;
  3715. case MENU_TIMEDATE_STYLE_DDMM_HM_AMPM: /* DD-MM HH:MM (AM/PM) */
  3716. has_am_pm = true;
  3717. switch (datetime->date_separator)
  3718. {
  3719. case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
  3720. format_str = "%d/%m %I:%M %p";
  3721. break;
  3722. case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
  3723. format_str = "%d.%m %I:%M %p";
  3724. break;
  3725. default:
  3726. format_str = "%d-%m %I:%M %p";
  3727. break;
  3728. }
  3729. break;
  3730. case MENU_TIMEDATE_STYLE_HMS_AMPM: /* HH:MM:SS (AM/PM) */
  3731. has_am_pm = true;
  3732. format_str = "%I:%M:%S %p";
  3733. break;
  3734. case MENU_TIMEDATE_STYLE_HM_AMPM: /* HH:MM (AM/PM) */
  3735. has_am_pm = true;
  3736. format_str = "%I:%M %p";
  3737. break;
  3738. }
  3739. if (has_am_pm)
  3740. strftime_am_pm(menu_st->datetime_cache, sizeof(menu_st->datetime_cache),
  3741. format_str, &tm_);
  3742. else
  3743. strftime(menu_st->datetime_cache, sizeof(menu_st->datetime_cache),
  3744. format_str, &tm_);
  3745. }
  3746. /* Copy cached datetime string to input
  3747. * menu_display_ctx_datetime_t struct */
  3748. strlcpy(datetime->s, menu_st->datetime_cache, datetime->len);
  3749. }
  3750. /* Display current (battery) power state */
  3751. void menu_display_powerstate(gfx_display_ctx_powerstate_t *powerstate)
  3752. {
  3753. int percent = 0;
  3754. struct rarch_state *p_rarch = &rarch_st;
  3755. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  3756. enum frontend_powerstate state = FRONTEND_POWERSTATE_NONE;
  3757. if (!powerstate)
  3758. return;
  3759. /* Trigger an update, if required */
  3760. if (menu_st->current_time_us - menu_st->powerstate_last_time_us >=
  3761. POWERSTATE_CHECK_INTERVAL)
  3762. {
  3763. menu_st->powerstate_last_time_us = menu_st->current_time_us;
  3764. task_push_get_powerstate();
  3765. }
  3766. /* Get last recorded state */
  3767. state = get_last_powerstate(&percent);
  3768. /* Populate gfx_display_ctx_powerstate_t */
  3769. powerstate->battery_enabled = (state != FRONTEND_POWERSTATE_NONE) &&
  3770. (state != FRONTEND_POWERSTATE_NO_SOURCE);
  3771. powerstate->percent = 0;
  3772. powerstate->charging = false;
  3773. if (powerstate->battery_enabled)
  3774. {
  3775. if (state == FRONTEND_POWERSTATE_CHARGING)
  3776. powerstate->charging = true;
  3777. if (percent > 0)
  3778. powerstate->percent = (unsigned)percent;
  3779. snprintf(powerstate->s, powerstate->len, "%u%%", powerstate->percent);
  3780. }
  3781. }
  3782. /* Iterate the menu driver for one frame. */
  3783. static bool menu_driver_iterate(
  3784. struct rarch_state *p_rarch,
  3785. enum menu_action action,
  3786. retro_time_t current_time)
  3787. {
  3788. return (p_rarch->menu_driver_data &&
  3789. generic_menu_iterate(
  3790. p_rarch,
  3791. p_rarch->menu_driver_data,
  3792. p_rarch->menu_userdata, action,
  3793. current_time) != -1);
  3794. }
  3795. int menu_driver_deferred_push_content_list(file_list_t *list)
  3796. {
  3797. struct rarch_state *p_rarch = &rarch_st;
  3798. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  3799. menu_handle_t *menu_data = p_rarch->menu_driver_data;
  3800. menu_list_t *menu_list = menu_st->entries.list;
  3801. file_list_t *selection_buf = MENU_LIST_GET_SELECTION(menu_list, (unsigned)0);
  3802. /* Must clear any existing menu search terms
  3803. * when switching 'tabs', since doing so
  3804. * bypasses standard backwards navigation
  3805. * (i.e. 'cancel' actions would normally
  3806. * pop the search stack - this will not
  3807. * happen if we jump to a new list directly) */
  3808. if (menu_data->search_terms)
  3809. string_list_free(menu_data->search_terms);
  3810. menu_data->search_terms = NULL;
  3811. menu_st->selection_ptr = 0;
  3812. if (!menu_driver_displaylist_push(
  3813. p_rarch,
  3814. menu_st,
  3815. list,
  3816. selection_buf))
  3817. return -1;
  3818. return 0;
  3819. }
  3820. bool menu_driver_list_cache(menu_ctx_list_t *list)
  3821. {
  3822. struct rarch_state *p_rarch = &rarch_st;
  3823. if (!list || !p_rarch->menu_driver_ctx || !p_rarch->menu_driver_ctx->list_cache)
  3824. return false;
  3825. p_rarch->menu_driver_ctx->list_cache(p_rarch->menu_userdata,
  3826. list->type, list->action);
  3827. return true;
  3828. }
  3829. static enum menu_driver_id_type menu_driver_set_id(const char *driver_name)
  3830. {
  3831. if (!string_is_empty(driver_name))
  3832. {
  3833. if (string_is_equal(driver_name, "rgui"))
  3834. return MENU_DRIVER_ID_RGUI;
  3835. else if (string_is_equal(driver_name, "ozone"))
  3836. return MENU_DRIVER_ID_OZONE;
  3837. else if (string_is_equal(driver_name, "glui"))
  3838. return MENU_DRIVER_ID_GLUI;
  3839. else if (string_is_equal(driver_name, "xmb"))
  3840. return MENU_DRIVER_ID_XMB;
  3841. else if (string_is_equal(driver_name, "stripes"))
  3842. return MENU_DRIVER_ID_STRIPES;
  3843. }
  3844. return MENU_DRIVER_ID_UNKNOWN;
  3845. }
  3846. static bool generic_menu_init_list(struct menu_state *menu_st)
  3847. {
  3848. menu_displaylist_info_t info;
  3849. menu_list_t *menu_list = menu_st->entries.list;
  3850. file_list_t *menu_stack = NULL;
  3851. file_list_t *selection_buf = NULL;
  3852. if (menu_list)
  3853. {
  3854. menu_stack = MENU_LIST_GET(menu_list, (unsigned)0);
  3855. selection_buf = MENU_LIST_GET_SELECTION(menu_list, (unsigned)0);
  3856. }
  3857. menu_displaylist_info_init(&info);
  3858. info.label = strdup(
  3859. msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU));
  3860. info.enum_idx = MENU_ENUM_LABEL_MAIN_MENU;
  3861. menu_entries_append_enum(menu_stack,
  3862. info.path,
  3863. info.label,
  3864. MENU_ENUM_LABEL_MAIN_MENU,
  3865. info.type, info.flags, 0);
  3866. info.list = selection_buf;
  3867. if (menu_displaylist_ctl(DISPLAYLIST_MAIN_MENU, &info))
  3868. menu_displaylist_process(&info);
  3869. menu_displaylist_info_free(&info);
  3870. return true;
  3871. }
  3872. static bool menu_driver_init_internal(
  3873. gfx_display_t *p_disp,
  3874. struct rarch_state *p_rarch,
  3875. settings_t *settings,
  3876. bool video_is_threaded)
  3877. {
  3878. if (p_rarch->menu_driver_ctx)
  3879. {
  3880. const char *ident = p_rarch->menu_driver_ctx->ident;
  3881. /* ID must be set first, since it is required for
  3882. * the proper determination of pixel/dpi scaling
  3883. * parameters (and some menu drivers fetch the
  3884. * current pixel/dpi scale during 'menu_driver_ctx->init()') */
  3885. if (ident)
  3886. p_disp->menu_driver_id = menu_driver_set_id(ident);
  3887. else
  3888. p_disp->menu_driver_id = MENU_DRIVER_ID_UNKNOWN;
  3889. if (p_rarch->menu_driver_ctx->init)
  3890. {
  3891. p_rarch->menu_driver_data = (menu_handle_t*)
  3892. p_rarch->menu_driver_ctx->init(&p_rarch->menu_userdata,
  3893. video_is_threaded);
  3894. p_rarch->menu_driver_data->userdata = p_rarch->menu_userdata;
  3895. p_rarch->menu_driver_data->driver_ctx = p_rarch->menu_driver_ctx;
  3896. }
  3897. }
  3898. if (!p_rarch->menu_driver_data || !menu_init(
  3899. &p_rarch->menu_driver_state,
  3900. &p_rarch->dialog_st,
  3901. p_rarch->menu_driver_ctx,
  3902. &p_rarch->menu_input_state,
  3903. &p_rarch->menu_input_pointer_hw_state,
  3904. settings))
  3905. return false;
  3906. gfx_display_init();
  3907. /* TODO/FIXME - can we get rid of this? Is this needed? */
  3908. configuration_set_string(settings,
  3909. settings->arrays.menu_driver, p_rarch->menu_driver_ctx->ident);
  3910. if (p_rarch->menu_driver_ctx->lists_init)
  3911. {
  3912. if (!p_rarch->menu_driver_ctx->lists_init(p_rarch->menu_driver_data))
  3913. return false;
  3914. }
  3915. else
  3916. generic_menu_init_list(&p_rarch->menu_driver_state);
  3917. return true;
  3918. }
  3919. bool menu_driver_init(bool video_is_threaded)
  3920. {
  3921. struct rarch_state *p_rarch = &rarch_st;
  3922. gfx_display_t *p_disp = &p_rarch->dispgfx;
  3923. command_event(CMD_EVENT_CORE_INFO_INIT, NULL);
  3924. command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
  3925. if ( p_rarch->menu_driver_data ||
  3926. menu_driver_init_internal(
  3927. &p_rarch->dispgfx,
  3928. p_rarch,
  3929. p_rarch->configuration_settings,
  3930. video_is_threaded))
  3931. {
  3932. if (p_rarch->menu_driver_ctx && p_rarch->menu_driver_ctx->context_reset)
  3933. {
  3934. p_rarch->menu_driver_ctx->context_reset(p_rarch->menu_userdata,
  3935. video_is_threaded);
  3936. return true;
  3937. }
  3938. }
  3939. /* If driver initialisation failed, must reset
  3940. * driver id to 'unknown' */
  3941. p_disp->menu_driver_id = MENU_DRIVER_ID_UNKNOWN;
  3942. return false;
  3943. }
  3944. void menu_driver_navigation_set(bool scroll)
  3945. {
  3946. struct rarch_state *p_rarch = &rarch_st;
  3947. if (p_rarch->menu_driver_ctx->navigation_set)
  3948. p_rarch->menu_driver_ctx->navigation_set(p_rarch->menu_userdata, scroll);
  3949. }
  3950. void menu_driver_populate_entries(menu_displaylist_info_t *info)
  3951. {
  3952. struct rarch_state *p_rarch = &rarch_st;
  3953. if (p_rarch->menu_driver_ctx && p_rarch->menu_driver_ctx->populate_entries)
  3954. p_rarch->menu_driver_ctx->populate_entries(
  3955. p_rarch->menu_userdata, info->path,
  3956. info->label, info->type);
  3957. }
  3958. bool menu_driver_push_list(menu_ctx_displaylist_t *disp_list)
  3959. {
  3960. struct rarch_state *p_rarch = &rarch_st;
  3961. if (p_rarch->menu_driver_ctx->list_push)
  3962. if (p_rarch->menu_driver_ctx->list_push(
  3963. p_rarch->menu_driver_data,
  3964. p_rarch->menu_userdata,
  3965. disp_list->info, disp_list->type) == 0)
  3966. return true;
  3967. return false;
  3968. }
  3969. void menu_driver_set_thumbnail_system(char *s, size_t len)
  3970. {
  3971. struct rarch_state *p_rarch = &rarch_st;
  3972. if ( p_rarch->menu_driver_ctx
  3973. && p_rarch->menu_driver_ctx->set_thumbnail_system)
  3974. p_rarch->menu_driver_ctx->set_thumbnail_system(
  3975. p_rarch->menu_userdata, s, len);
  3976. }
  3977. void menu_driver_get_thumbnail_system(char *s, size_t len)
  3978. {
  3979. struct rarch_state *p_rarch = &rarch_st;
  3980. if ( p_rarch->menu_driver_ctx
  3981. && p_rarch->menu_driver_ctx->get_thumbnail_system)
  3982. p_rarch->menu_driver_ctx->get_thumbnail_system(
  3983. p_rarch->menu_userdata, s, len);
  3984. }
  3985. void menu_driver_set_thumbnail_content(char *s, size_t len)
  3986. {
  3987. struct rarch_state *p_rarch = &rarch_st;
  3988. if ( p_rarch->menu_driver_ctx
  3989. && p_rarch->menu_driver_ctx->set_thumbnail_content)
  3990. p_rarch->menu_driver_ctx->set_thumbnail_content(
  3991. p_rarch->menu_userdata, s);
  3992. }
  3993. /* Teardown function for the menu driver. */
  3994. static void menu_driver_destroy(
  3995. struct rarch_state *p_rarch,
  3996. struct menu_state *menu_st)
  3997. {
  3998. menu_st->pending_quick_menu = false;
  3999. menu_st->prevent_populate = false;
  4000. menu_st->data_own = false;
  4001. p_rarch->menu_driver_ctx = NULL;
  4002. p_rarch->menu_userdata = NULL;
  4003. }
  4004. bool menu_driver_list_get_entry(menu_ctx_list_t *list)
  4005. {
  4006. struct rarch_state *p_rarch = &rarch_st;
  4007. if ( !p_rarch->menu_driver_ctx ||
  4008. !p_rarch->menu_driver_ctx->list_get_entry)
  4009. {
  4010. list->entry = NULL;
  4011. return false;
  4012. }
  4013. list->entry = p_rarch->menu_driver_ctx->list_get_entry(
  4014. p_rarch->menu_userdata,
  4015. list->type, (unsigned int)list->idx);
  4016. return true;
  4017. }
  4018. bool menu_driver_list_get_selection(menu_ctx_list_t *list)
  4019. {
  4020. struct rarch_state *p_rarch = &rarch_st;
  4021. if ( !p_rarch->menu_driver_ctx ||
  4022. !p_rarch->menu_driver_ctx->list_get_selection)
  4023. {
  4024. list->selection = 0;
  4025. return false;
  4026. }
  4027. list->selection = p_rarch->menu_driver_ctx->list_get_selection(
  4028. p_rarch->menu_userdata);
  4029. return true;
  4030. }
  4031. bool menu_driver_list_get_size(menu_ctx_list_t *list)
  4032. {
  4033. struct rarch_state *p_rarch = &rarch_st;
  4034. if ( !p_rarch->menu_driver_ctx ||
  4035. !p_rarch->menu_driver_ctx->list_get_size)
  4036. {
  4037. list->size = 0;
  4038. return false;
  4039. }
  4040. list->size = p_rarch->menu_driver_ctx->list_get_size(
  4041. p_rarch->menu_userdata, list->type);
  4042. return true;
  4043. }
  4044. retro_time_t menu_driver_get_current_time(void)
  4045. {
  4046. struct rarch_state *p_rarch = &rarch_st;
  4047. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  4048. return menu_st->current_time_us;
  4049. }
  4050. static void menu_driver_list_free(
  4051. const menu_ctx_driver_t *menu_driver_ctx,
  4052. menu_ctx_list_t *list)
  4053. {
  4054. if (menu_driver_ctx)
  4055. if (menu_driver_ctx->list_free)
  4056. menu_driver_ctx->list_free(
  4057. list->list, list->idx, list->list_size);
  4058. if (list->list)
  4059. {
  4060. file_list_free_userdata (list->list, list->idx);
  4061. file_list_free_actiondata(list->list, list->idx);
  4062. }
  4063. }
  4064. /* Returns true if search filter is enabled
  4065. * for the specified menu list */
  4066. bool menu_driver_search_filter_enabled(const char *label, unsigned type)
  4067. {
  4068. bool filter_enabled = false;
  4069. /* > Check for playlists */
  4070. filter_enabled = (type == MENU_SETTING_HORIZONTAL_MENU) ||
  4071. (type == MENU_HISTORY_TAB) ||
  4072. (type == MENU_FAVORITES_TAB) ||
  4073. (type == MENU_IMAGES_TAB) ||
  4074. (type == MENU_MUSIC_TAB) ||
  4075. (type == MENU_VIDEO_TAB) ||
  4076. (type == FILE_TYPE_PLAYLIST_COLLECTION);
  4077. if (!filter_enabled && !string_is_empty(label))
  4078. filter_enabled = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY)) ||
  4079. string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST)) ||
  4080. string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST)) ||
  4081. string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MUSIC_LIST)) ||
  4082. string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_VIDEO_LIST)) ||
  4083. /* > Check for core updater */
  4084. string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST));
  4085. return filter_enabled;
  4086. }
  4087. bool menu_driver_search_push(const char *search_term)
  4088. {
  4089. struct rarch_state *p_rarch = &rarch_st;
  4090. menu_handle_t *menu = p_rarch->menu_driver_data;
  4091. union string_list_elem_attr attr;
  4092. if (!menu || string_is_empty(search_term))
  4093. return false;
  4094. /* Initialise list, if required */
  4095. if (!menu->search_terms)
  4096. {
  4097. menu->search_terms = string_list_new();
  4098. if (!menu->search_terms)
  4099. return false;
  4100. }
  4101. /* Check whether search term already exists */
  4102. if (string_list_find_elem(menu->search_terms, search_term))
  4103. return false;
  4104. /* Add search term */
  4105. attr.i = 0;
  4106. if (!string_list_append(menu->search_terms,
  4107. search_term, attr))
  4108. return false;
  4109. return true;
  4110. }
  4111. bool menu_driver_search_pop(void)
  4112. {
  4113. struct rarch_state *p_rarch = &rarch_st;
  4114. menu_handle_t *menu = p_rarch->menu_driver_data;
  4115. union string_list_elem_attr attr = {0};
  4116. size_t element_index;
  4117. if (!menu || !menu->search_terms)
  4118. return false;
  4119. /* If we have a 'broken' list, free it
  4120. * (this cannot actually happen, but if
  4121. * we didn't free the list in this case
  4122. * then menu navigation could get 'stuck') */
  4123. if ((menu->search_terms->size < 1) ||
  4124. !menu->search_terms->elems)
  4125. goto free_list;
  4126. /* Get index of last element in the list */
  4127. element_index = menu->search_terms->size - 1;
  4128. /* If this is the only element, free the
  4129. * entire list */
  4130. if (element_index == 0)
  4131. goto free_list;
  4132. /* Otherwise, 'reset' the element... */
  4133. if (menu->search_terms->elems[element_index].data)
  4134. {
  4135. free(menu->search_terms->elems[element_index].data);
  4136. menu->search_terms->elems[element_index].data = NULL;
  4137. }
  4138. if (menu->search_terms->elems[element_index].userdata)
  4139. {
  4140. free(menu->search_terms->elems[element_index].userdata);
  4141. menu->search_terms->elems[element_index].userdata = NULL;
  4142. }
  4143. menu->search_terms->elems[element_index].attr = attr;
  4144. /* ...and decrement the list size */
  4145. menu->search_terms->size--;
  4146. return true;
  4147. free_list:
  4148. string_list_free(menu->search_terms);
  4149. menu->search_terms = NULL;
  4150. return true;
  4151. }
  4152. struct string_list *menu_driver_search_get_terms(void)
  4153. {
  4154. struct rarch_state *p_rarch = &rarch_st;
  4155. menu_handle_t *menu = p_rarch->menu_driver_data;
  4156. if (!menu)
  4157. return NULL;
  4158. return menu->search_terms;
  4159. }
  4160. /* Convenience function: Appends list of current
  4161. * search terms to specified string */
  4162. void menu_driver_search_append_terms_string(char *s, size_t len)
  4163. {
  4164. struct rarch_state *p_rarch = &rarch_st;
  4165. menu_handle_t *menu = p_rarch->menu_driver_data;
  4166. if (menu &&
  4167. menu->search_terms &&
  4168. (menu->search_terms->size > 0) &&
  4169. s)
  4170. {
  4171. char search_str[512];
  4172. search_str[0] = '\0';
  4173. string_list_join_concat(search_str, sizeof(search_str),
  4174. menu->search_terms, " > ");
  4175. strlcat(s, " > ", len);
  4176. strlcat(s, search_str, len);
  4177. }
  4178. }
  4179. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  4180. static void menu_driver_set_last_shader_path_int(
  4181. const char *shader_path,
  4182. enum rarch_shader_type *type,
  4183. char *shader_dir, size_t dir_len,
  4184. char *shader_file, size_t file_len)
  4185. {
  4186. const char *file_name = NULL;
  4187. if (!type ||
  4188. !shader_dir ||
  4189. (dir_len < 1) ||
  4190. !shader_file ||
  4191. (file_len < 1))
  4192. return;
  4193. /* Reset existing cache */
  4194. *type = RARCH_SHADER_NONE;
  4195. shader_dir[0] = '\0';
  4196. shader_file[0] = '\0';
  4197. /* If path is empty, do nothing */
  4198. if (string_is_empty(shader_path))
  4199. return;
  4200. /* Get shader type */
  4201. *type = video_shader_parse_type(shader_path);
  4202. /* If type is invalid, do nothing */
  4203. if (*type == RARCH_SHADER_NONE)
  4204. return;
  4205. /* Cache parent directory */
  4206. fill_pathname_parent_dir(shader_dir, shader_path, dir_len);
  4207. /* If parent directory is empty, then file name
  4208. * is only valid if 'shader_path' refers to an
  4209. * existing file in the root of the file system */
  4210. if (string_is_empty(shader_dir) &&
  4211. !path_is_valid(shader_path))
  4212. return;
  4213. /* Cache file name */
  4214. file_name = path_basename(shader_path);
  4215. if (!string_is_empty(file_name))
  4216. strlcpy(shader_file, file_name, file_len);
  4217. }
  4218. void menu_driver_set_last_shader_preset_path(const char *path)
  4219. {
  4220. struct rarch_state *p_rarch = &rarch_st;
  4221. menu_handle_t *menu = p_rarch->menu_driver_data;
  4222. if (!menu)
  4223. return;
  4224. menu_driver_set_last_shader_path_int(
  4225. path,
  4226. &menu->last_shader_selection.preset_type,
  4227. menu->last_shader_selection.preset_dir,
  4228. sizeof(menu->last_shader_selection.preset_dir),
  4229. menu->last_shader_selection.preset_file_name,
  4230. sizeof(menu->last_shader_selection.preset_file_name));
  4231. }
  4232. void menu_driver_set_last_shader_pass_path(const char *path)
  4233. {
  4234. struct rarch_state *p_rarch = &rarch_st;
  4235. menu_handle_t *menu = p_rarch->menu_driver_data;
  4236. if (!menu)
  4237. return;
  4238. menu_driver_set_last_shader_path_int(
  4239. path,
  4240. &menu->last_shader_selection.pass_type,
  4241. menu->last_shader_selection.pass_dir,
  4242. sizeof(menu->last_shader_selection.pass_dir),
  4243. menu->last_shader_selection.pass_file_name,
  4244. sizeof(menu->last_shader_selection.pass_file_name));
  4245. }
  4246. enum rarch_shader_type menu_driver_get_last_shader_preset_type(void)
  4247. {
  4248. struct rarch_state *p_rarch = &rarch_st;
  4249. menu_handle_t *menu = p_rarch->menu_driver_data;
  4250. if (!menu)
  4251. return RARCH_SHADER_NONE;
  4252. return menu->last_shader_selection.preset_type;
  4253. }
  4254. enum rarch_shader_type menu_driver_get_last_shader_pass_type(void)
  4255. {
  4256. struct rarch_state *p_rarch = &rarch_st;
  4257. menu_handle_t *menu = p_rarch->menu_driver_data;
  4258. if (!menu)
  4259. return RARCH_SHADER_NONE;
  4260. return menu->last_shader_selection.pass_type;
  4261. }
  4262. void menu_driver_get_last_shader_path_int(
  4263. struct rarch_state *p_rarch, enum rarch_shader_type type,
  4264. const char *shader_dir, const char *shader_file_name,
  4265. const char **dir_out, const char **file_name_out)
  4266. {
  4267. settings_t *settings = p_rarch->configuration_settings;
  4268. bool remember_last_dir = settings->bools.video_shader_remember_last_dir;
  4269. const char *video_shader_dir = settings->paths.directory_video_shader;
  4270. /* File name is NULL by default */
  4271. if (file_name_out)
  4272. *file_name_out = NULL;
  4273. /* If any of the following are true:
  4274. * - Directory caching is disabled
  4275. * - No directory has been cached
  4276. * - Cached directory is invalid
  4277. * - Last selected shader is incompatible with
  4278. * the current video driver
  4279. * ...use default settings */
  4280. if (!remember_last_dir ||
  4281. (type == RARCH_SHADER_NONE) ||
  4282. string_is_empty(shader_dir) ||
  4283. !path_is_directory(shader_dir) ||
  4284. !video_shader_is_supported(type))
  4285. {
  4286. if (dir_out)
  4287. *dir_out = video_shader_dir;
  4288. return;
  4289. }
  4290. /* Assign last set directory */
  4291. if (dir_out)
  4292. *dir_out = shader_dir;
  4293. /* Assign file name */
  4294. if (file_name_out &&
  4295. !string_is_empty(shader_file_name))
  4296. *file_name_out = shader_file_name;
  4297. }
  4298. void menu_driver_get_last_shader_preset_path(
  4299. const char **directory, const char **file_name)
  4300. {
  4301. struct rarch_state *p_rarch = &rarch_st;
  4302. menu_handle_t *menu = p_rarch->menu_driver_data;
  4303. enum rarch_shader_type type = RARCH_SHADER_NONE;
  4304. const char *shader_dir = NULL;
  4305. const char *shader_file_name = NULL;
  4306. if (menu)
  4307. {
  4308. type = menu->last_shader_selection.preset_type;
  4309. shader_dir = menu->last_shader_selection.preset_dir;
  4310. shader_file_name = menu->last_shader_selection.preset_file_name;
  4311. }
  4312. menu_driver_get_last_shader_path_int(p_rarch, type,
  4313. shader_dir, shader_file_name,
  4314. directory, file_name);
  4315. }
  4316. void menu_driver_get_last_shader_pass_path(
  4317. const char **directory, const char **file_name)
  4318. {
  4319. struct rarch_state *p_rarch = &rarch_st;
  4320. menu_handle_t *menu = p_rarch->menu_driver_data;
  4321. enum rarch_shader_type type = RARCH_SHADER_NONE;
  4322. const char *shader_dir = NULL;
  4323. const char *shader_file_name = NULL;
  4324. if (menu)
  4325. {
  4326. type = menu->last_shader_selection.pass_type;
  4327. shader_dir = menu->last_shader_selection.pass_dir;
  4328. shader_file_name = menu->last_shader_selection.pass_file_name;
  4329. }
  4330. menu_driver_get_last_shader_path_int(p_rarch, type,
  4331. shader_dir, shader_file_name,
  4332. directory, file_name);
  4333. }
  4334. #endif
  4335. const char *menu_driver_get_last_start_directory(void)
  4336. {
  4337. struct rarch_state *p_rarch = &rarch_st;
  4338. menu_handle_t *menu = p_rarch->menu_driver_data;
  4339. settings_t *settings = p_rarch->configuration_settings;
  4340. bool use_last = settings->bools.use_last_start_directory;
  4341. const char *default_directory = settings->paths.directory_menu_content;
  4342. /* Return default directory if there is no
  4343. * last directory or it's invalid */
  4344. if (!menu ||
  4345. !use_last ||
  4346. string_is_empty(menu->last_start_content.directory) ||
  4347. !path_is_directory(menu->last_start_content.directory))
  4348. return default_directory;
  4349. return menu->last_start_content.directory;
  4350. }
  4351. const char *menu_driver_get_last_start_file_name(void)
  4352. {
  4353. struct rarch_state *p_rarch = &rarch_st;
  4354. menu_handle_t *menu = p_rarch->menu_driver_data;
  4355. settings_t *settings = p_rarch->configuration_settings;
  4356. bool use_last = settings->bools.use_last_start_directory;
  4357. /* Return NULL if there is no last 'file name' */
  4358. if (!menu ||
  4359. !use_last ||
  4360. string_is_empty(menu->last_start_content.file_name))
  4361. return NULL;
  4362. return menu->last_start_content.file_name;
  4363. }
  4364. void menu_driver_set_last_start_content(const char *start_content_path)
  4365. {
  4366. struct rarch_state *p_rarch = &rarch_st;
  4367. menu_handle_t *menu = p_rarch->menu_driver_data;
  4368. settings_t *settings = p_rarch->configuration_settings;
  4369. bool use_last = settings->bools.use_last_start_directory;
  4370. const char *archive_delim = NULL;
  4371. const char *file_name = NULL;
  4372. char archive_path[PATH_MAX_LENGTH];
  4373. if (!menu)
  4374. return;
  4375. /* Reset existing cache */
  4376. menu->last_start_content.directory[0] = '\0';
  4377. menu->last_start_content.file_name[0] = '\0';
  4378. /* If 'use_last_start_directory' is disabled or
  4379. * path is empty, do nothing */
  4380. if (!use_last ||
  4381. string_is_empty(start_content_path))
  4382. return;
  4383. /* Cache directory */
  4384. fill_pathname_parent_dir(menu->last_start_content.directory,
  4385. start_content_path, sizeof(menu->last_start_content.directory));
  4386. /* Cache file name */
  4387. archive_delim = path_get_archive_delim(start_content_path);
  4388. if (archive_delim)
  4389. {
  4390. /* If path references a file inside an
  4391. * archive, must extract the string segment
  4392. * before the archive delimiter (i.e. path of
  4393. * 'parent' archive file) */
  4394. size_t len;
  4395. archive_path[0] = '\0';
  4396. len = (size_t)(1 + archive_delim - start_content_path);
  4397. len = (len < PATH_MAX_LENGTH) ? len : PATH_MAX_LENGTH;
  4398. strlcpy(archive_path, start_content_path, len * sizeof(char));
  4399. file_name = path_basename(archive_path);
  4400. }
  4401. else
  4402. file_name = path_basename(start_content_path);
  4403. if (!string_is_empty(file_name))
  4404. strlcpy(menu->last_start_content.file_name, file_name,
  4405. sizeof(menu->last_start_content.file_name));
  4406. }
  4407. const char *menu_driver_get_pending_selection(void)
  4408. {
  4409. struct rarch_state *p_rarch = &rarch_st;
  4410. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  4411. return menu_st->pending_selection;
  4412. }
  4413. void menu_driver_set_pending_selection(const char *pending_selection)
  4414. {
  4415. struct rarch_state *p_rarch = &rarch_st;
  4416. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  4417. char *selection = menu_st->pending_selection;
  4418. /* Reset existing cache */
  4419. selection[0] = '\0';
  4420. /* If path is empty, do nothing */
  4421. if (string_is_empty(pending_selection))
  4422. return;
  4423. strlcpy(selection, pending_selection,
  4424. sizeof(menu_st->pending_selection));
  4425. }
  4426. bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data)
  4427. {
  4428. struct rarch_state *p_rarch = &rarch_st;
  4429. gfx_display_t *p_disp = &p_rarch->dispgfx;
  4430. menu_handle_t *menu_data = p_rarch->menu_driver_data;
  4431. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  4432. switch (state)
  4433. {
  4434. case RARCH_MENU_CTL_SET_PENDING_QUICK_MENU:
  4435. menu_entries_flush_stack(NULL, MENU_SETTINGS);
  4436. menu_st->pending_quick_menu = true;
  4437. break;
  4438. case RARCH_MENU_CTL_FIND_DRIVER:
  4439. {
  4440. settings_t *settings = p_rarch->configuration_settings;
  4441. int i = (int)driver_find_index(
  4442. "menu_driver",
  4443. settings->arrays.menu_driver);
  4444. if (i >= 0)
  4445. p_rarch->menu_driver_ctx = (const menu_ctx_driver_t*)
  4446. menu_ctx_drivers[i];
  4447. else
  4448. {
  4449. if (verbosity_is_enabled())
  4450. {
  4451. unsigned d;
  4452. RARCH_WARN("Couldn't find any menu driver named \"%s\"\n",
  4453. settings->arrays.menu_driver);
  4454. RARCH_LOG_OUTPUT("Available menu drivers are:\n");
  4455. for (d = 0; menu_ctx_drivers[d]; d++)
  4456. {
  4457. if (menu_ctx_drivers[d])
  4458. {
  4459. RARCH_LOG_OUTPUT("\t%s\n", menu_ctx_drivers[d]->ident);
  4460. }
  4461. }
  4462. RARCH_WARN("Going to default to first menu driver...\n");
  4463. }
  4464. p_rarch->menu_driver_ctx = (const menu_ctx_driver_t*)
  4465. menu_ctx_drivers[0];
  4466. if (!p_rarch->menu_driver_ctx)
  4467. return false;
  4468. }
  4469. }
  4470. break;
  4471. case RARCH_MENU_CTL_SET_PREVENT_POPULATE:
  4472. menu_st->prevent_populate = true;
  4473. break;
  4474. case RARCH_MENU_CTL_UNSET_PREVENT_POPULATE:
  4475. menu_st->prevent_populate = false;
  4476. break;
  4477. case RARCH_MENU_CTL_IS_PREVENT_POPULATE:
  4478. return menu_st->prevent_populate;
  4479. case RARCH_MENU_CTL_DEINIT:
  4480. if ( p_rarch->menu_driver_ctx
  4481. && p_rarch->menu_driver_ctx->context_destroy)
  4482. p_rarch->menu_driver_ctx->context_destroy(p_rarch->menu_userdata);
  4483. if (menu_st->data_own)
  4484. return true;
  4485. playlist_free_cached();
  4486. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  4487. menu_shader_manager_free(p_rarch);
  4488. #endif
  4489. #ifdef HAVE_NETWORKING
  4490. core_updater_list_free_cached();
  4491. #endif
  4492. #if defined(HAVE_MENU) && defined(HAVE_LIBRETRODB)
  4493. menu_explore_free();
  4494. #endif
  4495. if (p_rarch->menu_driver_data)
  4496. {
  4497. unsigned i;
  4498. menu_st->scroll.acceleration = 0;
  4499. menu_st->selection_ptr = 0;
  4500. menu_st->scroll.index_size = 0;
  4501. for (i = 0; i < SCROLL_INDEX_SIZE; i++)
  4502. menu_st->scroll.index_list[i] = 0;
  4503. menu_input_reset(
  4504. &p_rarch->menu_input_state,
  4505. &p_rarch->menu_input_pointer_hw_state
  4506. );
  4507. if ( p_rarch->menu_driver_ctx
  4508. && p_rarch->menu_driver_ctx->free)
  4509. p_rarch->menu_driver_ctx->free(p_rarch->menu_userdata);
  4510. if (p_rarch->menu_userdata)
  4511. free(p_rarch->menu_userdata);
  4512. p_rarch->menu_userdata = NULL;
  4513. p_disp->menu_driver_id = MENU_DRIVER_ID_UNKNOWN;
  4514. #ifndef HAVE_DYNAMIC
  4515. if (frontend_driver_has_fork())
  4516. #endif
  4517. {
  4518. rarch_system_info_t *system = &p_rarch->runloop_system;
  4519. libretro_free_system_info(&system->info);
  4520. memset(&system->info, 0, sizeof(struct retro_system_info));
  4521. }
  4522. gfx_animation_deinit(&p_rarch->anim);
  4523. gfx_display_free();
  4524. menu_entries_settings_deinit(menu_st);
  4525. menu_entries_list_deinit(p_rarch->menu_driver_ctx, menu_st);
  4526. if (p_rarch->menu_driver_data->core_buf)
  4527. free(p_rarch->menu_driver_data->core_buf);
  4528. p_rarch->menu_driver_data->core_buf = NULL;
  4529. if (menu_data->search_terms)
  4530. string_list_free(menu_data->search_terms);
  4531. menu_data->search_terms = NULL;
  4532. menu_st->entries_need_refresh = false;
  4533. menu_st->entries_nonblocking_refresh = false;
  4534. menu_st->entries.begin = 0;
  4535. command_event(CMD_EVENT_HISTORY_DEINIT, NULL);
  4536. rarch_favorites_deinit();
  4537. p_rarch->dialog_st.pending_push = false;
  4538. p_rarch->dialog_st.current_id = 0;
  4539. p_rarch->dialog_st.current_type = MENU_DIALOG_NONE;
  4540. free(p_rarch->menu_driver_data);
  4541. }
  4542. p_rarch->menu_driver_data = NULL;
  4543. break;
  4544. case RARCH_MENU_CTL_ENVIRONMENT:
  4545. {
  4546. menu_ctx_environment_t *menu_environ =
  4547. (menu_ctx_environment_t*)data;
  4548. if (p_rarch->menu_driver_ctx->environ_cb)
  4549. {
  4550. if (p_rarch->menu_driver_ctx->environ_cb(menu_environ->type,
  4551. menu_environ->data, p_rarch->menu_userdata) == 0)
  4552. return true;
  4553. }
  4554. }
  4555. return false;
  4556. case RARCH_MENU_CTL_POINTER_DOWN:
  4557. {
  4558. menu_ctx_pointer_t *point = (menu_ctx_pointer_t*)data;
  4559. if (!p_rarch->menu_driver_ctx || !p_rarch->menu_driver_ctx->pointer_down)
  4560. {
  4561. point->retcode = 0;
  4562. return false;
  4563. }
  4564. point->retcode = p_rarch->menu_driver_ctx->pointer_down(
  4565. p_rarch->menu_userdata,
  4566. point->x, point->y, point->ptr,
  4567. point->cbs, point->entry, point->action);
  4568. }
  4569. break;
  4570. case RARCH_MENU_CTL_POINTER_UP:
  4571. {
  4572. menu_ctx_pointer_t *point = (menu_ctx_pointer_t*)data;
  4573. if (!p_rarch->menu_driver_ctx || !p_rarch->menu_driver_ctx->pointer_up)
  4574. {
  4575. point->retcode = 0;
  4576. return false;
  4577. }
  4578. point->retcode = p_rarch->menu_driver_ctx->pointer_up(
  4579. p_rarch->menu_userdata,
  4580. point->x, point->y, point->ptr,
  4581. point->gesture,
  4582. point->cbs, point->entry, point->action);
  4583. }
  4584. break;
  4585. case RARCH_MENU_CTL_OSK_PTR_AT_POS:
  4586. {
  4587. unsigned width = 0;
  4588. unsigned height = 0;
  4589. menu_ctx_pointer_t *point = (menu_ctx_pointer_t*)data;
  4590. if (!p_rarch->menu_driver_ctx || !p_rarch->menu_driver_ctx->osk_ptr_at_pos)
  4591. {
  4592. point->retcode = 0;
  4593. return false;
  4594. }
  4595. video_driver_get_size(&width, &height);
  4596. point->retcode = p_rarch->menu_driver_ctx->osk_ptr_at_pos(
  4597. p_rarch->menu_userdata,
  4598. point->x, point->y, width, height);
  4599. }
  4600. break;
  4601. case RARCH_MENU_CTL_UPDATE_THUMBNAIL_PATH:
  4602. {
  4603. size_t selection = menu_st->selection_ptr;
  4604. if (!p_rarch->menu_driver_ctx || !p_rarch->menu_driver_ctx->update_thumbnail_path)
  4605. return false;
  4606. p_rarch->menu_driver_ctx->update_thumbnail_path(
  4607. p_rarch->menu_userdata, (unsigned)selection, 'L');
  4608. p_rarch->menu_driver_ctx->update_thumbnail_path(
  4609. p_rarch->menu_userdata, (unsigned)selection, 'R');
  4610. }
  4611. break;
  4612. case RARCH_MENU_CTL_UPDATE_THUMBNAIL_IMAGE:
  4613. {
  4614. if (!p_rarch->menu_driver_ctx || !p_rarch->menu_driver_ctx->update_thumbnail_image)
  4615. return false;
  4616. p_rarch->menu_driver_ctx->update_thumbnail_image(p_rarch->menu_userdata);
  4617. }
  4618. break;
  4619. case RARCH_MENU_CTL_REFRESH_THUMBNAIL_IMAGE:
  4620. {
  4621. unsigned *i = (unsigned*)data;
  4622. if (!i || !p_rarch->menu_driver_ctx ||
  4623. !p_rarch->menu_driver_ctx->refresh_thumbnail_image)
  4624. return false;
  4625. p_rarch->menu_driver_ctx->refresh_thumbnail_image(
  4626. p_rarch->menu_userdata, *i);
  4627. }
  4628. break;
  4629. case RARCH_MENU_CTL_UPDATE_SAVESTATE_THUMBNAIL_PATH:
  4630. {
  4631. size_t selection = menu_st->selection_ptr;
  4632. if ( !p_rarch->menu_driver_ctx ||
  4633. !p_rarch->menu_driver_ctx->update_savestate_thumbnail_path)
  4634. return false;
  4635. p_rarch->menu_driver_ctx->update_savestate_thumbnail_path(
  4636. p_rarch->menu_userdata, (unsigned)selection);
  4637. }
  4638. break;
  4639. case RARCH_MENU_CTL_UPDATE_SAVESTATE_THUMBNAIL_IMAGE:
  4640. if ( !p_rarch->menu_driver_ctx ||
  4641. !p_rarch->menu_driver_ctx->update_savestate_thumbnail_image)
  4642. return false;
  4643. p_rarch->menu_driver_ctx->update_savestate_thumbnail_image(
  4644. p_rarch->menu_userdata);
  4645. break;
  4646. case MENU_NAVIGATION_CTL_CLEAR:
  4647. {
  4648. bool *pending_push = (bool*)data;
  4649. /* Always set current selection to first entry */
  4650. menu_st->selection_ptr = 0;
  4651. /* menu_driver_navigation_set() will be called
  4652. * at the next 'push'.
  4653. * If a push is *not* pending, have to do it here
  4654. * instead */
  4655. if (!(*pending_push))
  4656. {
  4657. menu_driver_navigation_set(true);
  4658. if (p_rarch->menu_driver_ctx->navigation_clear)
  4659. p_rarch->menu_driver_ctx->navigation_clear(
  4660. p_rarch->menu_userdata, *pending_push);
  4661. }
  4662. }
  4663. break;
  4664. case MENU_NAVIGATION_CTL_SET_LAST:
  4665. {
  4666. size_t menu_list_size = menu_st->entries.list ? MENU_LIST_GET_SELECTION(menu_st->entries.list, 0)->size : 0;
  4667. size_t new_selection = menu_list_size - 1;
  4668. menu_st->selection_ptr = new_selection;
  4669. if (p_rarch->menu_driver_ctx->navigation_set_last)
  4670. p_rarch->menu_driver_ctx->navigation_set_last(p_rarch->menu_userdata);
  4671. }
  4672. break;
  4673. case MENU_NAVIGATION_CTL_GET_SCROLL_ACCEL:
  4674. {
  4675. size_t *sel = (size_t*)data;
  4676. if (!sel)
  4677. return false;
  4678. *sel = menu_st->scroll.acceleration;
  4679. }
  4680. break;
  4681. default:
  4682. case RARCH_MENU_CTL_NONE:
  4683. break;
  4684. }
  4685. return true;
  4686. }
  4687. #endif
  4688. /**
  4689. * find_driver_nonempty:
  4690. * @label : string of driver type to be found.
  4691. * @i : index of driver.
  4692. * @str : identifier name of the found driver
  4693. * gets written to this string.
  4694. * @len : size of @str.
  4695. *
  4696. * Find driver based on @label.
  4697. *
  4698. * Returns: NULL if no driver based on @label found, otherwise
  4699. * pointer to driver.
  4700. **/
  4701. static const void *find_driver_nonempty(
  4702. const char *label, int i,
  4703. char *s, size_t len)
  4704. {
  4705. if (string_is_equal(label, "camera_driver"))
  4706. {
  4707. if (camera_drivers[i])
  4708. {
  4709. const char *ident = camera_drivers[i]->ident;
  4710. strlcpy(s, ident, len);
  4711. return camera_drivers[i];
  4712. }
  4713. }
  4714. else if (string_is_equal(label, "location_driver"))
  4715. {
  4716. if (location_drivers[i])
  4717. {
  4718. const char *ident = location_drivers[i]->ident;
  4719. strlcpy(s, ident, len);
  4720. return location_drivers[i];
  4721. }
  4722. }
  4723. #ifdef HAVE_MENU
  4724. else if (string_is_equal(label, "menu_driver"))
  4725. {
  4726. if (menu_ctx_drivers[i])
  4727. {
  4728. const char *ident = menu_ctx_drivers[i]->ident;
  4729. strlcpy(s, ident, len);
  4730. return menu_ctx_drivers[i];
  4731. }
  4732. }
  4733. #endif
  4734. else if (string_is_equal(label, "input_driver"))
  4735. {
  4736. if (input_drivers[i])
  4737. {
  4738. const char *ident = input_drivers[i]->ident;
  4739. strlcpy(s, ident, len);
  4740. return input_drivers[i];
  4741. }
  4742. }
  4743. else if (string_is_equal(label, "input_joypad_driver"))
  4744. {
  4745. if (joypad_drivers[i])
  4746. {
  4747. const char *ident = joypad_drivers[i]->ident;
  4748. strlcpy(s, ident, len);
  4749. return joypad_drivers[i];
  4750. }
  4751. }
  4752. else if (string_is_equal(label, "video_driver"))
  4753. {
  4754. if (video_drivers[i])
  4755. {
  4756. const char *ident = video_drivers[i]->ident;
  4757. strlcpy(s, ident, len);
  4758. return video_drivers[i];
  4759. }
  4760. }
  4761. else if (string_is_equal(label, "audio_driver"))
  4762. {
  4763. if (audio_drivers[i])
  4764. {
  4765. const char *ident = audio_drivers[i]->ident;
  4766. strlcpy(s, ident, len);
  4767. return audio_drivers[i];
  4768. }
  4769. }
  4770. else if (string_is_equal(label, "record_driver"))
  4771. {
  4772. if (record_drivers[i])
  4773. {
  4774. const char *ident = record_drivers[i]->ident;
  4775. strlcpy(s, ident, len);
  4776. return record_drivers[i];
  4777. }
  4778. }
  4779. else if (string_is_equal(label, "midi_driver"))
  4780. {
  4781. if (midi_driver_find_handle(i))
  4782. {
  4783. const char *ident = midi_drivers[i]->ident;
  4784. strlcpy(s, ident, len);
  4785. return midi_drivers[i];
  4786. }
  4787. }
  4788. else if (string_is_equal(label, "audio_resampler_driver"))
  4789. {
  4790. if (audio_resampler_driver_find_handle(i))
  4791. {
  4792. const char *ident = audio_resampler_driver_find_ident(i);
  4793. strlcpy(s, ident, len);
  4794. return audio_resampler_driver_find_handle(i);
  4795. }
  4796. }
  4797. else if (string_is_equal(label, "bluetooth_driver"))
  4798. {
  4799. if (bluetooth_drivers[i])
  4800. {
  4801. const char *ident = bluetooth_drivers[i]->ident;
  4802. strlcpy(s, ident, len);
  4803. return bluetooth_drivers[i];
  4804. }
  4805. }
  4806. else if (string_is_equal(label, "wifi_driver"))
  4807. {
  4808. if (wifi_drivers[i])
  4809. {
  4810. const char *ident = wifi_drivers[i]->ident;
  4811. strlcpy(s, ident, len);
  4812. return wifi_drivers[i];
  4813. }
  4814. }
  4815. return NULL;
  4816. }
  4817. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  4818. struct video_shader *menu_shader_get(void)
  4819. {
  4820. struct rarch_state *p_rarch = &rarch_st;
  4821. if (video_shader_any_supported())
  4822. if (p_rarch)
  4823. return p_rarch->menu_driver_shader;
  4824. return NULL;
  4825. }
  4826. void menu_shader_manager_free(void *data)
  4827. {
  4828. struct rarch_state *p_rarch = (struct rarch_state*)data;
  4829. if (p_rarch->menu_driver_shader)
  4830. free(p_rarch->menu_driver_shader);
  4831. p_rarch->menu_driver_shader = NULL;
  4832. }
  4833. /**
  4834. * menu_shader_manager_init:
  4835. *
  4836. * Initializes shader manager.
  4837. **/
  4838. bool menu_shader_manager_init(void)
  4839. {
  4840. struct rarch_state *p_rarch = &rarch_st;
  4841. enum rarch_shader_type type = RARCH_SHADER_NONE;
  4842. bool ret = true;
  4843. bool is_preset = false;
  4844. const char *path_shader = NULL;
  4845. struct video_shader *menu_shader = NULL;
  4846. /* We get the shader preset directly from the video driver, so that
  4847. * we are in sync with it (it could fail loading an auto-shader)
  4848. * If we can't (e.g. get_current_shader is not implemented),
  4849. * we'll load retroarch_get_shader_preset() like always */
  4850. video_shader_ctx_t shader_info = {0};
  4851. video_shader_driver_get_current_shader(&shader_info);
  4852. if (shader_info.data)
  4853. /* Use the path of the originally loaded preset because it could
  4854. * have been a preset with a #reference in it to another preset */
  4855. path_shader = shader_info.data->loaded_preset_path;
  4856. else
  4857. path_shader = retroarch_get_shader_preset();
  4858. menu_shader_manager_free(p_rarch);
  4859. menu_shader = (struct video_shader*)
  4860. calloc(1, sizeof(*menu_shader));
  4861. if (!menu_shader)
  4862. {
  4863. ret = false;
  4864. goto end;
  4865. }
  4866. if (string_is_empty(path_shader))
  4867. goto end;
  4868. type = video_shader_get_type_from_ext(path_get_extension(path_shader),
  4869. &is_preset);
  4870. if (!video_shader_is_supported(type))
  4871. {
  4872. ret = false;
  4873. goto end;
  4874. }
  4875. if (is_preset)
  4876. {
  4877. if (!video_shader_load_preset_into_shader(path_shader, menu_shader))
  4878. {
  4879. ret = false;
  4880. goto end;
  4881. }
  4882. menu_shader->modified = false;
  4883. }
  4884. else
  4885. {
  4886. strlcpy(menu_shader->pass[0].source.path, path_shader,
  4887. sizeof(menu_shader->pass[0].source.path));
  4888. menu_shader->passes = 1;
  4889. }
  4890. end:
  4891. p_rarch->menu_driver_shader = menu_shader;
  4892. command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL);
  4893. return ret;
  4894. }
  4895. /**
  4896. * menu_shader_manager_set_preset:
  4897. * @shader : Shader handle.
  4898. * @type : Type of shader.
  4899. * @preset_path : Preset path to load from.
  4900. * @apply : Whether to apply the shader or just update shader information
  4901. *
  4902. * Sets shader preset.
  4903. **/
  4904. bool menu_shader_manager_set_preset(struct video_shader *shader,
  4905. enum rarch_shader_type type, const char *preset_path, bool apply)
  4906. {
  4907. bool refresh = false;
  4908. bool ret = false;
  4909. if (apply && !retroarch_apply_shader(type, preset_path, true))
  4910. goto clear;
  4911. if (string_is_empty(preset_path))
  4912. {
  4913. ret = true;
  4914. goto clear;
  4915. }
  4916. /* Load stored Preset into menu on success.
  4917. * Used when a preset is directly loaded.
  4918. * No point in updating when the Preset was
  4919. * created from the menu itself. */
  4920. if ( !shader ||
  4921. !(video_shader_load_preset_into_shader(preset_path, shader)))
  4922. goto end;
  4923. RARCH_LOG("Menu shader set to: %s.\n", preset_path);
  4924. ret = true;
  4925. end:
  4926. #ifdef HAVE_MENU
  4927. menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
  4928. #endif
  4929. command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL);
  4930. return ret;
  4931. clear:
  4932. /* We don't want to disable shaders entirely here,
  4933. * just reset number of passes
  4934. * > Note: Disabling shaders at this point would in
  4935. * fact be dangerous, since it changes the number of
  4936. * entries in the shader options menu which can in
  4937. * turn lead to the menu selection pointer going out
  4938. * of bounds. This causes undefined behaviour/segfaults */
  4939. menu_shader_manager_clear_num_passes(shader);
  4940. command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL);
  4941. return ret;
  4942. }
  4943. static bool menu_shader_manager_save_preset_internal(
  4944. const struct video_shader *shader,
  4945. const char *basename,
  4946. const char *dir_video_shader,
  4947. bool apply,
  4948. const char **target_dirs,
  4949. size_t num_target_dirs)
  4950. {
  4951. char fullname[PATH_MAX_LENGTH];
  4952. char buffer[PATH_MAX_LENGTH];
  4953. bool ret = false;
  4954. enum rarch_shader_type type = RARCH_SHADER_NONE;
  4955. char *preset_path = NULL;
  4956. size_t i = 0;
  4957. struct rarch_state *p_rarch = &rarch_st;
  4958. settings_t *settings = p_rarch->configuration_settings;
  4959. bool save_reference =
  4960. settings->bools.video_shader_preset_save_reference_enable;
  4961. fullname[0] = buffer[0] = '\0';
  4962. if (!shader || !shader->passes)
  4963. return false;
  4964. type = menu_shader_manager_get_type(shader);
  4965. if (type == RARCH_SHADER_NONE)
  4966. return false;
  4967. if (!string_is_empty(basename))
  4968. {
  4969. /* We are comparing against a fixed list of file
  4970. * extensions, the longest (slangp) being 6 characters
  4971. * in length. We therefore only need to extract the first
  4972. * 7 characters from the extension of the input path
  4973. * to correctly validate a match */
  4974. char ext_lower[8];
  4975. const char *ext = NULL;
  4976. ext_lower[0] = '\0';
  4977. strlcpy(fullname, basename, sizeof(fullname));
  4978. /* Get file extension */
  4979. ext = strrchr(basename, '.');
  4980. /* Copy and convert to lower case */
  4981. if (ext && (*(++ext) != '\0'))
  4982. {
  4983. strlcpy(ext_lower, ext, sizeof(ext_lower));
  4984. string_to_lower(ext_lower);
  4985. }
  4986. /* Append extension automatically as appropriate. */
  4987. if ( !string_is_equal(ext_lower, "cgp")
  4988. && !string_is_equal(ext_lower, "glslp")
  4989. && !string_is_equal(ext_lower, "slangp"))
  4990. {
  4991. const char *preset_ext = video_shader_get_preset_extension(type);
  4992. strlcat(fullname, preset_ext, sizeof(fullname));
  4993. }
  4994. }
  4995. else
  4996. {
  4997. strcpy_literal(fullname, "retroarch");
  4998. strlcat(fullname,
  4999. video_shader_get_preset_extension(type), sizeof(fullname));
  5000. }
  5001. if (path_is_absolute(fullname))
  5002. {
  5003. preset_path = fullname;
  5004. ret = video_shader_write_preset(preset_path,
  5005. dir_video_shader,
  5006. shader, save_reference);
  5007. if (ret)
  5008. RARCH_LOG("[Shaders - Save Preset]: Saved shader preset to %s.\n", preset_path);
  5009. else
  5010. RARCH_ERR("[Shaders - Save Preset]: Failed writing shader preset to %s.\n", preset_path);
  5011. }
  5012. else
  5013. {
  5014. char basedir[PATH_MAX_LENGTH];
  5015. for (i = 0; i < num_target_dirs; i++)
  5016. {
  5017. if (string_is_empty(target_dirs[i]))
  5018. continue;
  5019. fill_pathname_join(buffer, target_dirs[i],
  5020. fullname, sizeof(buffer));
  5021. strlcpy(basedir, buffer, sizeof(basedir));
  5022. path_basedir(basedir);
  5023. if (!path_is_directory(basedir))
  5024. {
  5025. ret = path_mkdir(basedir);
  5026. if (!ret)
  5027. {
  5028. RARCH_WARN("[Shaders - Save Preset]: Failed to create preset directory %s.\n", basedir);
  5029. continue;
  5030. }
  5031. }
  5032. preset_path = buffer;
  5033. ret = video_shader_write_preset(preset_path,
  5034. dir_video_shader,
  5035. shader, save_reference);
  5036. if (ret)
  5037. {
  5038. RARCH_LOG("[Shaders - Save Preset]: Saved shader preset to %s.\n", preset_path);
  5039. break;
  5040. }
  5041. else
  5042. RARCH_WARN("[Shaders - Save Preset]: Failed writing shader preset to %s.\n", preset_path);
  5043. }
  5044. if (!ret)
  5045. RARCH_ERR("[Shaders - Save Preset]: Failed to write shader preset. Make sure shader directory"
  5046. " and/or config directory are writable.\n");
  5047. }
  5048. if (ret && apply)
  5049. menu_shader_manager_set_preset(NULL, type, preset_path, true);
  5050. return ret;
  5051. }
  5052. static bool menu_shader_manager_operate_auto_preset(
  5053. enum auto_shader_operation op,
  5054. const struct video_shader *shader,
  5055. const char *dir_video_shader,
  5056. const char *dir_menu_config,
  5057. enum auto_shader_type type, bool apply)
  5058. {
  5059. char old_presets_directory[PATH_MAX_LENGTH];
  5060. char config_directory[PATH_MAX_LENGTH];
  5061. char tmp[PATH_MAX_LENGTH];
  5062. char file[PATH_MAX_LENGTH];
  5063. struct retro_system_info *system = runloop_get_libretro_system_info();
  5064. const char *core_name = system ? system->library_name : NULL;
  5065. const char *auto_preset_dirs[3] = {0};
  5066. old_presets_directory[0] = config_directory[0] = tmp[0] = file[0] = '\0';
  5067. if (type != SHADER_PRESET_GLOBAL && string_is_empty(core_name))
  5068. return false;
  5069. if (!path_is_empty(RARCH_PATH_CONFIG))
  5070. fill_pathname_basedir(
  5071. config_directory,
  5072. path_get(RARCH_PATH_CONFIG),
  5073. sizeof(config_directory));
  5074. /* We are only including this directory for compatibility purposes with
  5075. * versions 1.8.7 and older. */
  5076. if (op != AUTO_SHADER_OP_SAVE && !string_is_empty(dir_video_shader))
  5077. fill_pathname_join(
  5078. old_presets_directory,
  5079. dir_video_shader,
  5080. "presets",
  5081. sizeof(old_presets_directory));
  5082. auto_preset_dirs[0] = dir_menu_config;
  5083. auto_preset_dirs[1] = config_directory;
  5084. auto_preset_dirs[2] = old_presets_directory;
  5085. switch (type)
  5086. {
  5087. case SHADER_PRESET_GLOBAL:
  5088. strcpy_literal(file, "global");
  5089. break;
  5090. case SHADER_PRESET_CORE:
  5091. fill_pathname_join(file, core_name, core_name, sizeof(file));
  5092. break;
  5093. case SHADER_PRESET_PARENT:
  5094. fill_pathname_parent_dir_name(tmp,
  5095. path_get(RARCH_PATH_BASENAME), sizeof(tmp));
  5096. fill_pathname_join(file, core_name, tmp, sizeof(file));
  5097. break;
  5098. case SHADER_PRESET_GAME:
  5099. {
  5100. const char *game_name =
  5101. path_basename(path_get(RARCH_PATH_BASENAME));
  5102. if (string_is_empty(game_name))
  5103. return false;
  5104. fill_pathname_join(file, core_name, game_name, sizeof(file));
  5105. break;
  5106. }
  5107. default:
  5108. return false;
  5109. }
  5110. switch (op)
  5111. {
  5112. case AUTO_SHADER_OP_SAVE:
  5113. return menu_shader_manager_save_preset_internal(
  5114. shader, file,
  5115. dir_video_shader,
  5116. apply,
  5117. auto_preset_dirs,
  5118. ARRAY_SIZE(auto_preset_dirs));
  5119. case AUTO_SHADER_OP_REMOVE:
  5120. {
  5121. /* remove all supported auto-shaders of given type */
  5122. char *end;
  5123. size_t i, j, n, m;
  5124. char preset_path[PATH_MAX_LENGTH];
  5125. /* n = amount of relevant shader presets found
  5126. * m = amount of successfully deleted shader presets */
  5127. n = m = 0;
  5128. for (i = 0; i < ARRAY_SIZE(auto_preset_dirs); i++)
  5129. {
  5130. if (string_is_empty(auto_preset_dirs[i]))
  5131. continue;
  5132. fill_pathname_join(preset_path,
  5133. auto_preset_dirs[i], file, sizeof(preset_path));
  5134. end = preset_path + strlen(preset_path);
  5135. for (j = 0; j < ARRAY_SIZE(shader_types); j++)
  5136. {
  5137. const char *preset_ext;
  5138. if (!video_shader_is_supported(shader_types[j]))
  5139. continue;
  5140. preset_ext = video_shader_get_preset_extension(shader_types[j]);
  5141. strlcpy(end, preset_ext, sizeof(preset_path) - (end - preset_path));
  5142. if (path_is_valid(preset_path))
  5143. {
  5144. n++;
  5145. if (!filestream_delete(preset_path))
  5146. {
  5147. m++;
  5148. RARCH_LOG("[Shaders]: Deleted shader preset from \"%s\".\n", preset_path);
  5149. }
  5150. else
  5151. RARCH_WARN("[Shaders]: Failed to remove shader preset at \"%s\".\n", preset_path);
  5152. }
  5153. }
  5154. }
  5155. return n == m;
  5156. }
  5157. case AUTO_SHADER_OP_EXISTS:
  5158. {
  5159. /* test if any supported auto-shaders of given type exists */
  5160. char *end;
  5161. size_t i, j;
  5162. char preset_path[PATH_MAX_LENGTH];
  5163. for (i = 0; i < ARRAY_SIZE(auto_preset_dirs); i++)
  5164. {
  5165. if (string_is_empty(auto_preset_dirs[i]))
  5166. continue;
  5167. fill_pathname_join(preset_path,
  5168. auto_preset_dirs[i], file, sizeof(preset_path));
  5169. end = preset_path + strlen(preset_path);
  5170. for (j = 0; j < ARRAY_SIZE(shader_types); j++)
  5171. {
  5172. const char *preset_ext;
  5173. if (!video_shader_is_supported(shader_types[j]))
  5174. continue;
  5175. preset_ext = video_shader_get_preset_extension(shader_types[j]);
  5176. strlcpy(end, preset_ext, sizeof(preset_path) - (end - preset_path));
  5177. if (path_is_valid(preset_path))
  5178. return true;
  5179. }
  5180. }
  5181. }
  5182. break;
  5183. }
  5184. return false;
  5185. }
  5186. /**
  5187. * menu_shader_manager_save_auto_preset:
  5188. * @shader : shader to save
  5189. * @type : type of shader preset which determines save path
  5190. * @apply : immediately set preset after saving
  5191. *
  5192. * Save a shader as an auto-shader to it's appropriate path:
  5193. * SHADER_PRESET_GLOBAL: <target dir>/global
  5194. * SHADER_PRESET_CORE: <target dir>/<core name>/<core name>
  5195. * SHADER_PRESET_PARENT: <target dir>/<core name>/<parent>
  5196. * SHADER_PRESET_GAME: <target dir>/<core name>/<game name>
  5197. * Needs to be consistent with retroarch_load_shader_preset()
  5198. * Auto-shaders will be saved as a reference if possible
  5199. **/
  5200. bool menu_shader_manager_save_auto_preset(
  5201. const struct video_shader *shader,
  5202. enum auto_shader_type type,
  5203. const char *dir_video_shader,
  5204. const char *dir_menu_config,
  5205. bool apply)
  5206. {
  5207. return menu_shader_manager_operate_auto_preset(
  5208. AUTO_SHADER_OP_SAVE, shader,
  5209. dir_video_shader,
  5210. dir_menu_config,
  5211. type, apply);
  5212. }
  5213. /**
  5214. * menu_shader_manager_save_preset:
  5215. * @shader : shader to save
  5216. * @type : type of shader preset which determines save path
  5217. * @basename : basename of preset
  5218. * @apply : immediately set preset after saving
  5219. *
  5220. * Save a shader preset to disk.
  5221. **/
  5222. bool menu_shader_manager_save_preset(const struct video_shader *shader,
  5223. const char *basename,
  5224. const char *dir_video_shader,
  5225. const char *dir_menu_config,
  5226. bool apply)
  5227. {
  5228. char config_directory[PATH_MAX_LENGTH];
  5229. const char *preset_dirs[3] = {0};
  5230. config_directory[0] = '\0';
  5231. if (!path_is_empty(RARCH_PATH_CONFIG))
  5232. fill_pathname_basedir(
  5233. config_directory,
  5234. path_get(RARCH_PATH_CONFIG),
  5235. sizeof(config_directory));
  5236. preset_dirs[0] = dir_video_shader;
  5237. preset_dirs[1] = dir_menu_config;
  5238. preset_dirs[2] = config_directory;
  5239. return menu_shader_manager_save_preset_internal(
  5240. shader, basename,
  5241. dir_video_shader,
  5242. apply,
  5243. preset_dirs,
  5244. ARRAY_SIZE(preset_dirs));
  5245. }
  5246. /**
  5247. * menu_shader_manager_remove_auto_preset:
  5248. * @type : type of shader preset to delete
  5249. *
  5250. * Deletes an auto-shader.
  5251. **/
  5252. bool menu_shader_manager_remove_auto_preset(
  5253. enum auto_shader_type type,
  5254. const char *dir_video_shader,
  5255. const char *dir_menu_config)
  5256. {
  5257. return menu_shader_manager_operate_auto_preset(
  5258. AUTO_SHADER_OP_REMOVE, NULL,
  5259. dir_video_shader,
  5260. dir_menu_config,
  5261. type, false);
  5262. }
  5263. /**
  5264. * menu_shader_manager_auto_preset_exists:
  5265. * @type : type of shader preset
  5266. *
  5267. * Tests if an auto-shader of the given type exists.
  5268. **/
  5269. bool menu_shader_manager_auto_preset_exists(
  5270. enum auto_shader_type type,
  5271. const char *dir_video_shader,
  5272. const char *dir_menu_config)
  5273. {
  5274. return menu_shader_manager_operate_auto_preset(
  5275. AUTO_SHADER_OP_EXISTS, NULL,
  5276. dir_video_shader,
  5277. dir_menu_config,
  5278. type, false);
  5279. }
  5280. int menu_shader_manager_clear_num_passes(struct video_shader *shader)
  5281. {
  5282. bool refresh = false;
  5283. if (!shader)
  5284. return 0;
  5285. shader->passes = 0;
  5286. #ifdef HAVE_MENU
  5287. menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
  5288. #endif
  5289. video_shader_resolve_parameters(shader);
  5290. shader->modified = true;
  5291. return 0;
  5292. }
  5293. int menu_shader_manager_clear_parameter(struct video_shader *shader,
  5294. unsigned i)
  5295. {
  5296. struct video_shader_parameter *param = shader ?
  5297. &shader->parameters[i] : NULL;
  5298. if (!param)
  5299. return 0;
  5300. param->current = param->initial;
  5301. param->current = MIN(MAX(param->minimum,
  5302. param->current), param->maximum);
  5303. shader->modified = true;
  5304. return 0;
  5305. }
  5306. int menu_shader_manager_clear_pass_filter(struct video_shader *shader,
  5307. unsigned i)
  5308. {
  5309. struct video_shader_pass *shader_pass = shader ?
  5310. &shader->pass[i] : NULL;
  5311. if (!shader_pass)
  5312. return -1;
  5313. shader_pass->filter = RARCH_FILTER_UNSPEC;
  5314. shader->modified = true;
  5315. return 0;
  5316. }
  5317. void menu_shader_manager_clear_pass_scale(struct video_shader *shader,
  5318. unsigned i)
  5319. {
  5320. struct video_shader_pass *shader_pass = shader ?
  5321. &shader->pass[i] : NULL;
  5322. if (!shader_pass)
  5323. return;
  5324. shader_pass->fbo.scale_x = 0;
  5325. shader_pass->fbo.scale_y = 0;
  5326. shader_pass->fbo.valid = false;
  5327. shader->modified = true;
  5328. }
  5329. void menu_shader_manager_clear_pass_path(struct video_shader *shader,
  5330. unsigned i)
  5331. {
  5332. struct video_shader_pass
  5333. *shader_pass = shader
  5334. ? &shader->pass[i]
  5335. : NULL;
  5336. if (shader_pass)
  5337. *shader_pass->source.path = '\0';
  5338. if (shader)
  5339. shader->modified = true;
  5340. }
  5341. /**
  5342. * menu_shader_manager_get_type:
  5343. * @shader : shader handle
  5344. *
  5345. * Gets type of shader.
  5346. *
  5347. * Returns: type of shader.
  5348. **/
  5349. enum rarch_shader_type menu_shader_manager_get_type(
  5350. const struct video_shader *shader)
  5351. {
  5352. enum rarch_shader_type type = RARCH_SHADER_NONE;
  5353. /* All shader types must be the same, or we cannot use it. */
  5354. size_t i = 0;
  5355. if (!shader)
  5356. return RARCH_SHADER_NONE;
  5357. type = video_shader_parse_type(shader->path);
  5358. if (!shader->passes)
  5359. return type;
  5360. if (type == RARCH_SHADER_NONE)
  5361. {
  5362. type = video_shader_parse_type(shader->pass[0].source.path);
  5363. i = 1;
  5364. }
  5365. for (; i < shader->passes; i++)
  5366. {
  5367. enum rarch_shader_type pass_type =
  5368. video_shader_parse_type(shader->pass[i].source.path);
  5369. switch (pass_type)
  5370. {
  5371. case RARCH_SHADER_CG:
  5372. case RARCH_SHADER_GLSL:
  5373. case RARCH_SHADER_SLANG:
  5374. if (type != pass_type)
  5375. return RARCH_SHADER_NONE;
  5376. break;
  5377. default:
  5378. break;
  5379. }
  5380. }
  5381. return type;
  5382. }
  5383. /**
  5384. * menu_shader_manager_apply_changes:
  5385. *
  5386. * Apply shader state changes.
  5387. **/
  5388. void menu_shader_manager_apply_changes(
  5389. struct video_shader *shader,
  5390. const char *dir_video_shader,
  5391. const char *dir_menu_config)
  5392. {
  5393. enum rarch_shader_type type = RARCH_SHADER_NONE;
  5394. if (!shader)
  5395. return;
  5396. type = menu_shader_manager_get_type(shader);
  5397. if (shader->passes && type != RARCH_SHADER_NONE)
  5398. {
  5399. menu_shader_manager_save_preset(shader, NULL,
  5400. dir_video_shader, dir_menu_config, true);
  5401. return;
  5402. }
  5403. menu_shader_manager_set_preset(NULL, type, NULL, true);
  5404. }
  5405. #endif
  5406. #ifdef HAVE_DISCORD
  5407. bool discord_is_ready(void)
  5408. {
  5409. struct rarch_state *p_rarch = &rarch_st;
  5410. discord_state_t *discord_st = &p_rarch->discord_st;
  5411. return discord_st->ready;
  5412. }
  5413. static char *discord_get_own_username(struct rarch_state *p_rarch)
  5414. {
  5415. discord_state_t *discord_st = &p_rarch->discord_st;
  5416. if (discord_st->ready)
  5417. return discord_st->user_name;
  5418. return NULL;
  5419. }
  5420. char *discord_get_own_avatar(void)
  5421. {
  5422. struct rarch_state *p_rarch = &rarch_st;
  5423. discord_state_t *discord_st = &p_rarch->discord_st;
  5424. if (discord_st->ready)
  5425. return discord_st->user_avatar;
  5426. return NULL;
  5427. }
  5428. bool discord_avatar_is_ready(void)
  5429. {
  5430. return false;
  5431. }
  5432. void discord_avatar_set_ready(bool ready)
  5433. {
  5434. struct rarch_state *p_rarch = &rarch_st;
  5435. discord_state_t *discord_st = &p_rarch->discord_st;
  5436. discord_st->avatar_ready = ready;
  5437. }
  5438. #ifdef HAVE_MENU
  5439. static bool discord_download_avatar(
  5440. const char* user_id, const char* avatar_id)
  5441. {
  5442. static char url[PATH_MAX_LENGTH];
  5443. static char url_encoded[PATH_MAX_LENGTH];
  5444. static char full_path[PATH_MAX_LENGTH];
  5445. static char buf[PATH_MAX_LENGTH];
  5446. file_transfer_t *transf = NULL;
  5447. struct rarch_state *p_rarch = &rarch_st;
  5448. discord_state_t *discord_st = &p_rarch->discord_st;
  5449. RARCH_LOG("[DISCORD]: User avatar ID: %s\n", user_id);
  5450. fill_pathname_application_special(buf,
  5451. sizeof(buf),
  5452. APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_DISCORD_AVATARS);
  5453. fill_pathname_join(full_path, buf, avatar_id, sizeof(full_path));
  5454. strlcpy(discord_st->user_avatar,
  5455. avatar_id, sizeof(discord_st->user_avatar));
  5456. if (path_is_valid(full_path))
  5457. return true;
  5458. if (string_is_empty(avatar_id))
  5459. return false;
  5460. snprintf(url, sizeof(url), "%s/%s/%s" FILE_PATH_PNG_EXTENSION, CDN_URL, user_id, avatar_id);
  5461. net_http_urlencode_full(url_encoded, url, sizeof(url_encoded));
  5462. snprintf(buf, sizeof(buf), "%s" FILE_PATH_PNG_EXTENSION, avatar_id);
  5463. transf = (file_transfer_t*)malloc(sizeof(*transf));
  5464. transf->enum_idx = MENU_ENUM_LABEL_CB_DISCORD_AVATAR;
  5465. strlcpy(transf->path, buf, sizeof(transf->path));
  5466. transf->user_data = NULL;
  5467. RARCH_LOG("[DISCORD]: Downloading avatar from: %s\n", url_encoded);
  5468. task_push_http_transfer_file(url_encoded, true, NULL, cb_generic_download, transf);
  5469. return false;
  5470. }
  5471. #endif
  5472. static void handle_discord_ready(const DiscordUser* connectedUser)
  5473. {
  5474. struct rarch_state *p_rarch = &rarch_st;
  5475. discord_state_t *discord_st = &p_rarch->discord_st;
  5476. strlcpy(discord_st->user_name,
  5477. connectedUser->username, sizeof(discord_st->user_name));
  5478. RARCH_LOG("[DISCORD]: Connected to user: %s#%s\n",
  5479. connectedUser->username,
  5480. connectedUser->discriminator);
  5481. #ifdef HAVE_MENU
  5482. discord_download_avatar(connectedUser->userId, connectedUser->avatar);
  5483. #endif
  5484. }
  5485. static void handle_discord_disconnected(int errcode, const char* message)
  5486. {
  5487. RARCH_LOG("[DISCORD]: Disconnected (%d: %s)\n", errcode, message);
  5488. }
  5489. static void handle_discord_error(int errcode, const char* message)
  5490. {
  5491. RARCH_LOG("[DISCORD]: Error (%d: %s)\n", errcode, message);
  5492. }
  5493. static void handle_discord_join_cb(retro_task_t *task,
  5494. void *task_data, void *user_data, const char *err)
  5495. {
  5496. char join_hostname[PATH_MAX_LENGTH];
  5497. struct netplay_room *room = NULL;
  5498. http_transfer_data_t *data = (http_transfer_data_t*)task_data;
  5499. struct rarch_state *p_rarch = &rarch_st;
  5500. discord_state_t *discord_st = &p_rarch->discord_st;
  5501. if (!data || err || !data->data)
  5502. goto finish;
  5503. data->data = (char*)realloc(data->data, data->len + 1);
  5504. data->data[data->len] = '\0';
  5505. netplay_rooms_parse(data->data);
  5506. room = netplay_room_get(0);
  5507. if (room)
  5508. {
  5509. bool host_method_is_mitm = room->host_method == NETPLAY_HOST_METHOD_MITM;
  5510. const char *srv_address = host_method_is_mitm ? room->mitm_address : room->address;
  5511. unsigned srv_port = host_method_is_mitm ? room->mitm_port : room->port;
  5512. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
  5513. deinit_netplay(p_rarch);
  5514. netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
  5515. snprintf(join_hostname, sizeof(join_hostname), "%s|%d",
  5516. srv_address, srv_port);
  5517. RARCH_LOG("[DISCORD]: Joining lobby at: %s\n", join_hostname);
  5518. task_push_netplay_crc_scan(room->gamecrc,
  5519. room->gamename, join_hostname, room->corename, room->subsystem_name);
  5520. discord_st->connecting = true;
  5521. if (discord_st->ready)
  5522. discord_update(DISCORD_PRESENCE_NETPLAY_CLIENT);
  5523. }
  5524. finish:
  5525. if (err)
  5526. RARCH_ERR("%s: %s\n", msg_hash_to_str(MSG_DOWNLOAD_FAILED), err);
  5527. if (data)
  5528. {
  5529. if (data->data)
  5530. free(data->data);
  5531. free(data);
  5532. }
  5533. if (user_data)
  5534. free(user_data);
  5535. }
  5536. static void handle_discord_join(const char* secret)
  5537. {
  5538. char url[2048] = FILE_PATH_LOBBY_LIBRETRO_URL;
  5539. struct string_list *list = string_split(secret, "|");
  5540. struct rarch_state *p_rarch = &rarch_st;
  5541. discord_state_t *discord_st = &p_rarch->discord_st;
  5542. strlcpy(discord_st->peer_party_id,
  5543. list->elems[0].data, sizeof(discord_st->peer_party_id));
  5544. strlcat(url, discord_st->peer_party_id, sizeof(url));
  5545. strlcat(url, "/", sizeof(url));
  5546. RARCH_LOG("[DISCORD]: Querying lobby id: %s at %s\n",
  5547. discord_st->peer_party_id, url);
  5548. task_push_http_transfer(url, true, NULL, handle_discord_join_cb, NULL);
  5549. }
  5550. static void handle_discord_spectate(const char* secret)
  5551. {
  5552. RARCH_LOG("[DISCORD]: Spectate (%s)\n", secret);
  5553. }
  5554. #ifdef HAVE_MENU
  5555. #if 0
  5556. static void handle_discord_join_response(void *ignore, const char *line)
  5557. {
  5558. /* TODO/FIXME: needs in-game widgets */
  5559. if (strstr(line, "yes"))
  5560. Discord_Respond(user_id, DISCORD_REPLY_YES);
  5561. #ifdef HAVE_MENU
  5562. menu_input_dialog_end();
  5563. retroarch_menu_running_finished(false);
  5564. #endif
  5565. }
  5566. #endif
  5567. #endif
  5568. static void handle_discord_join_request(const DiscordUser* request)
  5569. {
  5570. #ifdef HAVE_MENU
  5571. #if 0
  5572. char buf[PATH_MAX_LENGTH];
  5573. #endif
  5574. menu_input_ctx_line_t line;
  5575. RARCH_LOG("[DISCORD]: Join request from %s#%s - %s %s\n",
  5576. request->username,
  5577. request->discriminator,
  5578. request->userId,
  5579. request->avatar);
  5580. discord_download_avatar(request->userId, request->avatar);
  5581. #if 0
  5582. /* TODO/FIXME: Needs in-game widgets */
  5583. retroarch_menu_running();
  5584. memset(&line, 0, sizeof(line));
  5585. snprintf(buf, sizeof(buf), "%s %s?",
  5586. msg_hash_to_str(MSG_DISCORD_CONNECTION_REQUEST), request->username);
  5587. line.label = buf;
  5588. line.label_setting = "no_setting";
  5589. line.cb = handle_discord_join_response;
  5590. /* TODO/FIXME: needs in-game widgets
  5591. * TODO/FIXME: bespoke dialog, should show while in-game
  5592. * and have a hotkey to accept
  5593. * TODO/FIXME: show avatar of the user connecting
  5594. */
  5595. if (!menu_input_dialog_start(&line))
  5596. return;
  5597. #endif
  5598. #endif
  5599. }
  5600. void discord_update(enum discord_presence presence)
  5601. {
  5602. struct rarch_state *p_rarch = &rarch_st;
  5603. discord_state_t *discord_st = &p_rarch->discord_st;
  5604. if (presence == discord_st->status)
  5605. return;
  5606. if (!discord_st->connecting
  5607. &&
  5608. ( presence == DISCORD_PRESENCE_NONE
  5609. || presence == DISCORD_PRESENCE_MENU))
  5610. {
  5611. memset(&discord_st->presence,
  5612. 0, sizeof(discord_st->presence));
  5613. discord_st->peer_party_id[0] = '\0';
  5614. }
  5615. switch (presence)
  5616. {
  5617. case DISCORD_PRESENCE_MENU:
  5618. discord_st->presence.details = msg_hash_to_str(
  5619. MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU);
  5620. discord_st->presence.largeImageKey = "base";
  5621. discord_st->presence.largeImageText = msg_hash_to_str(
  5622. MENU_ENUM_LABEL_VALUE_NO_CORE);
  5623. discord_st->presence.instance = 0;
  5624. break;
  5625. case DISCORD_PRESENCE_GAME_PAUSED:
  5626. discord_st->presence.smallImageKey = "paused";
  5627. discord_st->presence.smallImageText = msg_hash_to_str(
  5628. MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED);
  5629. discord_st->presence.details = msg_hash_to_str(
  5630. MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED);
  5631. discord_st->pause_time = time(0);
  5632. discord_st->elapsed_time = difftime(discord_st->pause_time,
  5633. discord_st->start_time);
  5634. discord_st->presence.startTimestamp = discord_st->pause_time;
  5635. break;
  5636. case DISCORD_PRESENCE_GAME:
  5637. {
  5638. core_info_t *core_info = NULL;
  5639. core_info_get_current_core(&core_info);
  5640. if (core_info)
  5641. {
  5642. const char *system_id =
  5643. core_info->system_id
  5644. ? core_info->system_id
  5645. : "core";
  5646. const char *label = NULL;
  5647. const struct playlist_entry *entry = NULL;
  5648. playlist_t *current_playlist = playlist_get_cached();
  5649. if (current_playlist)
  5650. {
  5651. playlist_get_index_by_path(
  5652. current_playlist,
  5653. path_get(RARCH_PATH_CONTENT),
  5654. &entry);
  5655. if (entry && !string_is_empty(entry->label))
  5656. label = entry->label;
  5657. }
  5658. if (!label)
  5659. label = path_basename(path_get(RARCH_PATH_BASENAME));
  5660. discord_st->presence.largeImageKey = system_id;
  5661. if (core_info->display_name)
  5662. discord_st->presence.largeImageText =
  5663. core_info->display_name;
  5664. discord_st->start_time = time(0);
  5665. if (discord_st->pause_time != 0)
  5666. discord_st->start_time = time(0) -
  5667. discord_st->elapsed_time;
  5668. discord_st->pause_time = 0;
  5669. discord_st->elapsed_time = 0;
  5670. discord_st->presence.smallImageKey = "playing";
  5671. discord_st->presence.smallImageText = msg_hash_to_str(
  5672. MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING);
  5673. discord_st->presence.startTimestamp = discord_st->start_time;
  5674. #ifdef HAVE_CHEEVOS
  5675. discord_st->presence.details = rcheevos_get_richpresence();
  5676. if (!discord_st->presence.details || !*discord_st->presence.details)
  5677. #endif
  5678. discord_st->presence.details = msg_hash_to_str(
  5679. MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME);
  5680. discord_st->presence.state = label;
  5681. discord_st->presence.instance = 0;
  5682. if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
  5683. {
  5684. discord_st->peer_party_id[0] = '\0';
  5685. discord_st->connecting = false;
  5686. discord_st->presence.partyId = NULL;
  5687. discord_st->presence.partyMax = 0;
  5688. discord_st->presence.partySize = 0;
  5689. discord_st->presence.joinSecret = (const char*)'\0';
  5690. }
  5691. }
  5692. }
  5693. break;
  5694. case DISCORD_PRESENCE_NETPLAY_HOSTING:
  5695. {
  5696. char join_secret[128];
  5697. struct netplay_room *room = &p_rarch->netplay_host_room;
  5698. bool host_method_is_mitm = room->host_method == NETPLAY_HOST_METHOD_MITM;
  5699. const char *srv_address = host_method_is_mitm ? room->mitm_address : room->address;
  5700. unsigned srv_port = host_method_is_mitm ? room->mitm_port : room->port;
  5701. if (room->id == 0)
  5702. return;
  5703. RARCH_LOG("[DISCORD]: Netplay room details: ID=%d"
  5704. ", Nick=%s IP=%s Port=%d\n",
  5705. room->id, room->nickname,
  5706. srv_address, srv_port);
  5707. snprintf(discord_st->self_party_id,
  5708. sizeof(discord_st->self_party_id), "%d", room->id);
  5709. snprintf(join_secret,
  5710. sizeof(join_secret), "%d|%" PRId64,
  5711. room->id, cpu_features_get_time_usec());
  5712. discord_st->presence.joinSecret = strdup(join_secret);
  5713. #if 0
  5714. discord_st->presence.spectateSecret = "SPECSPECSPEC";
  5715. #endif
  5716. discord_st->presence.partyId = strdup(discord_st->self_party_id);
  5717. discord_st->presence.partyMax = 2;
  5718. discord_st->presence.partySize = 1;
  5719. RARCH_LOG("[DISCORD]: Join secret: %s\n", join_secret);
  5720. RARCH_LOG("[DISCORD]: Party ID: %s\n", discord_st->self_party_id);
  5721. }
  5722. break;
  5723. case DISCORD_PRESENCE_NETPLAY_CLIENT:
  5724. RARCH_LOG("[DISCORD]: Party ID: %s\n", discord_st->peer_party_id);
  5725. discord_st->presence.partyId = strdup(discord_st->peer_party_id);
  5726. break;
  5727. case DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED:
  5728. {
  5729. if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL) &&
  5730. !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_CONNECTED, NULL))
  5731. {
  5732. discord_st->peer_party_id[0] = '\0';
  5733. discord_st->connecting = false;
  5734. discord_st->presence.partyId = NULL;
  5735. discord_st->presence.partyMax = 0;
  5736. discord_st->presence.partySize = 0;
  5737. discord_st->presence.joinSecret = (const char*)'\0';
  5738. }
  5739. }
  5740. break;
  5741. #ifdef HAVE_CHEEVOS
  5742. case DISCORD_PRESENCE_RETROACHIEVEMENTS:
  5743. if (discord_st->pause_time)
  5744. return;
  5745. discord_st->presence.details = rcheevos_get_richpresence();
  5746. presence = DISCORD_PRESENCE_GAME;
  5747. break;
  5748. #endif
  5749. case DISCORD_PRESENCE_SHUTDOWN:
  5750. discord_st->presence.partyId = NULL;
  5751. discord_st->presence.partyMax = 0;
  5752. discord_st->presence.partySize = 0;
  5753. discord_st->presence.joinSecret = (const char*)'\0';
  5754. discord_st->connecting = false;
  5755. default:
  5756. break;
  5757. }
  5758. #ifdef DEBUG
  5759. RARCH_LOG("[DISCORD]: Updating (%d)\n", presence);
  5760. #endif
  5761. Discord_UpdatePresence(&discord_st->presence);
  5762. Discord_UpdateConnection();
  5763. discord_st->status = presence;
  5764. }
  5765. static void discord_init(
  5766. discord_state_t *discord_st,
  5767. const char *discord_app_id, char *args)
  5768. {
  5769. DiscordEventHandlers handlers;
  5770. char full_path[PATH_MAX_LENGTH];
  5771. char command[PATH_MAX_LENGTH];
  5772. discord_st->start_time = time(0);
  5773. handlers.ready = handle_discord_ready;
  5774. handlers.disconnected = handle_discord_disconnected;
  5775. handlers.errored = handle_discord_error;
  5776. handlers.joinGame = handle_discord_join;
  5777. handlers.spectateGame = handle_discord_spectate;
  5778. handlers.joinRequest = handle_discord_join_request;
  5779. Discord_Initialize(discord_app_id, &handlers, 0, NULL);
  5780. Discord_UpdateConnection();
  5781. #ifdef _WIN32
  5782. fill_pathname_application_path(full_path, sizeof(full_path));
  5783. if (strstr(args, full_path))
  5784. strlcpy(command, args, sizeof(command));
  5785. else
  5786. {
  5787. path_basedir(full_path);
  5788. strlcpy(command, full_path, sizeof(command));
  5789. strlcat(command, args, sizeof(command));
  5790. }
  5791. #else
  5792. strcpy_literal(command, "sh -c ");
  5793. strlcat(command, args, sizeof(command));
  5794. #endif
  5795. RARCH_LOG("[DISCORD]: Registering startup command: %s\n", command);
  5796. Discord_Register(discord_app_id, command);
  5797. Discord_UpdateConnection();
  5798. discord_st->ready = true;
  5799. }
  5800. #endif
  5801. #ifdef HAVE_NETWORKING
  5802. /**
  5803. * netplay_is_alive:
  5804. * @netplay : pointer to netplay object
  5805. *
  5806. * Checks if input port/index is controlled by netplay or not.
  5807. *
  5808. * Returns: true (1) if alive, otherwise false (0).
  5809. **/
  5810. static bool netplay_is_alive(netplay_t *netplay)
  5811. {
  5812. return (netplay->is_server) ||
  5813. (!netplay->is_server &&
  5814. netplay->self_mode >= NETPLAY_CONNECTION_CONNECTED);
  5815. }
  5816. /**
  5817. * netplay_should_skip:
  5818. * @netplay : pointer to netplay object
  5819. *
  5820. * If we're fast-forward replaying to resync, check if we
  5821. * should actually show frame.
  5822. *
  5823. * Returns: bool (1) if we should skip this frame, otherwise
  5824. * false (0).
  5825. **/
  5826. static bool netplay_should_skip(netplay_t *netplay)
  5827. {
  5828. if (!netplay)
  5829. return false;
  5830. return netplay->is_replay
  5831. && (netplay->self_mode >= NETPLAY_CONNECTION_CONNECTED);
  5832. }
  5833. /**
  5834. * get_self_input_state:
  5835. * @netplay : pointer to netplay object
  5836. *
  5837. * Grab our own input state and send this frame's input state (self and remote)
  5838. * over the network
  5839. *
  5840. * Returns: true (1) if successful, otherwise false (0).
  5841. */
  5842. static bool get_self_input_state(
  5843. bool block_libretro_input,
  5844. netplay_t *netplay)
  5845. {
  5846. unsigned i;
  5847. struct delta_frame *ptr = &netplay->buffer[netplay->self_ptr];
  5848. netplay_input_state_t istate = NULL;
  5849. uint32_t devices, used_devices = 0, devi, dev_type, local_device;
  5850. if (!netplay_delta_frame_ready(netplay, ptr, netplay->self_frame_count))
  5851. return false;
  5852. /* We've already read this frame! */
  5853. if (ptr->have_local)
  5854. return true;
  5855. devices = netplay->self_devices;
  5856. used_devices = 0;
  5857. for (devi = 0; devi < MAX_INPUT_DEVICES; devi++)
  5858. {
  5859. if (!(devices & (1 << devi)))
  5860. continue;
  5861. /* Find an appropriate local device */
  5862. dev_type = netplay->config_devices[devi]&RETRO_DEVICE_MASK;
  5863. for (local_device = 0; local_device < MAX_INPUT_DEVICES; local_device++)
  5864. {
  5865. if (used_devices & (1 << local_device))
  5866. continue;
  5867. if ((netplay->config_devices[local_device]&RETRO_DEVICE_MASK) == dev_type)
  5868. break;
  5869. }
  5870. if (local_device == MAX_INPUT_DEVICES)
  5871. local_device = 0;
  5872. used_devices |= (1 << local_device);
  5873. istate = netplay_input_state_for(&ptr->real_input[devi],
  5874. /* If we're a slave, we write our own input to MAX_CLIENTS to keep it separate */
  5875. (netplay->self_mode==NETPLAY_CONNECTION_SLAVE)?MAX_CLIENTS:netplay->self_client_num,
  5876. netplay_expected_input_size(netplay, 1 << devi),
  5877. true, false);
  5878. if (!istate)
  5879. continue; /* FIXME: More severe? */
  5880. /* First frame we always give zero input since relying on
  5881. * input from first frame screws up when we use -F 0. */
  5882. if ( !block_libretro_input
  5883. && netplay->self_frame_count > 0)
  5884. {
  5885. uint32_t *state = istate->data;
  5886. retro_input_state_t cb = netplay->cbs.state_cb;
  5887. unsigned dtype = netplay->config_devices[devi]&RETRO_DEVICE_MASK;
  5888. switch (dtype)
  5889. {
  5890. case RETRO_DEVICE_ANALOG:
  5891. for (i = 0; i < 2; i++)
  5892. {
  5893. int16_t tmp_x = cb(local_device,
  5894. RETRO_DEVICE_ANALOG, (unsigned)i, 0);
  5895. int16_t tmp_y = cb(local_device,
  5896. RETRO_DEVICE_ANALOG, (unsigned)i, 1);
  5897. state[1 + i] = (uint16_t)tmp_x | (((uint16_t)tmp_y) << 16);
  5898. }
  5899. /* no break */
  5900. case RETRO_DEVICE_JOYPAD:
  5901. for (i = 0; i <= RETRO_DEVICE_ID_JOYPAD_R3; i++)
  5902. {
  5903. int16_t tmp = cb(local_device,
  5904. RETRO_DEVICE_JOYPAD, 0, (unsigned)i);
  5905. state[0] |= tmp ? 1 << i : 0;
  5906. }
  5907. break;
  5908. case RETRO_DEVICE_MOUSE:
  5909. case RETRO_DEVICE_LIGHTGUN:
  5910. {
  5911. int16_t tmp_x = cb(local_device, dtype, 0, 0);
  5912. int16_t tmp_y = cb(local_device, dtype, 0, 1);
  5913. state[1] = (uint16_t)tmp_x | (((uint16_t)tmp_y) << 16);
  5914. for (i = 2;
  5915. i <= (unsigned)((dtype == RETRO_DEVICE_MOUSE) ?
  5916. RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN :
  5917. RETRO_DEVICE_ID_LIGHTGUN_START);
  5918. i++)
  5919. {
  5920. int16_t tmp = cb(local_device, dtype, 0,
  5921. (unsigned) i);
  5922. state[0] |= tmp ? 1 << i : 0;
  5923. }
  5924. break;
  5925. }
  5926. case RETRO_DEVICE_KEYBOARD:
  5927. {
  5928. unsigned key, word = 0, bit = 1;
  5929. for (key = 1; key < NETPLAY_KEY_LAST; key++)
  5930. {
  5931. state[word] |=
  5932. cb(local_device, RETRO_DEVICE_KEYBOARD, 0, netplay_key_ntoh(key)) ?
  5933. (UINT32_C(1) << bit) : 0;
  5934. bit++;
  5935. if (bit >= 32)
  5936. {
  5937. bit = 0;
  5938. word++;
  5939. if (word >= istate->size)
  5940. break;
  5941. }
  5942. }
  5943. break;
  5944. }
  5945. }
  5946. }
  5947. }
  5948. ptr->have_local = true;
  5949. if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
  5950. {
  5951. ptr->have_real[netplay->self_client_num] = true;
  5952. netplay->read_ptr[netplay->self_client_num] = NEXT_PTR(netplay->self_ptr);
  5953. netplay->read_frame_count[netplay->self_client_num] = netplay->self_frame_count + 1;
  5954. }
  5955. /* And send this input to our peers */
  5956. for (i = 0; i < netplay->connections_size; i++)
  5957. {
  5958. struct netplay_connection *connection = &netplay->connections[i];
  5959. if (connection->active && connection->mode >= NETPLAY_CONNECTION_CONNECTED)
  5960. netplay_send_cur_input(netplay, &netplay->connections[i]);
  5961. }
  5962. /* Handle any delayed state changes */
  5963. if (netplay->is_server)
  5964. netplay_delayed_state_change(netplay);
  5965. return true;
  5966. }
  5967. static bool init_netplay_deferred(
  5968. struct rarch_state *p_rarch,
  5969. const char* server, unsigned port)
  5970. {
  5971. if (!string_is_empty(server) && port != 0)
  5972. {
  5973. strlcpy(p_rarch->server_address_deferred, server,
  5974. sizeof(p_rarch->server_address_deferred));
  5975. p_rarch->server_port_deferred = port;
  5976. p_rarch->netplay_client_deferred = true;
  5977. }
  5978. else
  5979. p_rarch->netplay_client_deferred = false;
  5980. return p_rarch->netplay_client_deferred;
  5981. }
  5982. /**
  5983. * netplay_poll:
  5984. * @netplay : pointer to netplay object
  5985. *
  5986. * Polls network to see if we have anything new. If our
  5987. * network buffer is full, we simply have to block
  5988. * for new input data.
  5989. *
  5990. * Returns: true (1) if successful, otherwise false (0).
  5991. **/
  5992. static bool netplay_poll(
  5993. bool block_libretro_input,
  5994. settings_t *settings,
  5995. netplay_t *netplay)
  5996. {
  5997. int res;
  5998. uint32_t client;
  5999. size_t i;
  6000. if (!get_self_input_state(block_libretro_input, netplay))
  6001. goto catastrophe;
  6002. /* If we're not connected, we're done */
  6003. if (netplay->self_mode == NETPLAY_CONNECTION_NONE)
  6004. return true;
  6005. /* Read Netplay input, block if we're configured to stall for input every
  6006. * frame */
  6007. netplay_update_unread_ptr(netplay);
  6008. if (netplay->stateless_mode &&
  6009. (netplay->connected_players>1) &&
  6010. netplay->unread_frame_count <= netplay->run_frame_count)
  6011. res = netplay_poll_net_input(netplay, true);
  6012. else
  6013. res = netplay_poll_net_input(netplay, false);
  6014. if (res == -1)
  6015. goto catastrophe;
  6016. /* Resolve and/or simulate the input if we don't have real input */
  6017. netplay_resolve_input(netplay, netplay->run_ptr, false);
  6018. /* Handle any slaves */
  6019. if (netplay->is_server && netplay->connected_slaves)
  6020. netplay_handle_slaves(netplay);
  6021. netplay_update_unread_ptr(netplay);
  6022. /* Figure out how many frames of input latency we should be using to hide
  6023. * network latency */
  6024. if (netplay->frame_run_time_avg || netplay->stateless_mode)
  6025. {
  6026. /* FIXME: Using fixed 60fps for this calculation */
  6027. unsigned frames_per_frame = netplay->frame_run_time_avg ?
  6028. (16666 / netplay->frame_run_time_avg) :
  6029. 0;
  6030. unsigned frames_ahead = (netplay->run_frame_count > netplay->unread_frame_count) ?
  6031. (netplay->run_frame_count - netplay->unread_frame_count) :
  6032. 0;
  6033. int input_latency_frames_min = settings->uints.netplay_input_latency_frames_min -
  6034. (settings->bools.run_ahead_enabled ? settings->uints.run_ahead_frames : 0);
  6035. int input_latency_frames_max = input_latency_frames_min + settings->uints.netplay_input_latency_frames_range;
  6036. /* Assume we need a couple frames worth of time to actually run the
  6037. * current frame */
  6038. if (frames_per_frame > 2)
  6039. frames_per_frame -= 2;
  6040. else
  6041. frames_per_frame = 0;
  6042. /* Shall we adjust our latency? */
  6043. if (netplay->stateless_mode)
  6044. {
  6045. /* In stateless mode, we adjust up if we're "close" and down if we
  6046. * have a lot of slack */
  6047. if (netplay->input_latency_frames < input_latency_frames_min ||
  6048. (netplay->unread_frame_count == netplay->run_frame_count + 1 &&
  6049. netplay->input_latency_frames < input_latency_frames_max))
  6050. netplay->input_latency_frames++;
  6051. else if (netplay->input_latency_frames > input_latency_frames_max ||
  6052. (netplay->unread_frame_count > netplay->run_frame_count + 2 &&
  6053. netplay->input_latency_frames > input_latency_frames_min))
  6054. netplay->input_latency_frames--;
  6055. }
  6056. else if (netplay->input_latency_frames < input_latency_frames_min ||
  6057. (frames_per_frame < frames_ahead &&
  6058. netplay->input_latency_frames < input_latency_frames_max))
  6059. {
  6060. /* We can't hide this much network latency with replay, so hide some
  6061. * with input latency */
  6062. netplay->input_latency_frames++;
  6063. }
  6064. else if (netplay->input_latency_frames > input_latency_frames_max ||
  6065. (frames_per_frame > frames_ahead + 2 &&
  6066. netplay->input_latency_frames > input_latency_frames_min))
  6067. {
  6068. /* We don't need this much latency (any more) */
  6069. netplay->input_latency_frames--;
  6070. }
  6071. }
  6072. /* If we're stalled, consider unstalling */
  6073. switch (netplay->stall)
  6074. {
  6075. case NETPLAY_STALL_RUNNING_FAST:
  6076. if (netplay->unread_frame_count + NETPLAY_MAX_STALL_FRAMES - 2
  6077. > netplay->self_frame_count)
  6078. {
  6079. netplay->stall = NETPLAY_STALL_NONE;
  6080. for (i = 0; i < netplay->connections_size; i++)
  6081. {
  6082. struct netplay_connection *connection = &netplay->connections[i];
  6083. if (connection->active && connection->stall)
  6084. connection->stall = NETPLAY_STALL_NONE;
  6085. }
  6086. }
  6087. break;
  6088. case NETPLAY_STALL_SPECTATOR_WAIT:
  6089. if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING || netplay->unread_frame_count > netplay->self_frame_count)
  6090. netplay->stall = NETPLAY_STALL_NONE;
  6091. break;
  6092. case NETPLAY_STALL_INPUT_LATENCY:
  6093. /* Just let it recalculate momentarily */
  6094. netplay->stall = NETPLAY_STALL_NONE;
  6095. break;
  6096. case NETPLAY_STALL_SERVER_REQUESTED:
  6097. /* See if the stall is done */
  6098. if (netplay->connections[0].stall_frame == 0)
  6099. {
  6100. /* Stop stalling! */
  6101. netplay->connections[0].stall = NETPLAY_STALL_NONE;
  6102. netplay->stall = NETPLAY_STALL_NONE;
  6103. }
  6104. else
  6105. netplay->connections[0].stall_frame--;
  6106. break;
  6107. case NETPLAY_STALL_NO_CONNECTION:
  6108. /* We certainly haven't fixed this */
  6109. break;
  6110. default: /* not stalling */
  6111. break;
  6112. }
  6113. /* If we're not stalled, consider stalling */
  6114. if (!netplay->stall)
  6115. {
  6116. /* Have we not read enough latency frames? */
  6117. if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING &&
  6118. netplay->connected_players &&
  6119. netplay->run_frame_count + netplay->input_latency_frames > netplay->self_frame_count)
  6120. {
  6121. netplay->stall = NETPLAY_STALL_INPUT_LATENCY;
  6122. netplay->stall_time = 0;
  6123. }
  6124. /* Are we too far ahead? */
  6125. if (netplay->unread_frame_count + NETPLAY_MAX_STALL_FRAMES
  6126. <= netplay->self_frame_count)
  6127. {
  6128. netplay->stall = NETPLAY_STALL_RUNNING_FAST;
  6129. netplay->stall_time = cpu_features_get_time_usec();
  6130. /* Figure out who to blame */
  6131. if (netplay->is_server)
  6132. {
  6133. for (client = 1; client < MAX_CLIENTS; client++)
  6134. {
  6135. struct netplay_connection *connection;
  6136. if (!(netplay->connected_players & (1 << client)))
  6137. continue;
  6138. if (netplay->read_frame_count[client] > netplay->unread_frame_count)
  6139. continue;
  6140. connection = &netplay->connections[client-1];
  6141. if (connection->active &&
  6142. connection->mode == NETPLAY_CONNECTION_PLAYING)
  6143. {
  6144. connection->stall = NETPLAY_STALL_RUNNING_FAST;
  6145. connection->stall_time = netplay->stall_time;
  6146. }
  6147. }
  6148. }
  6149. }
  6150. /* If we're a spectator, are we ahead at all? */
  6151. if (!netplay->is_server &&
  6152. (netplay->self_mode == NETPLAY_CONNECTION_SPECTATING ||
  6153. netplay->self_mode == NETPLAY_CONNECTION_SLAVE) &&
  6154. netplay->unread_frame_count <= netplay->self_frame_count)
  6155. {
  6156. netplay->stall = NETPLAY_STALL_SPECTATOR_WAIT;
  6157. netplay->stall_time = cpu_features_get_time_usec();
  6158. }
  6159. }
  6160. /* If we're stalling, consider disconnection */
  6161. if (netplay->stall && netplay->stall_time)
  6162. {
  6163. retro_time_t now = cpu_features_get_time_usec();
  6164. /* Don't stall out while they're paused */
  6165. if (netplay->remote_paused)
  6166. netplay->stall_time = now;
  6167. else if (now - netplay->stall_time >=
  6168. (netplay->is_server ? MAX_SERVER_STALL_TIME_USEC :
  6169. MAX_CLIENT_STALL_TIME_USEC))
  6170. {
  6171. /* Stalled out! */
  6172. if (netplay->is_server)
  6173. {
  6174. bool fixed = false;
  6175. for (i = 0; i < netplay->connections_size; i++)
  6176. {
  6177. struct netplay_connection *connection = &netplay->connections[i];
  6178. if (connection->active &&
  6179. connection->mode == NETPLAY_CONNECTION_PLAYING &&
  6180. connection->stall)
  6181. {
  6182. netplay_hangup(netplay, connection);
  6183. fixed = true;
  6184. }
  6185. }
  6186. if (fixed)
  6187. {
  6188. /* Not stalled now :) */
  6189. netplay->stall = NETPLAY_STALL_NONE;
  6190. return true;
  6191. }
  6192. }
  6193. else
  6194. goto catastrophe;
  6195. return false;
  6196. }
  6197. }
  6198. return true;
  6199. catastrophe:
  6200. for (i = 0; i < netplay->connections_size; i++)
  6201. netplay_hangup(netplay, &netplay->connections[i]);
  6202. return false;
  6203. }
  6204. /**
  6205. * input_poll_net
  6206. *
  6207. * Poll the network if necessary.
  6208. */
  6209. void input_poll_net(void)
  6210. {
  6211. struct rarch_state *p_rarch = &rarch_st;
  6212. netplay_t *netplay = p_rarch->netplay_data;
  6213. if (!netplay_should_skip(netplay) && netplay && netplay->can_poll)
  6214. {
  6215. netplay->can_poll = false;
  6216. netplay_poll(
  6217. p_rarch->input_driver_block_libretro_input,
  6218. p_rarch->configuration_settings,
  6219. netplay);
  6220. }
  6221. }
  6222. /* Netplay polling callbacks */
  6223. static void video_frame_net(const void *data, unsigned width,
  6224. unsigned height, size_t pitch)
  6225. {
  6226. struct rarch_state *p_rarch = &rarch_st;
  6227. netplay_t *netplay = p_rarch->netplay_data;
  6228. if (!netplay_should_skip(netplay))
  6229. netplay->cbs.frame_cb(data, width, height, pitch);
  6230. }
  6231. static void audio_sample_net(int16_t left, int16_t right)
  6232. {
  6233. struct rarch_state *p_rarch = &rarch_st;
  6234. netplay_t *netplay = p_rarch->netplay_data;
  6235. if (!netplay_should_skip(netplay) && !netplay->stall)
  6236. netplay->cbs.sample_cb(left, right);
  6237. }
  6238. static size_t audio_sample_batch_net(const int16_t *data, size_t frames)
  6239. {
  6240. struct rarch_state *p_rarch = &rarch_st;
  6241. netplay_t *netplay = p_rarch->netplay_data;
  6242. if (!netplay_should_skip(netplay) && !netplay->stall)
  6243. return netplay->cbs.sample_batch_cb(data, frames);
  6244. return frames;
  6245. }
  6246. static int16_t netplay_input_state(netplay_t *netplay,
  6247. unsigned port, unsigned device,
  6248. unsigned idx, unsigned id)
  6249. {
  6250. struct delta_frame *delta;
  6251. netplay_input_state_t istate;
  6252. const uint32_t *curr_input_state = NULL;
  6253. size_t ptr =
  6254. netplay->is_replay
  6255. ? netplay->replay_ptr
  6256. : netplay->run_ptr;
  6257. if (port >= MAX_INPUT_DEVICES)
  6258. return 0;
  6259. /* If the port doesn't seem to correspond to the device, "correct" it. This
  6260. * is common with devices that typically only have one instance, such as
  6261. * keyboards, mice and lightguns. */
  6262. if (device != RETRO_DEVICE_JOYPAD &&
  6263. (netplay->config_devices[port]&RETRO_DEVICE_MASK) != device)
  6264. {
  6265. for (port = 0; port < MAX_INPUT_DEVICES; port++)
  6266. {
  6267. if ((netplay->config_devices[port]&RETRO_DEVICE_MASK) == device)
  6268. break;
  6269. }
  6270. if (port == MAX_INPUT_DEVICES)
  6271. return 0;
  6272. }
  6273. delta = &netplay->buffer[ptr];
  6274. istate = delta->resolved_input[port];
  6275. if (!istate || !istate->used || istate->size == 0)
  6276. return 0;
  6277. curr_input_state = istate->data;
  6278. switch (device)
  6279. {
  6280. case RETRO_DEVICE_JOYPAD:
  6281. if (id == RETRO_DEVICE_ID_JOYPAD_MASK)
  6282. return curr_input_state[0];
  6283. return ((1 << id) & curr_input_state[0]) ? 1 : 0;
  6284. case RETRO_DEVICE_ANALOG:
  6285. if (istate->size == 3)
  6286. {
  6287. uint32_t state = curr_input_state[1 + idx];
  6288. return (int16_t)(uint16_t)(state >> (id * 16));
  6289. }
  6290. break;
  6291. case RETRO_DEVICE_MOUSE:
  6292. case RETRO_DEVICE_LIGHTGUN:
  6293. if (istate->size == 2)
  6294. {
  6295. if (id <= RETRO_DEVICE_ID_MOUSE_Y)
  6296. return (int16_t)(uint16_t)(curr_input_state[1] >> (id * 16));
  6297. return ((1 << id) & curr_input_state[0]) ? 1 : 0;
  6298. }
  6299. break;
  6300. case RETRO_DEVICE_KEYBOARD:
  6301. {
  6302. unsigned key = netplay_key_hton(id);
  6303. if (key != NETPLAY_KEY_UNKNOWN)
  6304. {
  6305. unsigned word = key / 32;
  6306. unsigned bit = key % 32;
  6307. if (word <= istate->size)
  6308. return ((UINT32_C(1) << bit) & curr_input_state[word]) ? 1 : 0;
  6309. }
  6310. }
  6311. break;
  6312. default:
  6313. break;
  6314. }
  6315. return 0;
  6316. }
  6317. static void netplay_announce_cb(retro_task_t *task,
  6318. void *task_data, void *user_data, const char *error)
  6319. {
  6320. if (task_data)
  6321. {
  6322. unsigned i, ip_len, port_len;
  6323. struct rarch_state *p_rarch = &rarch_st;
  6324. http_transfer_data_t *data = (http_transfer_data_t*)task_data;
  6325. struct netplay_room *host_room = &p_rarch->netplay_host_room;
  6326. struct string_list *lines = NULL;
  6327. char *mitm_ip = NULL;
  6328. char *mitm_port = NULL;
  6329. char *buf = NULL;
  6330. char *host_string = NULL;
  6331. if (data->len == 0)
  6332. {
  6333. free(task_data);
  6334. return;
  6335. }
  6336. buf = (char*)calloc(1, data->len + 1);
  6337. memcpy(buf, data->data, data->len);
  6338. lines = string_split(buf, "\n");
  6339. if (lines->size == 0)
  6340. {
  6341. string_list_free(lines);
  6342. free(buf);
  6343. free(task_data);
  6344. return;
  6345. }
  6346. memset(host_room, 0, sizeof(*host_room));
  6347. for (i = 0; i < lines->size; i++)
  6348. {
  6349. const char *line = lines->elems[i].data;
  6350. if (!string_is_empty(line))
  6351. {
  6352. struct string_list *kv = string_split(line, "=");
  6353. const char *key = NULL;
  6354. const char *val = NULL;
  6355. if (!kv)
  6356. continue;
  6357. if (kv->size != 2)
  6358. {
  6359. string_list_free(kv);
  6360. continue;
  6361. }
  6362. key = kv->elems[0].data;
  6363. val = kv->elems[1].data;
  6364. if (string_is_equal(key, "id"))
  6365. sscanf(val, "%i", &host_room->id);
  6366. if (string_is_equal(key, "username"))
  6367. strlcpy(host_room->nickname, val, sizeof(host_room->nickname));
  6368. if (string_is_equal(key, "ip"))
  6369. strlcpy(host_room->address, val, sizeof(host_room->address));
  6370. if (string_is_equal(key, "mitm_ip"))
  6371. {
  6372. mitm_ip = strdup(val);
  6373. strlcpy(host_room->mitm_address, val, sizeof(host_room->mitm_address));
  6374. }
  6375. if (string_is_equal(key, "port"))
  6376. sscanf(val, "%i", &host_room->port);
  6377. if (string_is_equal(key, "mitm_port"))
  6378. {
  6379. mitm_port = strdup(val);
  6380. sscanf(mitm_port, "%i", &host_room->mitm_port);
  6381. }
  6382. if (string_is_equal(key, "core_name"))
  6383. strlcpy(host_room->corename, val, sizeof(host_room->corename));
  6384. if (string_is_equal(key, "frontend"))
  6385. strlcpy(host_room->frontend, val, sizeof(host_room->frontend));
  6386. if (string_is_equal(key, "core_version"))
  6387. strlcpy(host_room->coreversion, val, sizeof(host_room->coreversion));
  6388. if (string_is_equal(key, "game_name"))
  6389. strlcpy(host_room->gamename, val, sizeof(host_room->gamename));
  6390. if (string_is_equal(key, "game_crc"))
  6391. sscanf(val, "%08d", &host_room->gamecrc);
  6392. if (string_is_equal(key, "host_method"))
  6393. sscanf(val, "%i", &host_room->host_method);
  6394. if (string_is_equal(key, "has_password"))
  6395. {
  6396. if (string_is_equal_noncase(val, "true") || string_is_equal(val, "1"))
  6397. host_room->has_password = true;
  6398. else
  6399. host_room->has_password = false;
  6400. }
  6401. if (string_is_equal(key, "has_spectate_password"))
  6402. {
  6403. if (string_is_equal_noncase(val, "true") || string_is_equal(val, "1"))
  6404. host_room->has_spectate_password = true;
  6405. else
  6406. host_room->has_spectate_password = false;
  6407. }
  6408. if (string_is_equal(key, "fixed"))
  6409. {
  6410. if (string_is_equal_noncase(val, "true") || string_is_equal(val, "1"))
  6411. host_room->fixed = true;
  6412. else
  6413. host_room->fixed = false;
  6414. }
  6415. if (string_is_equal(key, "retroarch_version"))
  6416. strlcpy(host_room->retroarch_version, val, sizeof(host_room->retroarch_version));
  6417. if (string_is_equal(key, "country"))
  6418. strlcpy(host_room->country, val, sizeof(host_room->country));
  6419. string_list_free(kv);
  6420. }
  6421. }
  6422. if (mitm_ip && mitm_port)
  6423. {
  6424. ip_len = (unsigned)strlen(mitm_ip);
  6425. port_len = (unsigned)strlen(mitm_port);
  6426. /* Enable Netplay client mode */
  6427. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
  6428. {
  6429. command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
  6430. p_rarch->is_mitm = true;
  6431. host_room->host_method = NETPLAY_HOST_METHOD_MITM;
  6432. }
  6433. netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
  6434. host_string = (char*)calloc(1, ip_len + port_len + 2);
  6435. memcpy(host_string, mitm_ip, ip_len);
  6436. memcpy(host_string + ip_len, "|", 1);
  6437. memcpy(host_string + ip_len + 1, mitm_port, port_len);
  6438. /* Enable Netplay */
  6439. command_event(CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED, (void*)host_string);
  6440. command_event(CMD_EVENT_NETPLAY_INIT, (void*)host_string);
  6441. free(host_string);
  6442. }
  6443. #ifdef HAVE_DISCORD
  6444. if (discord_is_inited)
  6445. {
  6446. discord_userdata_t userdata;
  6447. userdata.status = DISCORD_PRESENCE_NETPLAY_HOSTING;
  6448. command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
  6449. }
  6450. #endif
  6451. string_list_free(lines);
  6452. free(buf);
  6453. free(task_data);
  6454. if (mitm_ip)
  6455. free(mitm_ip);
  6456. if (mitm_port)
  6457. free(mitm_port);
  6458. }
  6459. }
  6460. static void netplay_announce(struct rarch_state *p_rarch)
  6461. {
  6462. char buf[4600];
  6463. char frontend_architecture[PATH_MAX_LENGTH];
  6464. char frontend_architecture_tmp[32];
  6465. const frontend_ctx_driver_t
  6466. *frontend_drv = NULL;
  6467. char url[2048] = "http://lobby.libretro.com/add/";
  6468. char *username = NULL;
  6469. char *corename = NULL;
  6470. char *gamename = NULL;
  6471. char *subsystemname = NULL;
  6472. char *coreversion = NULL;
  6473. char *frontend_ident = NULL;
  6474. settings_t *settings = p_rarch->configuration_settings;
  6475. struct retro_system_info *system = &p_rarch->runloop_system.info;
  6476. uint32_t content_crc = content_get_crc();
  6477. struct string_list *subsystem = path_get_subsystem_list();
  6478. buf[0] = '\0';
  6479. if (subsystem)
  6480. {
  6481. unsigned i;
  6482. for (i = 0; i < subsystem->size; i++)
  6483. {
  6484. strlcat(buf, path_basename(subsystem->elems[i].data), sizeof(buf));
  6485. if (i < subsystem->size - 1)
  6486. strlcat(buf, "|", sizeof(buf));
  6487. }
  6488. net_http_urlencode(&gamename, buf);
  6489. net_http_urlencode(&subsystemname, path_get(RARCH_PATH_SUBSYSTEM));
  6490. content_crc = 0;
  6491. }
  6492. else
  6493. {
  6494. net_http_urlencode(&gamename,
  6495. !string_is_empty(path_basename(path_get(RARCH_PATH_BASENAME))) ?
  6496. path_basename(path_get(RARCH_PATH_BASENAME)) : "N/A");
  6497. net_http_urlencode(&subsystemname, "N/A");
  6498. }
  6499. frontend_drv =
  6500. (const frontend_ctx_driver_t*)frontend_driver_get_cpu_architecture_str(
  6501. frontend_architecture_tmp, sizeof(frontend_architecture_tmp));
  6502. strlcpy(frontend_architecture, frontend_drv->ident,
  6503. sizeof(frontend_architecture));
  6504. strlcat(frontend_architecture, " ",
  6505. sizeof(frontend_architecture));
  6506. strlcat(frontend_architecture, frontend_architecture_tmp,
  6507. sizeof(frontend_architecture));
  6508. #ifdef HAVE_DISCORD
  6509. if (discord_is_ready())
  6510. net_http_urlencode(&username, discord_get_own_username(p_rarch));
  6511. else
  6512. #endif
  6513. net_http_urlencode(&username, settings->paths.username);
  6514. net_http_urlencode(&corename, system->library_name);
  6515. net_http_urlencode(&coreversion, system->library_version);
  6516. net_http_urlencode(&frontend_ident, frontend_architecture);
  6517. buf[0] = '\0';
  6518. snprintf(buf, sizeof(buf), "username=%s&core_name=%s&core_version=%s&"
  6519. "game_name=%s&game_crc=%08X&port=%d&mitm_server=%s"
  6520. "&has_password=%d&has_spectate_password=%d&force_mitm=%d"
  6521. "&retroarch_version=%s&frontend=%s&subsystem_name=%s",
  6522. username, corename, coreversion, gamename, content_crc,
  6523. settings->uints.netplay_port,
  6524. settings->arrays.netplay_mitm_server,
  6525. *settings->paths.netplay_password ? 1 : 0,
  6526. *settings->paths.netplay_spectate_password ? 1 : 0,
  6527. settings->bools.netplay_use_mitm_server,
  6528. PACKAGE_VERSION, frontend_architecture, subsystemname);
  6529. task_push_http_post_transfer(url, buf, true, NULL,
  6530. netplay_announce_cb, NULL);
  6531. if (username)
  6532. free(username);
  6533. if (corename)
  6534. free(corename);
  6535. if (gamename)
  6536. free(gamename);
  6537. if (coreversion)
  6538. free(coreversion);
  6539. if (frontend_ident)
  6540. free(frontend_ident);
  6541. }
  6542. static int16_t input_state_net(unsigned port, unsigned device,
  6543. unsigned idx, unsigned id)
  6544. {
  6545. struct rarch_state *p_rarch = &rarch_st;
  6546. netplay_t *netplay = p_rarch->netplay_data;
  6547. if (netplay)
  6548. {
  6549. if (netplay_is_alive(netplay))
  6550. return netplay_input_state(netplay, port, device, idx, id);
  6551. return netplay->cbs.state_cb(port, device, idx, id);
  6552. }
  6553. return 0;
  6554. }
  6555. /* ^^^ Netplay polling callbacks */
  6556. /**
  6557. * netplay_frontend_paused
  6558. * @netplay : pointer to netplay object
  6559. * @paused : true if frontend is paused
  6560. *
  6561. * Inform Netplay of the frontend's pause state (paused or otherwise)
  6562. */
  6563. static void netplay_frontend_paused(netplay_t *netplay, bool paused)
  6564. {
  6565. size_t i;
  6566. uint32_t paused_ct = 0;
  6567. netplay->local_paused = paused;
  6568. /* Communicating this is a bit odd: If exactly one other connection is
  6569. * paused, then we must tell them that we're unpaused, as from their
  6570. * perspective we are. If more than one other connection is paused, then our
  6571. * status as proxy means we are NOT unpaused to either of them. */
  6572. for (i = 0; i < netplay->connections_size; i++)
  6573. {
  6574. struct netplay_connection *connection = &netplay->connections[i];
  6575. if (connection->active && connection->paused)
  6576. paused_ct++;
  6577. }
  6578. if (paused_ct > 1)
  6579. return;
  6580. /* Send our unpaused status. Must send manually because we must immediately
  6581. * flush the buffer: If we're paused, we won't be polled. */
  6582. for (i = 0; i < netplay->connections_size; i++)
  6583. {
  6584. struct netplay_connection *connection = &netplay->connections[i];
  6585. if ( connection->active
  6586. && connection->mode >= NETPLAY_CONNECTION_CONNECTED)
  6587. {
  6588. if (paused)
  6589. netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_PAUSE,
  6590. netplay->nick, NETPLAY_NICK_LEN);
  6591. else
  6592. netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_RESUME,
  6593. NULL, 0);
  6594. /* We're not going to be polled, so we need to
  6595. * flush this command now */
  6596. netplay_send_flush(&connection->send_packet_buffer,
  6597. connection->fd, true);
  6598. }
  6599. }
  6600. }
  6601. /**
  6602. * netplay_disconnect
  6603. * @netplay : pointer to netplay object
  6604. *
  6605. * Disconnect netplay.
  6606. *
  6607. * Returns: true (1) if successful. At present, cannot fail.
  6608. **/
  6609. static void netplay_disconnect(
  6610. struct rarch_state *p_rarch,
  6611. netplay_t *netplay)
  6612. {
  6613. size_t i;
  6614. for (i = 0; i < netplay->connections_size; i++)
  6615. netplay_hangup(netplay, &netplay->connections[i]);
  6616. deinit_netplay(p_rarch);
  6617. #ifdef HAVE_DISCORD
  6618. if (discord_is_inited)
  6619. {
  6620. discord_userdata_t userdata;
  6621. userdata.status = DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED;
  6622. command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
  6623. }
  6624. #endif
  6625. }
  6626. /**
  6627. * netplay_pre_frame:
  6628. * @netplay : pointer to netplay object
  6629. *
  6630. * Pre-frame for Netplay.
  6631. * Call this before running retro_run().
  6632. *
  6633. * Returns: true (1) if the frontend is cleared to emulate the frame, false (0)
  6634. * if we're stalled or paused
  6635. **/
  6636. static bool netplay_pre_frame(struct rarch_state *p_rarch,
  6637. netplay_t *netplay)
  6638. {
  6639. bool sync_stalled = false;
  6640. settings_t *settings = p_rarch->configuration_settings;
  6641. retro_assert(netplay);
  6642. if (settings->bools.netplay_public_announce)
  6643. {
  6644. p_rarch->reannounce++;
  6645. if (
  6646. (netplay->is_server || p_rarch->is_mitm) &&
  6647. (p_rarch->reannounce % 300 == 0))
  6648. netplay_announce(p_rarch);
  6649. }
  6650. /* Make sure that if announcement is turned on mid-game, it gets announced */
  6651. else
  6652. p_rarch->reannounce = -1;
  6653. /* FIXME: This is an ugly way to learn we're not paused anymore */
  6654. if (netplay->local_paused)
  6655. if (netplay->local_paused != false)
  6656. netplay_frontend_paused(netplay, false);
  6657. /* Are we ready now? */
  6658. if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION)
  6659. netplay_try_init_serialization(netplay);
  6660. if (netplay->is_server && !settings->bools.netplay_use_mitm_server)
  6661. {
  6662. /* Advertise our server */
  6663. netplay_lan_ad_server(netplay);
  6664. /* NAT traversal if applicable */
  6665. if (netplay->nat_traversal &&
  6666. !netplay->nat_traversal_task_oustanding &&
  6667. netplay->nat_traversal_state.request_outstanding &&
  6668. !netplay->nat_traversal_state.have_inet4)
  6669. {
  6670. struct timeval tmptv = {0};
  6671. fd_set fds = netplay->nat_traversal_state.fds;
  6672. if (socket_select(netplay->nat_traversal_state.nfds, &fds, NULL, NULL, &tmptv) > 0)
  6673. natt_read(&netplay->nat_traversal_state);
  6674. #ifndef HAVE_SOCKET_LEGACY
  6675. if (!netplay->nat_traversal_state.request_outstanding ||
  6676. netplay->nat_traversal_state.have_inet4)
  6677. netplay_announce_nat_traversal(netplay);
  6678. #endif
  6679. }
  6680. }
  6681. sync_stalled = !netplay_sync_pre_frame(netplay);
  6682. /* If we're disconnected, deinitialize */
  6683. if (!netplay->is_server && !netplay->connections[0].active)
  6684. {
  6685. netplay_disconnect(p_rarch, netplay);
  6686. return true;
  6687. }
  6688. if (sync_stalled ||
  6689. ((!netplay->is_server || (netplay->connected_players>1)) &&
  6690. (netplay->stall || netplay->remote_paused)))
  6691. {
  6692. /* We may have received data even if we're stalled, so run post-frame
  6693. * sync */
  6694. netplay_sync_post_frame(netplay, true);
  6695. return false;
  6696. }
  6697. return true;
  6698. }
  6699. /**
  6700. * netplay_post_frame:
  6701. * @netplay : pointer to netplay object
  6702. *
  6703. * Post-frame for Netplay.
  6704. * We check if we have new input and replay from recorded input.
  6705. * Call this after running retro_run().
  6706. **/
  6707. static void netplay_post_frame(
  6708. struct rarch_state *p_rarch,
  6709. netplay_t *netplay)
  6710. {
  6711. size_t i;
  6712. retro_assert(netplay);
  6713. netplay_update_unread_ptr(netplay);
  6714. netplay_sync_post_frame(netplay, false);
  6715. for (i = 0; i < netplay->connections_size; i++)
  6716. {
  6717. struct netplay_connection *connection = &netplay->connections[i];
  6718. if (connection->active &&
  6719. !netplay_send_flush(&connection->send_packet_buffer, connection->fd,
  6720. false))
  6721. netplay_hangup(netplay, connection);
  6722. }
  6723. /* If we're disconnected, deinitialize */
  6724. if (!netplay->is_server && !netplay->connections[0].active)
  6725. netplay_disconnect(p_rarch, netplay);
  6726. }
  6727. /**
  6728. * netplay_force_future
  6729. * @netplay : pointer to netplay object
  6730. *
  6731. * Force netplay to ignore all past input, typically because we've just loaded
  6732. * a state or reset.
  6733. */
  6734. static void netplay_force_future(netplay_t *netplay)
  6735. {
  6736. /* Wherever we're inputting, that's where we consider our state to be loaded */
  6737. netplay->run_ptr = netplay->self_ptr;
  6738. netplay->run_frame_count = netplay->self_frame_count;
  6739. /* We need to ignore any intervening data from the other side,
  6740. * and never rewind past this */
  6741. netplay_update_unread_ptr(netplay);
  6742. if (netplay->unread_frame_count < netplay->run_frame_count)
  6743. {
  6744. uint32_t client;
  6745. for (client = 0; client < MAX_CLIENTS; client++)
  6746. {
  6747. if (!(netplay->connected_players & (1 << client)))
  6748. continue;
  6749. if (netplay->read_frame_count[client] < netplay->run_frame_count)
  6750. {
  6751. netplay->read_ptr[client] = netplay->run_ptr;
  6752. netplay->read_frame_count[client] = netplay->run_frame_count;
  6753. }
  6754. }
  6755. if (netplay->server_frame_count < netplay->run_frame_count)
  6756. {
  6757. netplay->server_ptr = netplay->run_ptr;
  6758. netplay->server_frame_count = netplay->run_frame_count;
  6759. }
  6760. netplay_update_unread_ptr(netplay);
  6761. }
  6762. if (netplay->other_frame_count < netplay->run_frame_count)
  6763. {
  6764. netplay->other_ptr = netplay->run_ptr;
  6765. netplay->other_frame_count = netplay->run_frame_count;
  6766. }
  6767. }
  6768. /**
  6769. * netplay_send_savestate
  6770. * @netplay : pointer to netplay object
  6771. * @serial_info : the savestate being loaded
  6772. * @cx : compression type
  6773. * @z : compression backend to use
  6774. *
  6775. * Send a loaded savestate to those connected peers using the given compression
  6776. * scheme.
  6777. */
  6778. static void netplay_send_savestate(netplay_t *netplay,
  6779. retro_ctx_serialize_info_t *serial_info, uint32_t cx,
  6780. struct compression_transcoder *z)
  6781. {
  6782. uint32_t header[4];
  6783. uint32_t rd, wn;
  6784. size_t i;
  6785. /* Compress it */
  6786. z->compression_backend->set_in(z->compression_stream,
  6787. (const uint8_t*)serial_info->data_const, (uint32_t)serial_info->size);
  6788. z->compression_backend->set_out(z->compression_stream,
  6789. netplay->zbuffer, (uint32_t)netplay->zbuffer_size);
  6790. if (!z->compression_backend->trans(z->compression_stream, true, &rd,
  6791. &wn, NULL))
  6792. {
  6793. /* Catastrophe! */
  6794. for (i = 0; i < netplay->connections_size; i++)
  6795. netplay_hangup(netplay, &netplay->connections[i]);
  6796. return;
  6797. }
  6798. /* Send it to relevant peers */
  6799. header[0] = htonl(NETPLAY_CMD_LOAD_SAVESTATE);
  6800. header[1] = htonl(wn + 2*sizeof(uint32_t));
  6801. header[2] = htonl(netplay->run_frame_count);
  6802. header[3] = htonl(serial_info->size);
  6803. for (i = 0; i < netplay->connections_size; i++)
  6804. {
  6805. struct netplay_connection *connection = &netplay->connections[i];
  6806. if (!connection->active ||
  6807. connection->mode < NETPLAY_CONNECTION_CONNECTED ||
  6808. connection->compression_supported != cx) continue;
  6809. if (!netplay_send(&connection->send_packet_buffer, connection->fd, header,
  6810. sizeof(header)) ||
  6811. !netplay_send(&connection->send_packet_buffer, connection->fd,
  6812. netplay->zbuffer, wn))
  6813. netplay_hangup(netplay, connection);
  6814. }
  6815. }
  6816. /**
  6817. * netplay_load_savestate
  6818. * @netplay : pointer to netplay object
  6819. * @serial_info : the savestate being loaded, NULL means
  6820. * "load it yourself"
  6821. * @save : Whether to save the provided serial_info
  6822. * into the frame buffer
  6823. *
  6824. * Inform Netplay of a savestate load and send it to the other side
  6825. **/
  6826. void netplay_load_savestate(netplay_t *netplay,
  6827. retro_ctx_serialize_info_t *serial_info, bool save)
  6828. {
  6829. retro_ctx_serialize_info_t tmp_serial_info;
  6830. netplay_force_future(netplay);
  6831. /* Record it in our own buffer */
  6832. if (save || !serial_info)
  6833. {
  6834. if (netplay_delta_frame_ready(netplay,
  6835. &netplay->buffer[netplay->run_ptr], netplay->run_frame_count))
  6836. {
  6837. if (!serial_info)
  6838. {
  6839. tmp_serial_info.size = netplay->state_size;
  6840. tmp_serial_info.data = netplay->buffer[netplay->run_ptr].state;
  6841. if (!core_serialize(&tmp_serial_info))
  6842. return;
  6843. tmp_serial_info.data_const = tmp_serial_info.data;
  6844. serial_info = &tmp_serial_info;
  6845. }
  6846. else
  6847. {
  6848. if (serial_info->size <= netplay->state_size)
  6849. memcpy(netplay->buffer[netplay->run_ptr].state,
  6850. serial_info->data_const, serial_info->size);
  6851. }
  6852. }
  6853. /* FIXME: This is a critical failure! */
  6854. else
  6855. return;
  6856. }
  6857. /* Don't send it if we're expected to be desynced */
  6858. if (netplay->desync)
  6859. return;
  6860. /* If we can't send it to the peer, loading a state was a bad idea */
  6861. if (netplay->quirks & (
  6862. NETPLAY_QUIRK_NO_SAVESTATES
  6863. | NETPLAY_QUIRK_NO_TRANSMISSION))
  6864. return;
  6865. /* Send this to every peer */
  6866. if (netplay->compress_nil.compression_backend)
  6867. netplay_send_savestate(netplay, serial_info, 0, &netplay->compress_nil);
  6868. if (netplay->compress_zlib.compression_backend)
  6869. netplay_send_savestate(netplay, serial_info, NETPLAY_COMPRESSION_ZLIB,
  6870. &netplay->compress_zlib);
  6871. }
  6872. /**
  6873. * netplay_core_reset
  6874. * @netplay : pointer to netplay object
  6875. *
  6876. * Indicate that the core has been reset to netplay peers
  6877. **/
  6878. static void netplay_core_reset(netplay_t *netplay)
  6879. {
  6880. size_t i;
  6881. uint32_t cmd[3];
  6882. /* Ignore past input */
  6883. netplay_force_future(netplay);
  6884. /* Request that our peers reset */
  6885. cmd[0] = htonl(NETPLAY_CMD_RESET);
  6886. cmd[1] = htonl(sizeof(uint32_t));
  6887. cmd[2] = htonl(netplay->self_frame_count);
  6888. for (i = 0; i < netplay->connections_size; i++)
  6889. {
  6890. struct netplay_connection *connection = &netplay->connections[i];
  6891. if (!connection->active ||
  6892. connection->mode < NETPLAY_CONNECTION_CONNECTED) continue;
  6893. if (!netplay_send(&connection->send_packet_buffer, connection->fd, cmd,
  6894. sizeof(cmd)))
  6895. netplay_hangup(netplay, connection);
  6896. }
  6897. }
  6898. /**
  6899. * netplay_settings_share_mode
  6900. *
  6901. * Get the preferred share mode
  6902. */
  6903. uint8_t netplay_settings_share_mode(
  6904. unsigned share_digital, unsigned share_analog)
  6905. {
  6906. if (share_digital || share_analog)
  6907. {
  6908. uint8_t share_mode = 0;
  6909. switch (share_digital)
  6910. {
  6911. case RARCH_NETPLAY_SHARE_DIGITAL_OR:
  6912. share_mode |= NETPLAY_SHARE_DIGITAL_OR;
  6913. break;
  6914. case RARCH_NETPLAY_SHARE_DIGITAL_XOR:
  6915. share_mode |= NETPLAY_SHARE_DIGITAL_XOR;
  6916. break;
  6917. case RARCH_NETPLAY_SHARE_DIGITAL_VOTE:
  6918. share_mode |= NETPLAY_SHARE_DIGITAL_VOTE;
  6919. break;
  6920. default:
  6921. share_mode |= NETPLAY_SHARE_NO_PREFERENCE;
  6922. }
  6923. switch (share_analog)
  6924. {
  6925. case RARCH_NETPLAY_SHARE_ANALOG_MAX:
  6926. share_mode |= NETPLAY_SHARE_ANALOG_MAX;
  6927. break;
  6928. case RARCH_NETPLAY_SHARE_ANALOG_AVERAGE:
  6929. share_mode |= NETPLAY_SHARE_ANALOG_AVERAGE;
  6930. break;
  6931. default:
  6932. share_mode |= NETPLAY_SHARE_NO_PREFERENCE;
  6933. }
  6934. return share_mode;
  6935. }
  6936. return 0;
  6937. }
  6938. /**
  6939. * netplay_toggle_play_spectate
  6940. *
  6941. * Toggle between play mode and spectate mode
  6942. */
  6943. static void netplay_toggle_play_spectate(netplay_t *netplay)
  6944. {
  6945. switch (netplay->self_mode)
  6946. {
  6947. case NETPLAY_CONNECTION_PLAYING:
  6948. case NETPLAY_CONNECTION_SLAVE:
  6949. /* Switch to spectator mode immediately */
  6950. netplay->self_mode = NETPLAY_CONNECTION_SPECTATING;
  6951. netplay_cmd_mode(netplay, NETPLAY_CONNECTION_SPECTATING);
  6952. break;
  6953. case NETPLAY_CONNECTION_SPECTATING:
  6954. /* Switch only after getting permission */
  6955. netplay_cmd_mode(netplay, NETPLAY_CONNECTION_PLAYING);
  6956. break;
  6957. default:
  6958. break;
  6959. }
  6960. }
  6961. static void deinit_netplay(struct rarch_state *p_rarch)
  6962. {
  6963. if (p_rarch->netplay_data)
  6964. {
  6965. netplay_free(p_rarch->netplay_data);
  6966. p_rarch->netplay_enabled = false;
  6967. p_rarch->netplay_is_client = false;
  6968. p_rarch->is_mitm = false;
  6969. }
  6970. p_rarch->netplay_data = NULL;
  6971. core_unset_netplay_callbacks();
  6972. }
  6973. /**
  6974. * init_netplay
  6975. * @direct_host : Host to connect to directly, if applicable (client only)
  6976. * @server : server address to connect to (client only)
  6977. * @port : TCP port to host on/connect to
  6978. *
  6979. * Initializes netplay.
  6980. *
  6981. * If netplay is already initialized, will return false (0).
  6982. *
  6983. * Returns: true (1) if successful, otherwise false (0).
  6984. **/
  6985. static bool init_netplay(
  6986. struct rarch_state *p_rarch,
  6987. void *direct_host,
  6988. const char *server, unsigned port)
  6989. {
  6990. struct retro_callbacks cbs = {0};
  6991. settings_t *settings = p_rarch->configuration_settings;
  6992. uint64_t serialization_quirks = 0;
  6993. uint64_t quirks = 0;
  6994. bool _netplay_is_client = p_rarch->netplay_is_client;
  6995. bool _netplay_enabled = p_rarch->netplay_enabled;
  6996. if (!_netplay_enabled)
  6997. return false;
  6998. core_set_default_callbacks(&cbs);
  6999. if (!core_set_netplay_callbacks())
  7000. return false;
  7001. /* Map the core's quirks to our quirks */
  7002. serialization_quirks = core_serialization_quirks();
  7003. /* Quirks we don't support! Just disable everything. */
  7004. if (serialization_quirks & ~((uint64_t) NETPLAY_QUIRK_MAP_UNDERSTOOD))
  7005. quirks |= NETPLAY_QUIRK_NO_SAVESTATES;
  7006. if (serialization_quirks & NETPLAY_QUIRK_MAP_NO_SAVESTATES)
  7007. quirks |= NETPLAY_QUIRK_NO_SAVESTATES;
  7008. if (serialization_quirks & NETPLAY_QUIRK_MAP_NO_TRANSMISSION)
  7009. quirks |= NETPLAY_QUIRK_NO_TRANSMISSION;
  7010. if (serialization_quirks & NETPLAY_QUIRK_MAP_INITIALIZATION)
  7011. quirks |= NETPLAY_QUIRK_INITIALIZATION;
  7012. if (serialization_quirks & NETPLAY_QUIRK_MAP_ENDIAN_DEPENDENT)
  7013. quirks |= NETPLAY_QUIRK_ENDIAN_DEPENDENT;
  7014. if (serialization_quirks & NETPLAY_QUIRK_MAP_PLATFORM_DEPENDENT)
  7015. quirks |= NETPLAY_QUIRK_PLATFORM_DEPENDENT;
  7016. if (_netplay_is_client)
  7017. {
  7018. RARCH_LOG("[Netplay]: %s\n", msg_hash_to_str(MSG_CONNECTING_TO_NETPLAY_HOST));
  7019. }
  7020. else
  7021. {
  7022. RARCH_LOG("[Netplay]: %s\n", msg_hash_to_str(MSG_WAITING_FOR_CLIENT));
  7023. runloop_msg_queue_push(
  7024. msg_hash_to_str(MSG_WAITING_FOR_CLIENT),
  7025. 0, 180, false,
  7026. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  7027. if (settings->bools.netplay_public_announce)
  7028. netplay_announce(p_rarch);
  7029. }
  7030. p_rarch->netplay_data = (netplay_t*)netplay_new(
  7031. _netplay_is_client
  7032. ? direct_host
  7033. : NULL,
  7034. _netplay_is_client
  7035. ? (!p_rarch->netplay_client_deferred
  7036. ? server
  7037. : p_rarch->server_address_deferred)
  7038. : NULL,
  7039. _netplay_is_client ? (!p_rarch->netplay_client_deferred
  7040. ? port
  7041. : p_rarch->server_port_deferred)
  7042. : (port != 0 ? port : RARCH_DEFAULT_PORT),
  7043. settings->bools.netplay_stateless_mode,
  7044. settings->ints.netplay_check_frames,
  7045. &cbs,
  7046. settings->bools.netplay_nat_traversal && !settings->bools.netplay_use_mitm_server,
  7047. #ifdef HAVE_DISCORD
  7048. discord_get_own_username(p_rarch)
  7049. ? discord_get_own_username(p_rarch)
  7050. :
  7051. #endif
  7052. settings->paths.username,
  7053. quirks);
  7054. if (p_rarch->netplay_data)
  7055. {
  7056. if ( p_rarch->netplay_data->is_server
  7057. && !settings->bools.netplay_start_as_spectator)
  7058. netplay_toggle_play_spectate(p_rarch->netplay_data);
  7059. return true;
  7060. }
  7061. RARCH_WARN("%s\n", msg_hash_to_str(MSG_NETPLAY_FAILED));
  7062. runloop_msg_queue_push(
  7063. msg_hash_to_str(MSG_NETPLAY_FAILED),
  7064. 0, 180, false,
  7065. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  7066. return false;
  7067. }
  7068. /**
  7069. * netplay_driver_ctl
  7070. *
  7071. * Frontend access to Netplay functionality
  7072. */
  7073. bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data)
  7074. {
  7075. struct rarch_state *p_rarch = &rarch_st;
  7076. netplay_t *netplay = p_rarch->netplay_data;
  7077. bool ret = true;
  7078. if (p_rarch->in_netplay)
  7079. return true;
  7080. p_rarch->in_netplay = true;
  7081. if (!netplay)
  7082. {
  7083. switch (state)
  7084. {
  7085. case RARCH_NETPLAY_CTL_ENABLE_SERVER:
  7086. p_rarch->netplay_enabled = true;
  7087. p_rarch->netplay_is_client = false;
  7088. goto done;
  7089. case RARCH_NETPLAY_CTL_ENABLE_CLIENT:
  7090. p_rarch->netplay_enabled = true;
  7091. p_rarch->netplay_is_client = true;
  7092. break;
  7093. case RARCH_NETPLAY_CTL_DISABLE:
  7094. p_rarch->netplay_enabled = false;
  7095. #ifdef HAVE_DISCORD
  7096. if (discord_is_inited)
  7097. {
  7098. discord_userdata_t userdata;
  7099. userdata.status = DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED;
  7100. command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
  7101. }
  7102. #endif
  7103. goto done;
  7104. case RARCH_NETPLAY_CTL_IS_ENABLED:
  7105. ret = p_rarch->netplay_enabled;
  7106. goto done;
  7107. case RARCH_NETPLAY_CTL_IS_REPLAYING:
  7108. case RARCH_NETPLAY_CTL_IS_DATA_INITED:
  7109. ret = false;
  7110. goto done;
  7111. case RARCH_NETPLAY_CTL_IS_SERVER:
  7112. ret = p_rarch->netplay_enabled
  7113. && !p_rarch->netplay_is_client;
  7114. goto done;
  7115. case RARCH_NETPLAY_CTL_IS_CONNECTED:
  7116. ret = false;
  7117. goto done;
  7118. default:
  7119. goto done;
  7120. }
  7121. }
  7122. switch (state)
  7123. {
  7124. case RARCH_NETPLAY_CTL_ENABLE_SERVER:
  7125. case RARCH_NETPLAY_CTL_ENABLE_CLIENT:
  7126. case RARCH_NETPLAY_CTL_IS_DATA_INITED:
  7127. goto done;
  7128. case RARCH_NETPLAY_CTL_DISABLE:
  7129. ret = false;
  7130. goto done;
  7131. case RARCH_NETPLAY_CTL_IS_ENABLED:
  7132. goto done;
  7133. case RARCH_NETPLAY_CTL_IS_REPLAYING:
  7134. ret = netplay->is_replay;
  7135. goto done;
  7136. case RARCH_NETPLAY_CTL_IS_SERVER:
  7137. ret = p_rarch->netplay_enabled
  7138. && !p_rarch->netplay_is_client;
  7139. goto done;
  7140. case RARCH_NETPLAY_CTL_IS_CONNECTED:
  7141. ret = netplay->is_connected;
  7142. goto done;
  7143. case RARCH_NETPLAY_CTL_POST_FRAME:
  7144. netplay_post_frame(p_rarch, netplay);
  7145. break;
  7146. case RARCH_NETPLAY_CTL_PRE_FRAME:
  7147. ret = netplay_pre_frame(p_rarch, netplay);
  7148. goto done;
  7149. case RARCH_NETPLAY_CTL_GAME_WATCH:
  7150. netplay_toggle_play_spectate(netplay);
  7151. break;
  7152. case RARCH_NETPLAY_CTL_PAUSE:
  7153. if (netplay->local_paused != true)
  7154. netplay_frontend_paused(netplay, true);
  7155. break;
  7156. case RARCH_NETPLAY_CTL_UNPAUSE:
  7157. if (netplay->local_paused != false)
  7158. netplay_frontend_paused(netplay, false);
  7159. break;
  7160. case RARCH_NETPLAY_CTL_LOAD_SAVESTATE:
  7161. netplay_load_savestate(netplay, (retro_ctx_serialize_info_t*)data, true);
  7162. break;
  7163. case RARCH_NETPLAY_CTL_RESET:
  7164. netplay_core_reset(netplay);
  7165. break;
  7166. case RARCH_NETPLAY_CTL_DISCONNECT:
  7167. ret = true;
  7168. if (netplay)
  7169. netplay_disconnect(p_rarch, netplay);
  7170. goto done;
  7171. case RARCH_NETPLAY_CTL_FINISHED_NAT_TRAVERSAL:
  7172. netplay->nat_traversal_task_oustanding = false;
  7173. #ifndef HAVE_SOCKET_LEGACY
  7174. netplay_announce_nat_traversal(netplay);
  7175. #endif
  7176. goto done;
  7177. case RARCH_NETPLAY_CTL_DESYNC_PUSH:
  7178. netplay->desync++;
  7179. break;
  7180. case RARCH_NETPLAY_CTL_DESYNC_POP:
  7181. if (netplay->desync)
  7182. {
  7183. netplay->desync--;
  7184. if (!netplay->desync)
  7185. netplay_load_savestate(netplay, NULL, true);
  7186. }
  7187. break;
  7188. default:
  7189. case RARCH_NETPLAY_CTL_NONE:
  7190. ret = false;
  7191. }
  7192. done:
  7193. p_rarch->in_netplay = false;
  7194. return ret;
  7195. }
  7196. #endif
  7197. static void log_counters(
  7198. struct retro_perf_counter **counters, unsigned num)
  7199. {
  7200. unsigned i;
  7201. for (i = 0; i < num; i++)
  7202. {
  7203. if (counters[i]->call_cnt)
  7204. {
  7205. RARCH_LOG(PERF_LOG_FMT,
  7206. counters[i]->ident,
  7207. (uint64_t)counters[i]->total /
  7208. (uint64_t)counters[i]->call_cnt,
  7209. (uint64_t)counters[i]->call_cnt);
  7210. }
  7211. }
  7212. }
  7213. static void retro_perf_log(void)
  7214. {
  7215. struct rarch_state *p_rarch = &rarch_st;
  7216. RARCH_LOG("[PERF]: Performance counters (libretro):\n");
  7217. log_counters(p_rarch->perf_counters_libretro, p_rarch->perf_ptr_libretro);
  7218. }
  7219. struct retro_perf_counter **retro_get_perf_counter_rarch(void)
  7220. {
  7221. struct rarch_state *p_rarch = &rarch_st;
  7222. return p_rarch->perf_counters_rarch;
  7223. }
  7224. struct retro_perf_counter **retro_get_perf_counter_libretro(void)
  7225. {
  7226. struct rarch_state *p_rarch = &rarch_st;
  7227. return p_rarch->perf_counters_libretro;
  7228. }
  7229. unsigned retro_get_perf_count_rarch(void)
  7230. {
  7231. struct rarch_state *p_rarch = &rarch_st;
  7232. return p_rarch->perf_ptr_rarch;
  7233. }
  7234. unsigned retro_get_perf_count_libretro(void)
  7235. {
  7236. struct rarch_state *p_rarch = &rarch_st;
  7237. return p_rarch->perf_ptr_libretro;
  7238. }
  7239. void rarch_perf_register(struct retro_perf_counter *perf)
  7240. {
  7241. struct rarch_state *p_rarch = &rarch_st;
  7242. if (
  7243. !p_rarch->runloop_perfcnt_enable
  7244. || perf->registered
  7245. || p_rarch->perf_ptr_rarch >= MAX_COUNTERS
  7246. )
  7247. return;
  7248. p_rarch->perf_counters_rarch[p_rarch->perf_ptr_rarch++] = perf;
  7249. perf->registered = true;
  7250. }
  7251. static void performance_counter_register(struct retro_perf_counter *perf)
  7252. {
  7253. struct rarch_state *p_rarch = &rarch_st;
  7254. if (perf->registered || p_rarch->perf_ptr_libretro >= MAX_COUNTERS)
  7255. return;
  7256. p_rarch->perf_counters_libretro[p_rarch->perf_ptr_libretro++] = perf;
  7257. perf->registered = true;
  7258. }
  7259. struct string_list *dir_list_new_special(const char *input_dir,
  7260. enum dir_list_type type, const char *filter,
  7261. bool show_hidden_files)
  7262. {
  7263. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  7264. char ext_shaders[255];
  7265. #endif
  7266. char ext_name[255];
  7267. const char *exts = NULL;
  7268. bool recursive = false;
  7269. switch (type)
  7270. {
  7271. case DIR_LIST_AUTOCONFIG:
  7272. exts = filter;
  7273. break;
  7274. case DIR_LIST_CORES:
  7275. ext_name[0] = '\0';
  7276. if (!frontend_driver_get_core_extension(ext_name, sizeof(ext_name)))
  7277. return NULL;
  7278. exts = ext_name;
  7279. break;
  7280. case DIR_LIST_RECURSIVE:
  7281. recursive = true;
  7282. /* fall-through */
  7283. case DIR_LIST_CORE_INFO:
  7284. {
  7285. core_info_list_t *list = NULL;
  7286. core_info_get_list(&list);
  7287. if (list)
  7288. exts = list->all_ext;
  7289. }
  7290. break;
  7291. case DIR_LIST_SHADERS:
  7292. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  7293. {
  7294. union string_list_elem_attr attr;
  7295. struct string_list str_list;
  7296. if (!string_list_initialize(&str_list))
  7297. return NULL;
  7298. ext_shaders[0] = '\0';
  7299. attr.i = 0;
  7300. if (video_shader_is_supported(RARCH_SHADER_CG))
  7301. {
  7302. string_list_append(&str_list, "cgp", attr);
  7303. string_list_append(&str_list, "cg", attr);
  7304. }
  7305. if (video_shader_is_supported(RARCH_SHADER_GLSL))
  7306. {
  7307. string_list_append(&str_list, "glslp", attr);
  7308. string_list_append(&str_list, "glsl", attr);
  7309. }
  7310. if (video_shader_is_supported(RARCH_SHADER_SLANG))
  7311. {
  7312. string_list_append(&str_list, "slangp", attr);
  7313. string_list_append(&str_list, "slang", attr);
  7314. }
  7315. string_list_join_concat(ext_shaders, sizeof(ext_shaders), &str_list, "|");
  7316. string_list_deinitialize(&str_list);
  7317. exts = ext_shaders;
  7318. }
  7319. break;
  7320. #else
  7321. return NULL;
  7322. #endif
  7323. case DIR_LIST_COLLECTIONS:
  7324. exts = "lpl";
  7325. break;
  7326. case DIR_LIST_DATABASES:
  7327. exts = "rdb";
  7328. break;
  7329. case DIR_LIST_PLAIN:
  7330. exts = filter;
  7331. break;
  7332. case DIR_LIST_NONE:
  7333. default:
  7334. return NULL;
  7335. }
  7336. return dir_list_new(input_dir, exts, false,
  7337. show_hidden_files,
  7338. type == DIR_LIST_CORE_INFO, recursive);
  7339. }
  7340. struct string_list *string_list_new_special(enum string_list_type type,
  7341. void *data, unsigned *len, size_t *list_size)
  7342. {
  7343. union string_list_elem_attr attr;
  7344. unsigned i;
  7345. core_info_list_t *core_info_list = NULL;
  7346. const core_info_t *core_info = NULL;
  7347. struct string_list *s = string_list_new();
  7348. if (!s || !len)
  7349. goto error;
  7350. attr.i = 0;
  7351. *len = 0;
  7352. switch (type)
  7353. {
  7354. case STRING_LIST_MENU_DRIVERS:
  7355. #ifdef HAVE_MENU
  7356. for (i = 0; menu_ctx_drivers[i]; i++)
  7357. {
  7358. const char *opt = menu_ctx_drivers[i]->ident;
  7359. *len += strlen(opt) + 1;
  7360. /* Don't allow the user to set menu driver to "null" using the UI.
  7361. * Can prevent the user from locking him/herself out of the program. */
  7362. if (string_is_not_equal(opt, "null"))
  7363. string_list_append(s, opt, attr);
  7364. }
  7365. break;
  7366. #endif
  7367. case STRING_LIST_CAMERA_DRIVERS:
  7368. for (i = 0; camera_drivers[i]; i++)
  7369. {
  7370. const char *opt = camera_drivers[i]->ident;
  7371. *len += strlen(opt) + 1;
  7372. string_list_append(s, opt, attr);
  7373. }
  7374. break;
  7375. case STRING_LIST_BLUETOOTH_DRIVERS:
  7376. #ifdef HAVE_BLUETOOTH
  7377. for (i = 0; bluetooth_drivers[i]; i++)
  7378. {
  7379. const char *opt = bluetooth_drivers[i]->ident;
  7380. *len += strlen(opt) + 1;
  7381. string_list_append(s, opt, attr);
  7382. }
  7383. break;
  7384. #endif
  7385. case STRING_LIST_WIFI_DRIVERS:
  7386. #ifdef HAVE_WIFI
  7387. for (i = 0; wifi_drivers[i]; i++)
  7388. {
  7389. const char *opt = wifi_drivers[i]->ident;
  7390. *len += strlen(opt) + 1;
  7391. string_list_append(s, opt, attr);
  7392. }
  7393. break;
  7394. #endif
  7395. case STRING_LIST_LOCATION_DRIVERS:
  7396. for (i = 0; location_drivers[i]; i++)
  7397. {
  7398. const char *opt = location_drivers[i]->ident;
  7399. *len += strlen(opt) + 1;
  7400. string_list_append(s, opt, attr);
  7401. }
  7402. break;
  7403. case STRING_LIST_AUDIO_DRIVERS:
  7404. for (i = 0; audio_drivers[i]; i++)
  7405. {
  7406. const char *opt = audio_drivers[i]->ident;
  7407. *len += strlen(opt) + 1;
  7408. string_list_append(s, opt, attr);
  7409. }
  7410. break;
  7411. case STRING_LIST_AUDIO_RESAMPLER_DRIVERS:
  7412. for (i = 0; audio_resampler_driver_find_handle(i); i++)
  7413. {
  7414. const char *opt = audio_resampler_driver_find_ident(i);
  7415. *len += strlen(opt) + 1;
  7416. string_list_append(s, opt, attr);
  7417. }
  7418. break;
  7419. case STRING_LIST_VIDEO_DRIVERS:
  7420. for (i = 0; video_drivers[i]; i++)
  7421. {
  7422. const char *opt = video_drivers[i]->ident;
  7423. *len += strlen(opt) + 1;
  7424. /* Don't allow the user to set video driver to "null" using the UI.
  7425. * Can prevent the user from locking him/herself out of the program. */
  7426. if (string_is_not_equal(opt, "null"))
  7427. string_list_append(s, opt, attr);
  7428. }
  7429. break;
  7430. case STRING_LIST_INPUT_DRIVERS:
  7431. for (i = 0; input_drivers[i]; i++)
  7432. {
  7433. const char *opt = input_drivers[i]->ident;
  7434. *len += strlen(opt) + 1;
  7435. /* Don't allow the user to set input driver to "null" using the UI.
  7436. * Can prevent the user from locking him/herself out of the program. */
  7437. if (string_is_not_equal(opt, "null"))
  7438. string_list_append(s, opt, attr);
  7439. }
  7440. break;
  7441. case STRING_LIST_INPUT_HID_DRIVERS:
  7442. #ifdef HAVE_HID
  7443. for (i = 0; hid_drivers[i]; i++)
  7444. {
  7445. const char *opt = hid_drivers[i]->ident;
  7446. *len += strlen(opt) + 1;
  7447. /* Don't allow the user to set input HID driver to "null" using the UI.
  7448. * Can prevent the user from locking him/herself out of the program. */
  7449. if (string_is_not_equal(opt, "null"))
  7450. string_list_append(s, opt, attr);
  7451. }
  7452. #endif
  7453. break;
  7454. case STRING_LIST_INPUT_JOYPAD_DRIVERS:
  7455. for (i = 0; joypad_drivers[i]; i++)
  7456. {
  7457. const char *opt = joypad_drivers[i]->ident;
  7458. *len += strlen(opt) + 1;
  7459. /* Don't allow the user to set input joypad driver to "null" using the UI.
  7460. * Can prevent the user from locking him/herself out of the program. */
  7461. if (string_is_not_equal(opt, "null"))
  7462. string_list_append(s, opt, attr);
  7463. }
  7464. break;
  7465. case STRING_LIST_RECORD_DRIVERS:
  7466. for (i = 0; record_drivers[i]; i++)
  7467. {
  7468. const char *opt = record_drivers[i]->ident;
  7469. *len += strlen(opt) + 1;
  7470. string_list_append(s, opt, attr);
  7471. }
  7472. break;
  7473. case STRING_LIST_MIDI_DRIVERS:
  7474. for (i = 0; midi_driver_find_handle(i); i++)
  7475. {
  7476. const char *opt = midi_drivers[i]->ident;
  7477. *len += strlen(opt) + 1;
  7478. string_list_append(s, opt, attr);
  7479. }
  7480. break;
  7481. case STRING_LIST_SUPPORTED_CORES_PATHS:
  7482. core_info_get_list(&core_info_list);
  7483. core_info_list_get_supported_cores(core_info_list,
  7484. (const char*)data, &core_info, list_size);
  7485. if (!core_info)
  7486. goto error;
  7487. if (*list_size == 0)
  7488. goto error;
  7489. for (i = 0; i < *list_size; i++)
  7490. {
  7491. const core_info_t *info = (const core_info_t*)&core_info[i];
  7492. const char *opt = info->path;
  7493. if (!opt)
  7494. goto error;
  7495. *len += strlen(opt) + 1;
  7496. string_list_append(s, opt, attr);
  7497. }
  7498. break;
  7499. case STRING_LIST_SUPPORTED_CORES_NAMES:
  7500. core_info_get_list(&core_info_list);
  7501. core_info_list_get_supported_cores(core_info_list,
  7502. (const char*)data, &core_info, list_size);
  7503. if (!core_info)
  7504. goto error;
  7505. if (*list_size == 0)
  7506. goto error;
  7507. for (i = 0; i < *list_size; i++)
  7508. {
  7509. core_info_t *info = (core_info_t*)&core_info[i];
  7510. const char *opt = info->display_name;
  7511. if (!opt)
  7512. goto error;
  7513. *len += strlen(opt) + 1;
  7514. string_list_append(s, opt, attr);
  7515. }
  7516. break;
  7517. case STRING_LIST_NONE:
  7518. default:
  7519. goto error;
  7520. }
  7521. return s;
  7522. error:
  7523. string_list_free(s);
  7524. s = NULL;
  7525. return NULL;
  7526. }
  7527. const char *char_list_new_special(enum string_list_type type, void *data)
  7528. {
  7529. unsigned len = 0;
  7530. size_t list_size;
  7531. struct string_list *s = string_list_new_special(type, data, &len, &list_size);
  7532. char *options = (len > 0) ? (char*)calloc(len, sizeof(char)): NULL;
  7533. if (options && s)
  7534. string_list_join_concat(options, len, s, "|");
  7535. string_list_free(s);
  7536. s = NULL;
  7537. return options;
  7538. }
  7539. static void path_set_redirect(struct rarch_state *p_rarch)
  7540. {
  7541. char content_dir_name[PATH_MAX_LENGTH];
  7542. char new_savefile_dir[PATH_MAX_LENGTH];
  7543. char new_savestate_dir[PATH_MAX_LENGTH];
  7544. global_t *global = &p_rarch->g_extern;
  7545. const char *old_savefile_dir = p_rarch->dir_savefile;
  7546. const char *old_savestate_dir = p_rarch->dir_savestate;
  7547. struct retro_system_info *system = &p_rarch->runloop_system.info;
  7548. settings_t *settings = p_rarch->configuration_settings;
  7549. bool sort_savefiles_enable = settings->bools.sort_savefiles_enable;
  7550. bool sort_savefiles_by_content_enable = settings->bools.sort_savefiles_by_content_enable;
  7551. bool sort_savestates_enable = settings->bools.sort_savestates_enable;
  7552. bool sort_savestates_by_content_enable = settings->bools.sort_savestates_by_content_enable;
  7553. bool savefiles_in_content_dir = settings->bools.savefiles_in_content_dir;
  7554. bool savestates_in_content_dir = settings->bools.savestates_in_content_dir;
  7555. content_dir_name[0] = '\0';
  7556. new_savefile_dir[0] = '\0';
  7557. new_savestate_dir[0] = '\0';
  7558. /* Initialize current save directories
  7559. * with the values from the config. */
  7560. strlcpy(new_savefile_dir, old_savefile_dir, sizeof(new_savefile_dir));
  7561. strlcpy(new_savestate_dir, old_savestate_dir, sizeof(new_savestate_dir));
  7562. /* Get content directory name, if per-content-directory
  7563. * saves/states are enabled */
  7564. if ((sort_savefiles_by_content_enable ||
  7565. sort_savestates_by_content_enable) &&
  7566. !string_is_empty(p_rarch->path_main_basename))
  7567. fill_pathname_parent_dir_name(content_dir_name,
  7568. p_rarch->path_main_basename, sizeof(content_dir_name));
  7569. if (system && !string_is_empty(system->library_name))
  7570. {
  7571. #ifdef HAVE_MENU
  7572. if (!string_is_equal(system->library_name,
  7573. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE)))
  7574. #endif
  7575. {
  7576. /* Per-core and/or per-content-directory saves */
  7577. if ((sort_savefiles_enable || sort_savefiles_by_content_enable)
  7578. && !string_is_empty(old_savefile_dir))
  7579. {
  7580. /* Append content directory name to save location */
  7581. if (sort_savefiles_by_content_enable)
  7582. fill_pathname_join(
  7583. new_savefile_dir,
  7584. old_savefile_dir,
  7585. content_dir_name,
  7586. sizeof(new_savefile_dir));
  7587. /* Append library_name to the save location */
  7588. if (sort_savefiles_enable)
  7589. fill_pathname_join(
  7590. new_savefile_dir,
  7591. new_savefile_dir,
  7592. system->library_name,
  7593. sizeof(new_savefile_dir));
  7594. /* If path doesn't exist, try to create it,
  7595. * if everything fails revert to the original path. */
  7596. if (!path_is_directory(new_savefile_dir))
  7597. if (!path_mkdir(new_savefile_dir))
  7598. {
  7599. RARCH_LOG("%s %s\n",
  7600. msg_hash_to_str(MSG_REVERTING_SAVEFILE_DIRECTORY_TO),
  7601. old_savefile_dir);
  7602. strlcpy(new_savefile_dir, old_savefile_dir, sizeof(new_savefile_dir));
  7603. }
  7604. }
  7605. /* Per-core and/or per-content-directory savestates */
  7606. if ((sort_savestates_enable || sort_savestates_by_content_enable)
  7607. && !string_is_empty(old_savestate_dir))
  7608. {
  7609. /* Append content directory name to savestate location */
  7610. if (sort_savestates_by_content_enable)
  7611. fill_pathname_join(
  7612. new_savestate_dir,
  7613. old_savestate_dir,
  7614. content_dir_name,
  7615. sizeof(new_savestate_dir));
  7616. /* Append library_name to the savestate location */
  7617. if (sort_savestates_enable)
  7618. {
  7619. fill_pathname_join(
  7620. new_savestate_dir,
  7621. new_savestate_dir,
  7622. system->library_name,
  7623. sizeof(new_savestate_dir));
  7624. }
  7625. /* If path doesn't exist, try to create it.
  7626. * If everything fails, revert to the original path. */
  7627. if (!path_is_directory(new_savestate_dir))
  7628. if (!path_mkdir(new_savestate_dir))
  7629. {
  7630. RARCH_LOG("%s %s\n",
  7631. msg_hash_to_str(MSG_REVERTING_SAVESTATE_DIRECTORY_TO),
  7632. old_savestate_dir);
  7633. strlcpy(new_savestate_dir,
  7634. old_savestate_dir,
  7635. sizeof(new_savestate_dir));
  7636. }
  7637. }
  7638. }
  7639. }
  7640. /* Set savefile directory if empty to content directory */
  7641. if (string_is_empty(new_savefile_dir) || savefiles_in_content_dir)
  7642. {
  7643. strlcpy(new_savefile_dir, p_rarch->path_main_basename,
  7644. sizeof(new_savefile_dir));
  7645. path_basedir(new_savefile_dir);
  7646. if (string_is_empty(new_savefile_dir))
  7647. RARCH_LOG("Cannot resolve save file path.\n",
  7648. msg_hash_to_str(MSG_REVERTING_SAVEFILE_DIRECTORY_TO),
  7649. new_savefile_dir);
  7650. else if (sort_savefiles_enable || sort_savefiles_by_content_enable)
  7651. RARCH_LOG("Saving files in content directory is set. This overrides other save file directory settings.\n");
  7652. }
  7653. /* Set savestate directory if empty based on content directory */
  7654. if (string_is_empty(new_savestate_dir) || savestates_in_content_dir)
  7655. {
  7656. strlcpy(new_savestate_dir, p_rarch->path_main_basename,
  7657. sizeof(new_savestate_dir));
  7658. path_basedir(new_savestate_dir);
  7659. if (string_is_empty(new_savestate_dir))
  7660. RARCH_LOG("Cannot resolve save state file path.\n",
  7661. msg_hash_to_str(MSG_REVERTING_SAVESTATE_DIRECTORY_TO),
  7662. new_savestate_dir);
  7663. else if (sort_savestates_enable || sort_savestates_by_content_enable)
  7664. RARCH_LOG("Saving save states in content directory is set. This overrides other save state file directory settings.\n");
  7665. }
  7666. if (global && system && !string_is_empty(system->library_name))
  7667. {
  7668. bool savefile_is_dir = path_is_directory(new_savefile_dir);
  7669. bool savestate_is_dir = path_is_directory(new_savestate_dir);
  7670. if (savefile_is_dir)
  7671. strlcpy(global->name.savefile, new_savefile_dir,
  7672. sizeof(global->name.savefile));
  7673. else
  7674. savefile_is_dir = path_is_directory(global->name.savefile);
  7675. if (savestate_is_dir)
  7676. strlcpy(global->name.savestate, new_savestate_dir,
  7677. sizeof(global->name.savestate));
  7678. else
  7679. savestate_is_dir = path_is_directory(global->name.savestate);
  7680. if (savefile_is_dir)
  7681. {
  7682. fill_pathname_dir(global->name.savefile,
  7683. !string_is_empty(p_rarch->path_main_basename)
  7684. ? p_rarch->path_main_basename
  7685. : system->library_name,
  7686. FILE_PATH_SRM_EXTENSION,
  7687. sizeof(global->name.savefile));
  7688. RARCH_LOG("[Overrides]: %s \"%s\".\n",
  7689. msg_hash_to_str(MSG_REDIRECTING_SAVEFILE_TO),
  7690. global->name.savefile);
  7691. }
  7692. if (savestate_is_dir)
  7693. {
  7694. fill_pathname_dir(global->name.savestate,
  7695. !string_is_empty(p_rarch->path_main_basename)
  7696. ? p_rarch->path_main_basename
  7697. : system->library_name,
  7698. FILE_PATH_STATE_EXTENSION,
  7699. sizeof(global->name.savestate));
  7700. RARCH_LOG("[Overrides]: %s \"%s\".\n",
  7701. msg_hash_to_str(MSG_REDIRECTING_SAVESTATE_TO),
  7702. global->name.savestate);
  7703. }
  7704. #ifdef HAVE_CHEATS
  7705. if (path_is_directory(global->name.cheatfile))
  7706. {
  7707. fill_pathname_dir(global->name.cheatfile,
  7708. !string_is_empty(p_rarch->path_main_basename)
  7709. ? p_rarch->path_main_basename
  7710. : system->library_name,
  7711. FILE_PATH_CHT_EXTENSION,
  7712. sizeof(global->name.cheatfile));
  7713. RARCH_LOG("[Overrides]: %s \"%s\".\n",
  7714. msg_hash_to_str(MSG_REDIRECTING_CHEATFILE_TO),
  7715. global->name.cheatfile);
  7716. }
  7717. #endif
  7718. }
  7719. dir_set(RARCH_DIR_CURRENT_SAVEFILE, new_savefile_dir);
  7720. dir_set(RARCH_DIR_CURRENT_SAVESTATE, new_savestate_dir);
  7721. }
  7722. static void path_set_basename(
  7723. struct rarch_state *p_rarch,
  7724. const char *path)
  7725. {
  7726. char *dst = NULL;
  7727. path_set(RARCH_PATH_CONTENT, path);
  7728. path_set(RARCH_PATH_BASENAME, path);
  7729. #ifdef HAVE_COMPRESSION
  7730. /* Removing extension is a bit tricky for compressed files.
  7731. * Basename means:
  7732. * /file/to/path/game.extension should be:
  7733. * /file/to/path/game
  7734. *
  7735. * Two things to consider here are: /file/to/path/ is expected
  7736. * to be a directory and "game" is a single file. This is used for
  7737. * states and srm default paths.
  7738. *
  7739. * For compressed files we have:
  7740. *
  7741. * /file/to/path/comp.7z#game.extension and
  7742. * /file/to/path/comp.7z#folder/game.extension
  7743. *
  7744. * The choice I take here is:
  7745. * /file/to/path/game as basename. We might end up in a writable
  7746. * directory then and the name of srm and states are meaningful.
  7747. *
  7748. */
  7749. path_basedir_wrapper(p_rarch->path_main_basename);
  7750. if (!string_is_empty(p_rarch->path_main_basename))
  7751. fill_pathname_dir(p_rarch->path_main_basename, path, "", sizeof(p_rarch->path_main_basename));
  7752. #endif
  7753. if ((dst = strrchr(p_rarch->path_main_basename, '.')))
  7754. *dst = '\0';
  7755. }
  7756. struct string_list *path_get_subsystem_list(void)
  7757. {
  7758. struct rarch_state *p_rarch = &rarch_st;
  7759. return p_rarch->subsystem_fullpaths;
  7760. }
  7761. void path_set_special(char **argv, unsigned num_content)
  7762. {
  7763. unsigned i;
  7764. char str[PATH_MAX_LENGTH];
  7765. union string_list_elem_attr attr;
  7766. struct string_list subsystem_paths = {0};
  7767. struct rarch_state *p_rarch = &rarch_st;
  7768. global_t *global = &p_rarch->g_extern;
  7769. const char *savestate_dir = p_rarch->current_savestate_dir;
  7770. /* First content file is the significant one. */
  7771. path_set_basename(p_rarch, argv[0]);
  7772. string_list_initialize(&subsystem_paths);
  7773. p_rarch->subsystem_fullpaths = string_list_new();
  7774. retro_assert(p_rarch->subsystem_fullpaths);
  7775. attr.i = 0;
  7776. for (i = 0; i < num_content; i++)
  7777. {
  7778. string_list_append(p_rarch->subsystem_fullpaths, argv[i], attr);
  7779. strlcpy(str, argv[i], sizeof(str));
  7780. path_remove_extension(str);
  7781. string_list_append(&subsystem_paths, path_basename(str), attr);
  7782. }
  7783. str[0] = '\0';
  7784. string_list_join_concat(str, sizeof(str), &subsystem_paths, " + ");
  7785. string_list_deinitialize(&subsystem_paths);
  7786. /* We defer SRAM path updates until we can resolve it.
  7787. * It is more complicated for special content types. */
  7788. if (global)
  7789. {
  7790. bool is_dir = path_is_directory(savestate_dir);
  7791. if (is_dir)
  7792. strlcpy(global->name.savestate, savestate_dir,
  7793. sizeof(global->name.savestate));
  7794. else
  7795. is_dir = path_is_directory(global->name.savestate);
  7796. if (is_dir)
  7797. {
  7798. fill_pathname_dir(global->name.savestate,
  7799. str,
  7800. ".state",
  7801. sizeof(global->name.savestate));
  7802. RARCH_LOG("%s \"%s\".\n",
  7803. msg_hash_to_str(MSG_REDIRECTING_SAVESTATE_TO),
  7804. global->name.savestate);
  7805. }
  7806. }
  7807. }
  7808. static bool path_init_subsystem(struct rarch_state *p_rarch)
  7809. {
  7810. unsigned i, j;
  7811. const struct retro_subsystem_info *info = NULL;
  7812. global_t *global = &p_rarch->g_extern;
  7813. rarch_system_info_t *system = &p_rarch->runloop_system;
  7814. bool subsystem_path_empty = path_is_empty(RARCH_PATH_SUBSYSTEM);
  7815. const char *savefile_dir = p_rarch->current_savefile_dir;
  7816. if (!system || subsystem_path_empty)
  7817. return false;
  7818. /* For subsystems, we know exactly which RAM types are supported. */
  7819. info = libretro_find_subsystem_info(
  7820. system->subsystem.data,
  7821. system->subsystem.size,
  7822. path_get(RARCH_PATH_SUBSYSTEM));
  7823. /* We'll handle this error gracefully later. */
  7824. if (info)
  7825. {
  7826. unsigned num_content = MIN(info->num_roms,
  7827. subsystem_path_empty ?
  7828. 0 : (unsigned)p_rarch->subsystem_fullpaths->size);
  7829. for (i = 0; i < num_content; i++)
  7830. {
  7831. for (j = 0; j < info->roms[i].num_memory; j++)
  7832. {
  7833. char ext[32];
  7834. union string_list_elem_attr attr;
  7835. char savename[PATH_MAX_LENGTH];
  7836. char path[PATH_MAX_LENGTH];
  7837. const struct retro_subsystem_memory_info *mem =
  7838. (const struct retro_subsystem_memory_info*)
  7839. &info->roms[i].memory[j];
  7840. path[0] = ext[0] = '\0';
  7841. strcpy_literal(ext, ".");
  7842. strlcat(ext, mem->extension, sizeof(ext));
  7843. strlcpy(savename,
  7844. p_rarch->subsystem_fullpaths->elems[i].data,
  7845. sizeof(savename));
  7846. path_remove_extension(savename);
  7847. if (path_is_directory(savefile_dir))
  7848. {
  7849. /* Use SRAM dir */
  7850. /* Redirect content fullpath to save directory. */
  7851. strlcpy(path, savefile_dir, sizeof(path));
  7852. fill_pathname_dir(path, savename, ext, sizeof(path));
  7853. }
  7854. else
  7855. fill_pathname(path, savename, ext, sizeof(path));
  7856. RARCH_LOG("%s \"%s\".\n",
  7857. msg_hash_to_str(MSG_REDIRECTING_SAVEFILE_TO),
  7858. path);
  7859. attr.i = mem->type;
  7860. string_list_append((struct string_list*)savefile_ptr_get(),
  7861. path, attr);
  7862. }
  7863. }
  7864. }
  7865. if (global)
  7866. {
  7867. /* Let other relevant paths be inferred from the main SRAM location. */
  7868. if (!retroarch_override_setting_is_set(
  7869. RARCH_OVERRIDE_SETTING_SAVE_PATH, NULL))
  7870. fill_pathname_noext(global->name.savefile,
  7871. p_rarch->path_main_basename,
  7872. ".srm",
  7873. sizeof(global->name.savefile));
  7874. if (path_is_directory(global->name.savefile))
  7875. {
  7876. fill_pathname_dir(global->name.savefile,
  7877. p_rarch->path_main_basename,
  7878. ".srm",
  7879. sizeof(global->name.savefile));
  7880. RARCH_LOG("%s \"%s\".\n",
  7881. msg_hash_to_str(MSG_REDIRECTING_SAVEFILE_TO),
  7882. global->name.savefile);
  7883. }
  7884. }
  7885. return true;
  7886. }
  7887. static void path_init_savefile(struct rarch_state *p_rarch)
  7888. {
  7889. bool should_sram_be_used = p_rarch->rarch_use_sram
  7890. && !p_rarch->rarch_is_sram_save_disabled;
  7891. p_rarch->rarch_use_sram = should_sram_be_used;
  7892. if (!p_rarch->rarch_use_sram)
  7893. {
  7894. RARCH_LOG("[SRAM]: %s\n",
  7895. msg_hash_to_str(MSG_SRAM_WILL_NOT_BE_SAVED));
  7896. return;
  7897. }
  7898. command_event(CMD_EVENT_AUTOSAVE_INIT, NULL);
  7899. }
  7900. static void path_init_savefile_internal(
  7901. global_t *global,
  7902. struct rarch_state *p_rarch)
  7903. {
  7904. path_deinit_savefile();
  7905. path_init_savefile_new();
  7906. if (!path_init_subsystem(p_rarch))
  7907. path_init_savefile_rtc(global->name.savefile);
  7908. }
  7909. static void path_fill_names(struct rarch_state *p_rarch)
  7910. {
  7911. global_t *global = &p_rarch->g_extern;
  7912. path_init_savefile_internal(global, p_rarch);
  7913. #ifdef HAVE_BSV_MOVIE
  7914. if (global)
  7915. strlcpy(p_rarch->bsv_movie_state.movie_path,
  7916. global->name.savefile,
  7917. sizeof(p_rarch->bsv_movie_state.movie_path));
  7918. #endif
  7919. if (string_is_empty(p_rarch->path_main_basename))
  7920. return;
  7921. if (global)
  7922. {
  7923. if (string_is_empty(global->name.ups))
  7924. fill_pathname_noext(global->name.ups,
  7925. p_rarch->path_main_basename,
  7926. ".ups",
  7927. sizeof(global->name.ups));
  7928. if (string_is_empty(global->name.bps))
  7929. fill_pathname_noext(global->name.bps,
  7930. p_rarch->path_main_basename,
  7931. ".bps",
  7932. sizeof(global->name.bps));
  7933. if (string_is_empty(global->name.ips))
  7934. fill_pathname_noext(global->name.ips,
  7935. p_rarch->path_main_basename,
  7936. ".ips",
  7937. sizeof(global->name.ips));
  7938. }
  7939. }
  7940. char *path_get_ptr(enum rarch_path_type type)
  7941. {
  7942. struct rarch_state *p_rarch = &rarch_st;
  7943. switch (type)
  7944. {
  7945. case RARCH_PATH_CONTENT:
  7946. return p_rarch->path_content;
  7947. case RARCH_PATH_DEFAULT_SHADER_PRESET:
  7948. return p_rarch->path_default_shader_preset;
  7949. case RARCH_PATH_BASENAME:
  7950. return p_rarch->path_main_basename;
  7951. case RARCH_PATH_CORE_OPTIONS:
  7952. if (!path_is_empty(RARCH_PATH_CORE_OPTIONS))
  7953. return p_rarch->path_core_options_file;
  7954. break;
  7955. case RARCH_PATH_SUBSYSTEM:
  7956. return p_rarch->subsystem_path;
  7957. case RARCH_PATH_CONFIG:
  7958. if (!path_is_empty(RARCH_PATH_CONFIG))
  7959. return p_rarch->path_config_file;
  7960. break;
  7961. case RARCH_PATH_CONFIG_APPEND:
  7962. if (!path_is_empty(RARCH_PATH_CONFIG_APPEND))
  7963. return p_rarch->path_config_append_file;
  7964. break;
  7965. case RARCH_PATH_CORE:
  7966. return p_rarch->path_libretro;
  7967. case RARCH_PATH_NONE:
  7968. case RARCH_PATH_NAMES:
  7969. break;
  7970. }
  7971. return NULL;
  7972. }
  7973. const char *path_get(enum rarch_path_type type)
  7974. {
  7975. struct rarch_state *p_rarch = &rarch_st;
  7976. switch (type)
  7977. {
  7978. case RARCH_PATH_CONTENT:
  7979. return p_rarch->path_content;
  7980. case RARCH_PATH_DEFAULT_SHADER_PRESET:
  7981. return p_rarch->path_default_shader_preset;
  7982. case RARCH_PATH_BASENAME:
  7983. return p_rarch->path_main_basename;
  7984. case RARCH_PATH_CORE_OPTIONS:
  7985. if (!path_is_empty(RARCH_PATH_CORE_OPTIONS))
  7986. return p_rarch->path_core_options_file;
  7987. break;
  7988. case RARCH_PATH_SUBSYSTEM:
  7989. return p_rarch->subsystem_path;
  7990. case RARCH_PATH_CONFIG:
  7991. if (!path_is_empty(RARCH_PATH_CONFIG))
  7992. return p_rarch->path_config_file;
  7993. break;
  7994. case RARCH_PATH_CONFIG_APPEND:
  7995. if (!path_is_empty(RARCH_PATH_CONFIG_APPEND))
  7996. return p_rarch->path_config_append_file;
  7997. break;
  7998. case RARCH_PATH_CORE:
  7999. return p_rarch->path_libretro;
  8000. case RARCH_PATH_NONE:
  8001. case RARCH_PATH_NAMES:
  8002. break;
  8003. }
  8004. return NULL;
  8005. }
  8006. size_t path_get_realsize(enum rarch_path_type type)
  8007. {
  8008. struct rarch_state *p_rarch = &rarch_st;
  8009. switch (type)
  8010. {
  8011. case RARCH_PATH_CONTENT:
  8012. return sizeof(p_rarch->path_content);
  8013. case RARCH_PATH_DEFAULT_SHADER_PRESET:
  8014. return sizeof(p_rarch->path_default_shader_preset);
  8015. case RARCH_PATH_BASENAME:
  8016. return sizeof(p_rarch->path_main_basename);
  8017. case RARCH_PATH_CORE_OPTIONS:
  8018. return sizeof(p_rarch->path_core_options_file);
  8019. case RARCH_PATH_SUBSYSTEM:
  8020. return sizeof(p_rarch->subsystem_path);
  8021. case RARCH_PATH_CONFIG:
  8022. return sizeof(p_rarch->path_config_file);
  8023. case RARCH_PATH_CONFIG_APPEND:
  8024. return sizeof(p_rarch->path_config_append_file);
  8025. case RARCH_PATH_CORE:
  8026. return sizeof(p_rarch->path_libretro);
  8027. case RARCH_PATH_NONE:
  8028. case RARCH_PATH_NAMES:
  8029. break;
  8030. }
  8031. return 0;
  8032. }
  8033. static void path_set_names(struct rarch_state *p_rarch, const char *path)
  8034. {
  8035. global_t *global = &p_rarch->g_extern;
  8036. path_set_basename(p_rarch, path);
  8037. if (global)
  8038. {
  8039. if (!retroarch_override_setting_is_set(
  8040. RARCH_OVERRIDE_SETTING_SAVE_PATH, NULL))
  8041. fill_pathname_noext(global->name.savefile,
  8042. p_rarch->path_main_basename,
  8043. ".srm", sizeof(global->name.savefile));
  8044. if (!retroarch_override_setting_is_set(
  8045. RARCH_OVERRIDE_SETTING_STATE_PATH, NULL))
  8046. fill_pathname_noext(global->name.savestate,
  8047. p_rarch->path_main_basename,
  8048. ".state", sizeof(global->name.savestate));
  8049. #ifdef HAVE_CHEATS
  8050. if (!string_is_empty(p_rarch->path_main_basename))
  8051. fill_pathname_noext(global->name.cheatfile,
  8052. p_rarch->path_main_basename,
  8053. ".cht", sizeof(global->name.cheatfile));
  8054. #endif
  8055. }
  8056. path_set_redirect(p_rarch);
  8057. }
  8058. bool path_set(enum rarch_path_type type, const char *path)
  8059. {
  8060. struct rarch_state *p_rarch = &rarch_st;
  8061. if (!path)
  8062. return false;
  8063. switch (type)
  8064. {
  8065. case RARCH_PATH_BASENAME:
  8066. strlcpy(p_rarch->path_main_basename, path,
  8067. sizeof(p_rarch->path_main_basename));
  8068. break;
  8069. case RARCH_PATH_NAMES:
  8070. path_set_names(p_rarch, path);
  8071. break;
  8072. case RARCH_PATH_CORE:
  8073. strlcpy(p_rarch->path_libretro, path,
  8074. sizeof(p_rarch->path_libretro));
  8075. break;
  8076. case RARCH_PATH_DEFAULT_SHADER_PRESET:
  8077. strlcpy(p_rarch->path_default_shader_preset, path,
  8078. sizeof(p_rarch->path_default_shader_preset));
  8079. break;
  8080. case RARCH_PATH_CONFIG_APPEND:
  8081. strlcpy(p_rarch->path_config_append_file, path,
  8082. sizeof(p_rarch->path_config_append_file));
  8083. break;
  8084. case RARCH_PATH_CONFIG:
  8085. strlcpy(p_rarch->path_config_file, path,
  8086. sizeof(p_rarch->path_config_file));
  8087. break;
  8088. case RARCH_PATH_SUBSYSTEM:
  8089. strlcpy(p_rarch->subsystem_path, path,
  8090. sizeof(p_rarch->subsystem_path));
  8091. break;
  8092. case RARCH_PATH_CORE_OPTIONS:
  8093. strlcpy(p_rarch->path_core_options_file, path,
  8094. sizeof(p_rarch->path_core_options_file));
  8095. break;
  8096. case RARCH_PATH_CONTENT:
  8097. strlcpy(p_rarch->path_content, path,
  8098. sizeof(p_rarch->path_content));
  8099. break;
  8100. case RARCH_PATH_NONE:
  8101. break;
  8102. }
  8103. return true;
  8104. }
  8105. bool path_is_empty(enum rarch_path_type type)
  8106. {
  8107. struct rarch_state *p_rarch = &rarch_st;
  8108. switch (type)
  8109. {
  8110. case RARCH_PATH_DEFAULT_SHADER_PRESET:
  8111. if (string_is_empty(p_rarch->path_default_shader_preset))
  8112. return true;
  8113. break;
  8114. case RARCH_PATH_SUBSYSTEM:
  8115. if (string_is_empty(p_rarch->subsystem_path))
  8116. return true;
  8117. break;
  8118. case RARCH_PATH_CONFIG:
  8119. if (string_is_empty(p_rarch->path_config_file))
  8120. return true;
  8121. break;
  8122. case RARCH_PATH_CORE_OPTIONS:
  8123. if (string_is_empty(p_rarch->path_core_options_file))
  8124. return true;
  8125. break;
  8126. case RARCH_PATH_CONFIG_APPEND:
  8127. if (string_is_empty(p_rarch->path_config_append_file))
  8128. return true;
  8129. break;
  8130. case RARCH_PATH_CONTENT:
  8131. if (string_is_empty(p_rarch->path_content))
  8132. return true;
  8133. break;
  8134. case RARCH_PATH_CORE:
  8135. if (string_is_empty(p_rarch->path_libretro))
  8136. return true;
  8137. break;
  8138. case RARCH_PATH_BASENAME:
  8139. if (string_is_empty(p_rarch->path_main_basename))
  8140. return true;
  8141. break;
  8142. case RARCH_PATH_NONE:
  8143. case RARCH_PATH_NAMES:
  8144. break;
  8145. }
  8146. return false;
  8147. }
  8148. void path_clear(enum rarch_path_type type)
  8149. {
  8150. struct rarch_state *p_rarch = &rarch_st;
  8151. switch (type)
  8152. {
  8153. case RARCH_PATH_SUBSYSTEM:
  8154. *p_rarch->subsystem_path = '\0';
  8155. break;
  8156. case RARCH_PATH_CORE:
  8157. *p_rarch->path_libretro = '\0';
  8158. break;
  8159. case RARCH_PATH_CONFIG:
  8160. *p_rarch->path_config_file = '\0';
  8161. break;
  8162. case RARCH_PATH_CONTENT:
  8163. *p_rarch->path_content = '\0';
  8164. break;
  8165. case RARCH_PATH_BASENAME:
  8166. *p_rarch->path_main_basename = '\0';
  8167. break;
  8168. case RARCH_PATH_CORE_OPTIONS:
  8169. *p_rarch->path_core_options_file = '\0';
  8170. break;
  8171. case RARCH_PATH_DEFAULT_SHADER_PRESET:
  8172. *p_rarch->path_default_shader_preset = '\0';
  8173. break;
  8174. case RARCH_PATH_CONFIG_APPEND:
  8175. *p_rarch->path_config_append_file = '\0';
  8176. break;
  8177. case RARCH_PATH_NONE:
  8178. case RARCH_PATH_NAMES:
  8179. break;
  8180. }
  8181. }
  8182. static void path_clear_all(void)
  8183. {
  8184. path_clear(RARCH_PATH_CONTENT);
  8185. path_clear(RARCH_PATH_CONFIG);
  8186. path_clear(RARCH_PATH_CONFIG_APPEND);
  8187. path_clear(RARCH_PATH_CORE_OPTIONS);
  8188. path_clear(RARCH_PATH_BASENAME);
  8189. }
  8190. enum rarch_content_type path_is_media_type(const char *path)
  8191. {
  8192. char ext_lower[128];
  8193. ext_lower[0] = '\0';
  8194. strlcpy(ext_lower, path_get_extension(path), sizeof(ext_lower));
  8195. string_to_lower(ext_lower);
  8196. /* hack, to detect livestreams so the ffmpeg core can be started */
  8197. if (string_starts_with_size(path, "udp://", STRLEN_CONST("udp://")) ||
  8198. string_starts_with_size(path, "http://", STRLEN_CONST("http://")) ||
  8199. string_starts_with_size(path, "https://", STRLEN_CONST("https://")) ||
  8200. string_starts_with_size(path, "tcp://", STRLEN_CONST("tcp://")) ||
  8201. string_starts_with_size(path, "rtmp://", STRLEN_CONST("rtmp://")) ||
  8202. string_starts_with_size(path, "rtp://", STRLEN_CONST("rtp://")))
  8203. return RARCH_CONTENT_MOVIE;
  8204. switch (msg_hash_to_file_type(msg_hash_calculate(ext_lower)))
  8205. {
  8206. #if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
  8207. case FILE_TYPE_OGM:
  8208. case FILE_TYPE_MKV:
  8209. case FILE_TYPE_AVI:
  8210. case FILE_TYPE_MP4:
  8211. case FILE_TYPE_FLV:
  8212. case FILE_TYPE_WEBM:
  8213. case FILE_TYPE_3GP:
  8214. case FILE_TYPE_3G2:
  8215. case FILE_TYPE_F4F:
  8216. case FILE_TYPE_F4V:
  8217. case FILE_TYPE_MOV:
  8218. case FILE_TYPE_WMV:
  8219. case FILE_TYPE_MPG:
  8220. case FILE_TYPE_MPEG:
  8221. case FILE_TYPE_VOB:
  8222. case FILE_TYPE_ASF:
  8223. case FILE_TYPE_DIVX:
  8224. case FILE_TYPE_M2P:
  8225. case FILE_TYPE_M2TS:
  8226. case FILE_TYPE_PS:
  8227. case FILE_TYPE_TS:
  8228. case FILE_TYPE_MXF:
  8229. return RARCH_CONTENT_MOVIE;
  8230. case FILE_TYPE_WMA:
  8231. case FILE_TYPE_OGG:
  8232. case FILE_TYPE_MP3:
  8233. case FILE_TYPE_M4A:
  8234. case FILE_TYPE_FLAC:
  8235. case FILE_TYPE_WAV:
  8236. return RARCH_CONTENT_MUSIC;
  8237. #endif
  8238. #ifdef HAVE_IMAGEVIEWER
  8239. case FILE_TYPE_JPEG:
  8240. case FILE_TYPE_PNG:
  8241. case FILE_TYPE_TGA:
  8242. case FILE_TYPE_BMP:
  8243. return RARCH_CONTENT_IMAGE;
  8244. #endif
  8245. #ifdef HAVE_IBXM
  8246. case FILE_TYPE_MOD:
  8247. case FILE_TYPE_S3M:
  8248. case FILE_TYPE_XM:
  8249. return RARCH_CONTENT_MUSIC;
  8250. #endif
  8251. #ifdef HAVE_GONG
  8252. case FILE_TYPE_GONG:
  8253. return RARCH_CONTENT_GONG;
  8254. #endif
  8255. case FILE_TYPE_NONE:
  8256. default:
  8257. break;
  8258. }
  8259. return RARCH_CONTENT_NONE;
  8260. }
  8261. static void path_deinit_subsystem(struct rarch_state *p_rarch)
  8262. {
  8263. if (p_rarch->subsystem_fullpaths)
  8264. string_list_free(p_rarch->subsystem_fullpaths);
  8265. p_rarch->subsystem_fullpaths = NULL;
  8266. }
  8267. static void dir_free_shader(struct rarch_state *p_rarch)
  8268. {
  8269. struct rarch_dir_shader_list *dir_list =
  8270. (struct rarch_dir_shader_list*)&p_rarch->dir_shader_list;
  8271. settings_t *settings = p_rarch->configuration_settings;
  8272. bool shader_remember_last_dir = settings->bools.video_shader_remember_last_dir;
  8273. if (dir_list->shader_list)
  8274. {
  8275. dir_list_free(dir_list->shader_list);
  8276. dir_list->shader_list = NULL;
  8277. }
  8278. if (dir_list->directory)
  8279. {
  8280. free(dir_list->directory);
  8281. dir_list->directory = NULL;
  8282. }
  8283. dir_list->selection = 0;
  8284. dir_list->shader_loaded = false;
  8285. dir_list->remember_last_preset_dir = shader_remember_last_dir;
  8286. }
  8287. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  8288. static bool dir_init_shader_internal(
  8289. struct rarch_state *p_rarch,
  8290. const char *shader_dir,
  8291. const char *shader_file_name,
  8292. bool show_hidden_files)
  8293. {
  8294. struct rarch_dir_shader_list *dir_list = (struct rarch_dir_shader_list*)
  8295. &p_rarch->dir_shader_list;
  8296. struct string_list *new_list = dir_list_new_special(
  8297. shader_dir, DIR_LIST_SHADERS, NULL, show_hidden_files);
  8298. settings_t *settings = p_rarch->configuration_settings;
  8299. bool shader_remember_last_dir = settings->bools.video_shader_remember_last_dir;
  8300. bool search_file_name = shader_remember_last_dir &&
  8301. !string_is_empty(shader_file_name);
  8302. bool file_name_found = false;
  8303. size_t i;
  8304. if (!new_list)
  8305. return false;
  8306. if (new_list->size < 1)
  8307. {
  8308. dir_list_free(new_list);
  8309. return false;
  8310. }
  8311. dir_list_sort(new_list, false);
  8312. dir_list->shader_list = new_list;
  8313. dir_list->directory = strdup(shader_dir);
  8314. dir_list->selection = 0;
  8315. dir_list->shader_loaded = false;
  8316. dir_list->remember_last_preset_dir = shader_remember_last_dir;
  8317. for (i = 0; i < new_list->size; i++)
  8318. {
  8319. const char *file_path = new_list->elems[i].data;
  8320. if (string_is_empty(file_path))
  8321. continue;
  8322. RARCH_LOG("[Shaders]: %s \"%s\"\n",
  8323. msg_hash_to_str(MSG_FOUND_SHADER),
  8324. file_path);
  8325. /* If a shader file name has been provided,
  8326. * search the list for a match and set 'selection'
  8327. * index if found */
  8328. if (search_file_name && !file_name_found)
  8329. {
  8330. const char *file_name = path_basename(file_path);
  8331. if (!string_is_empty(file_name) &&
  8332. string_is_equal(file_name, shader_file_name))
  8333. {
  8334. dir_list->selection = i;
  8335. file_name_found = true;
  8336. }
  8337. }
  8338. }
  8339. return true;
  8340. }
  8341. static void dir_init_shader(struct rarch_state *p_rarch)
  8342. {
  8343. settings_t *settings = p_rarch->configuration_settings;
  8344. bool show_hidden_files = settings->bools.show_hidden_files;
  8345. bool shader_remember_last_dir = settings->bools.video_shader_remember_last_dir;
  8346. const char *directory_video_shader = settings->paths.directory_video_shader;
  8347. const char *directory_menu_config = settings->paths.directory_menu_config;
  8348. const char *last_shader_preset_dir = NULL;
  8349. const char *last_shader_preset_file_name = NULL;
  8350. #if defined(HAVE_MENU)
  8351. enum rarch_shader_type last_shader_preset_type = menu_driver_get_last_shader_preset_type();
  8352. menu_driver_get_last_shader_preset_path(
  8353. &last_shader_preset_dir, &last_shader_preset_file_name);
  8354. #else
  8355. enum rarch_shader_type last_shader_preset_type = RARCH_SHADER_NONE;
  8356. #endif
  8357. /* Always free existing shader list */
  8358. dir_free_shader(p_rarch);
  8359. /* Try directory of last selected shader preset */
  8360. if (shader_remember_last_dir &&
  8361. (last_shader_preset_type != RARCH_SHADER_NONE) &&
  8362. !string_is_empty(last_shader_preset_dir) &&
  8363. dir_init_shader_internal(p_rarch,
  8364. last_shader_preset_dir,
  8365. last_shader_preset_file_name,
  8366. show_hidden_files))
  8367. return;
  8368. /* Try video shaders directory */
  8369. if (!string_is_empty(directory_video_shader) &&
  8370. dir_init_shader_internal(
  8371. p_rarch, directory_video_shader, NULL, show_hidden_files))
  8372. return;
  8373. /* Try config directory */
  8374. if (!string_is_empty(directory_menu_config) &&
  8375. dir_init_shader_internal(
  8376. p_rarch, directory_menu_config, NULL, show_hidden_files))
  8377. return;
  8378. /* Try 'top level' directory containing main
  8379. * RetroArch config file */
  8380. if (!path_is_empty(RARCH_PATH_CONFIG))
  8381. {
  8382. char *rarch_config_directory = strdup(path_get(RARCH_PATH_CONFIG));
  8383. path_basedir(rarch_config_directory);
  8384. if (!string_is_empty(rarch_config_directory))
  8385. dir_init_shader_internal(
  8386. p_rarch, rarch_config_directory, NULL, show_hidden_files);
  8387. free(rarch_config_directory);
  8388. }
  8389. }
  8390. /**
  8391. * dir_check_shader:
  8392. * @pressed_next : Was next shader key pressed?
  8393. * @pressed_prev : Was previous shader key pressed?
  8394. *
  8395. * Checks if any one of the shader keys has been pressed for this frame:
  8396. * a) Next shader index.
  8397. * b) Previous shader index.
  8398. *
  8399. * Will also immediately apply the shader.
  8400. **/
  8401. static void dir_check_shader(struct rarch_state *p_rarch,
  8402. bool pressed_next, bool pressed_prev)
  8403. {
  8404. struct rarch_dir_shader_list *dir_list = (struct rarch_dir_shader_list*)
  8405. &p_rarch->dir_shader_list;
  8406. settings_t *settings = p_rarch->configuration_settings;
  8407. bool shader_remember_last_dir = settings->bools.video_shader_remember_last_dir;
  8408. const char *last_shader_preset_dir = NULL;
  8409. const char *last_shader_preset_file_name = NULL;
  8410. const char *set_shader_path = NULL;
  8411. bool dir_list_initialised = false;
  8412. #if defined(HAVE_MENU)
  8413. enum rarch_shader_type last_shader_preset_type = menu_driver_get_last_shader_preset_type();
  8414. menu_driver_get_last_shader_preset_path(
  8415. &last_shader_preset_dir, &last_shader_preset_file_name);
  8416. #else
  8417. enum rarch_shader_type last_shader_preset_type = RARCH_SHADER_NONE;
  8418. #endif
  8419. /* Check whether shader list needs to be
  8420. * (re)initialised */
  8421. if (!dir_list->shader_list ||
  8422. (dir_list->remember_last_preset_dir != shader_remember_last_dir) ||
  8423. (shader_remember_last_dir &&
  8424. (last_shader_preset_type != RARCH_SHADER_NONE) &&
  8425. !string_is_equal(dir_list->directory, last_shader_preset_dir)))
  8426. {
  8427. dir_init_shader(p_rarch);
  8428. dir_list_initialised = true;
  8429. }
  8430. if (!dir_list->shader_list ||
  8431. (dir_list->shader_list->size < 1))
  8432. return;
  8433. /* Check whether a 'last used' shader file
  8434. * name is provided
  8435. * > Note: We can end up calling
  8436. * string_is_equal(dir_list->directory, last_shader_preset_dir)
  8437. * twice. This is wasteful, but we cannot safely cache
  8438. * the first result since dir_init_shader() is called
  8439. * in-between the two invocations... */
  8440. if (shader_remember_last_dir &&
  8441. (last_shader_preset_type != RARCH_SHADER_NONE) &&
  8442. string_is_equal(dir_list->directory, last_shader_preset_dir) &&
  8443. !string_is_empty(last_shader_preset_file_name))
  8444. {
  8445. /* Ensure that we start with a dir_list selection
  8446. * index matching the last used shader */
  8447. if (!dir_list_initialised)
  8448. {
  8449. const char *current_file_path = NULL;
  8450. const char *current_file_name = NULL;
  8451. if (dir_list->selection < dir_list->shader_list->size)
  8452. current_file_path = dir_list->shader_list->elems[dir_list->selection].data;
  8453. if (!string_is_empty(current_file_path))
  8454. current_file_name = path_basename(current_file_path);
  8455. if (!string_is_empty(current_file_name) &&
  8456. !string_is_equal(current_file_name, last_shader_preset_file_name))
  8457. {
  8458. size_t i;
  8459. for (i = 0; i < dir_list->shader_list->size; i++)
  8460. {
  8461. const char *file_path = dir_list->shader_list->elems[i].data;
  8462. const char *file_name = NULL;
  8463. if (string_is_empty(file_path))
  8464. continue;
  8465. file_name = path_basename(file_path);
  8466. if (string_is_empty(file_name))
  8467. continue;
  8468. if (string_is_equal(file_name, last_shader_preset_file_name))
  8469. {
  8470. dir_list->selection = i;
  8471. break;
  8472. }
  8473. }
  8474. }
  8475. }
  8476. /* Check whether the shader referenced by the
  8477. * current selection index is already loaded */
  8478. if (!dir_list->shader_loaded)
  8479. {
  8480. struct video_shader *shader = menu_shader_get();
  8481. if (shader && !string_is_empty(shader->loaded_preset_path))
  8482. {
  8483. char last_shader_path[PATH_MAX_LENGTH];
  8484. last_shader_path[0] = '\0';
  8485. fill_pathname_join(last_shader_path,
  8486. last_shader_preset_dir, last_shader_preset_file_name,
  8487. sizeof(last_shader_path));
  8488. if (string_is_equal(last_shader_path, shader->loaded_preset_path))
  8489. dir_list->shader_loaded = true;
  8490. }
  8491. }
  8492. }
  8493. /* Select next shader in list */
  8494. if (pressed_next)
  8495. {
  8496. /* Only increment selection if a shader
  8497. * from this list has already been loaded
  8498. * (otherwise first entry in the list may
  8499. * be skipped) */
  8500. if (dir_list->shader_loaded)
  8501. {
  8502. if (dir_list->selection < dir_list->shader_list->size - 1)
  8503. dir_list->selection++;
  8504. else
  8505. dir_list->selection = 0;
  8506. }
  8507. }
  8508. /* Select previous shader in list */
  8509. else if (pressed_prev)
  8510. {
  8511. if (dir_list->selection > 0)
  8512. dir_list->selection--;
  8513. else
  8514. dir_list->selection = dir_list->shader_list->size - 1;
  8515. }
  8516. else
  8517. return;
  8518. set_shader_path = dir_list->shader_list->elems[dir_list->selection].data;
  8519. #if defined(HAVE_MENU)
  8520. menu_driver_set_last_shader_preset_path(set_shader_path);
  8521. #endif
  8522. command_set_shader(set_shader_path);
  8523. dir_list->shader_loaded = true;
  8524. }
  8525. #endif
  8526. /* get size functions */
  8527. size_t dir_get_size(enum rarch_dir_type type)
  8528. {
  8529. struct rarch_state *p_rarch = &rarch_st;
  8530. switch (type)
  8531. {
  8532. case RARCH_DIR_SYSTEM:
  8533. return sizeof(p_rarch->dir_system);
  8534. case RARCH_DIR_SAVESTATE:
  8535. return sizeof(p_rarch->dir_savestate);
  8536. case RARCH_DIR_CURRENT_SAVESTATE:
  8537. return sizeof(p_rarch->current_savestate_dir);
  8538. case RARCH_DIR_SAVEFILE:
  8539. return sizeof(p_rarch->dir_savefile);
  8540. case RARCH_DIR_CURRENT_SAVEFILE:
  8541. return sizeof(p_rarch->current_savefile_dir);
  8542. case RARCH_DIR_NONE:
  8543. break;
  8544. }
  8545. return 0;
  8546. }
  8547. /* clear functions */
  8548. void dir_clear(enum rarch_dir_type type)
  8549. {
  8550. struct rarch_state *p_rarch = &rarch_st;
  8551. switch (type)
  8552. {
  8553. case RARCH_DIR_SAVEFILE:
  8554. *p_rarch->dir_savefile = '\0';
  8555. break;
  8556. case RARCH_DIR_CURRENT_SAVEFILE:
  8557. *p_rarch->current_savefile_dir = '\0';
  8558. break;
  8559. case RARCH_DIR_SAVESTATE:
  8560. *p_rarch->dir_savestate = '\0';
  8561. break;
  8562. case RARCH_DIR_CURRENT_SAVESTATE:
  8563. *p_rarch->current_savestate_dir = '\0';
  8564. break;
  8565. case RARCH_DIR_SYSTEM:
  8566. *p_rarch->dir_system = '\0';
  8567. break;
  8568. case RARCH_DIR_NONE:
  8569. break;
  8570. }
  8571. }
  8572. static void dir_clear_all(void)
  8573. {
  8574. dir_clear(RARCH_DIR_SYSTEM);
  8575. dir_clear(RARCH_DIR_SAVEFILE);
  8576. dir_clear(RARCH_DIR_SAVESTATE);
  8577. }
  8578. /* get ptr functions */
  8579. char *dir_get_ptr(enum rarch_dir_type type)
  8580. {
  8581. struct rarch_state *p_rarch = &rarch_st;
  8582. switch (type)
  8583. {
  8584. case RARCH_DIR_SAVEFILE:
  8585. return p_rarch->dir_savefile;
  8586. case RARCH_DIR_CURRENT_SAVEFILE:
  8587. return p_rarch->current_savefile_dir;
  8588. case RARCH_DIR_SAVESTATE:
  8589. return p_rarch->dir_savestate;
  8590. case RARCH_DIR_CURRENT_SAVESTATE:
  8591. return p_rarch->current_savestate_dir;
  8592. case RARCH_DIR_SYSTEM:
  8593. return p_rarch->dir_system;
  8594. case RARCH_DIR_NONE:
  8595. break;
  8596. }
  8597. return NULL;
  8598. }
  8599. void dir_set(enum rarch_dir_type type, const char *path)
  8600. {
  8601. struct rarch_state *p_rarch = &rarch_st;
  8602. switch (type)
  8603. {
  8604. case RARCH_DIR_CURRENT_SAVEFILE:
  8605. strlcpy(p_rarch->current_savefile_dir, path,
  8606. sizeof(p_rarch->current_savefile_dir));
  8607. break;
  8608. case RARCH_DIR_SAVEFILE:
  8609. strlcpy(p_rarch->dir_savefile, path,
  8610. sizeof(p_rarch->dir_savefile));
  8611. break;
  8612. case RARCH_DIR_CURRENT_SAVESTATE:
  8613. strlcpy(p_rarch->current_savestate_dir, path,
  8614. sizeof(p_rarch->current_savestate_dir));
  8615. break;
  8616. case RARCH_DIR_SAVESTATE:
  8617. strlcpy(p_rarch->dir_savestate, path,
  8618. sizeof(p_rarch->dir_savestate));
  8619. break;
  8620. case RARCH_DIR_SYSTEM:
  8621. strlcpy(p_rarch->dir_system, path,
  8622. sizeof(p_rarch->dir_system));
  8623. break;
  8624. case RARCH_DIR_NONE:
  8625. break;
  8626. }
  8627. }
  8628. void dir_check_defaults(const char *custom_ini_path)
  8629. {
  8630. size_t i;
  8631. /* Early return for people with a custom folder setup
  8632. * so it doesn't create unnecessary directories */
  8633. if (!string_is_empty(custom_ini_path) &&
  8634. path_is_valid(custom_ini_path))
  8635. return;
  8636. for (i = 0; i < DEFAULT_DIR_LAST; i++)
  8637. {
  8638. const char *dir_path = g_defaults.dirs[i];
  8639. char new_path[PATH_MAX_LENGTH];
  8640. if (string_is_empty(dir_path))
  8641. continue;
  8642. new_path[0] = '\0';
  8643. fill_pathname_expand_special(new_path,
  8644. dir_path, sizeof(new_path));
  8645. if (!path_is_directory(new_path))
  8646. path_mkdir(new_path);
  8647. }
  8648. }
  8649. #ifdef HAVE_ACCESSIBILITY
  8650. static bool is_accessibility_enabled(struct rarch_state *p_rarch)
  8651. {
  8652. settings_t *settings = p_rarch->configuration_settings;
  8653. bool accessibility_enable = settings->bools.accessibility_enable;
  8654. bool accessibility_enabled = p_rarch->accessibility_enabled;
  8655. if (accessibility_enabled || accessibility_enable)
  8656. return true;
  8657. return false;
  8658. }
  8659. #endif
  8660. bool gfx_widgets_ready(void)
  8661. {
  8662. #ifdef HAVE_GFX_WIDGETS
  8663. struct rarch_state *p_rarch = &rarch_st;
  8664. return p_rarch->widgets_active;
  8665. #else
  8666. return false;
  8667. #endif
  8668. }
  8669. #ifdef HAVE_MENU
  8670. static void menu_input_search_cb(void *userdata, const char *str)
  8671. {
  8672. const char *label = NULL;
  8673. unsigned type = MENU_SETTINGS_NONE;
  8674. struct rarch_state *p_rarch = &rarch_st;
  8675. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  8676. if (string_is_empty(str))
  8677. goto end;
  8678. /* Determine whether we are currently
  8679. * viewing a menu list with 'search
  8680. * filter' support */
  8681. file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
  8682. NULL, &label, &type, NULL);
  8683. if (menu_driver_search_filter_enabled(label, type))
  8684. {
  8685. /* Add search term */
  8686. if (menu_driver_search_push(str))
  8687. {
  8688. bool refresh = false;
  8689. /* Reset navigation pointer */
  8690. menu_st->selection_ptr = 0;
  8691. menu_driver_navigation_set(false);
  8692. /* Refresh menu */
  8693. menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
  8694. menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
  8695. }
  8696. }
  8697. /* Perform a regular search: jump to the
  8698. * first matching entry */
  8699. else
  8700. {
  8701. size_t idx = 0;
  8702. struct rarch_state *p_rarch = &rarch_st;
  8703. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  8704. menu_list_t *menu_list = menu_st->entries.list;
  8705. file_list_t *selection_buf = menu_list ? MENU_LIST_GET_SELECTION(menu_list, (unsigned)0) : NULL;
  8706. if (!selection_buf)
  8707. goto end;
  8708. if (file_list_search(selection_buf, str, &idx))
  8709. {
  8710. menu_st->selection_ptr = idx;
  8711. menu_driver_navigation_set(true);
  8712. }
  8713. }
  8714. end:
  8715. menu_input_dialog_end();
  8716. }
  8717. const char *menu_input_dialog_get_label_buffer(void)
  8718. {
  8719. struct rarch_state *p_rarch = &rarch_st;
  8720. return p_rarch->menu_input_dialog_keyboard_label;
  8721. }
  8722. const char *menu_input_dialog_get_label_setting_buffer(void)
  8723. {
  8724. struct rarch_state *p_rarch = &rarch_st;
  8725. return p_rarch->menu_input_dialog_keyboard_label_setting;
  8726. }
  8727. void menu_input_dialog_end(void)
  8728. {
  8729. struct rarch_state *p_rarch = &rarch_st;
  8730. p_rarch->menu_input_dialog_keyboard_type = 0;
  8731. p_rarch->menu_input_dialog_keyboard_idx = 0;
  8732. p_rarch->menu_input_dialog_keyboard_display = false;
  8733. p_rarch->menu_input_dialog_keyboard_label[0] = '\0';
  8734. p_rarch->menu_input_dialog_keyboard_label_setting[0] = '\0';
  8735. /* Avoid triggering states on pressing return. */
  8736. /* Inhibits input for 2 frames
  8737. * > Required, since input is ignored for 1 frame
  8738. * after certain events - e.g. closing the OSK */
  8739. p_rarch->input_driver_flushing_input = 2;
  8740. }
  8741. const char *menu_input_dialog_get_buffer(void)
  8742. {
  8743. struct rarch_state *p_rarch = &rarch_st;
  8744. if (!(*p_rarch->menu_input_dialog_keyboard_buffer))
  8745. return "";
  8746. return *p_rarch->menu_input_dialog_keyboard_buffer;
  8747. }
  8748. unsigned menu_input_dialog_get_kb_idx(void)
  8749. {
  8750. struct rarch_state *p_rarch = &rarch_st;
  8751. return p_rarch->menu_input_dialog_keyboard_idx;
  8752. }
  8753. bool menu_input_dialog_start_search(void)
  8754. {
  8755. struct rarch_state *p_rarch = &rarch_st;
  8756. menu_handle_t *menu = p_rarch->menu_driver_data;
  8757. if (!menu)
  8758. return false;
  8759. p_rarch->menu_input_dialog_keyboard_display = true;
  8760. strlcpy(p_rarch->menu_input_dialog_keyboard_label,
  8761. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SEARCH),
  8762. sizeof(p_rarch->menu_input_dialog_keyboard_label));
  8763. if (p_rarch->keyboard_line.buffer)
  8764. free(p_rarch->keyboard_line.buffer);
  8765. p_rarch->keyboard_line.buffer = NULL;
  8766. p_rarch->keyboard_line.ptr = 0;
  8767. p_rarch->keyboard_line.size = 0;
  8768. p_rarch->keyboard_line.cb = NULL;
  8769. p_rarch->keyboard_line.userdata = NULL;
  8770. p_rarch->keyboard_line.enabled = false;
  8771. #ifdef HAVE_ACCESSIBILITY
  8772. if (is_accessibility_enabled(p_rarch))
  8773. accessibility_speak_priority(p_rarch, (char*)
  8774. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SEARCH), 10);
  8775. #endif
  8776. p_rarch->menu_input_dialog_keyboard_buffer =
  8777. input_keyboard_start_line(menu,
  8778. &p_rarch->keyboard_line,
  8779. menu_input_search_cb);
  8780. /* While reading keyboard line input, we have to block all hotkeys. */
  8781. p_rarch->keyboard_mapping_blocked= true;
  8782. return true;
  8783. }
  8784. bool menu_input_dialog_start(menu_input_ctx_line_t *line)
  8785. {
  8786. struct rarch_state *p_rarch = &rarch_st;
  8787. menu_handle_t *menu = p_rarch->menu_driver_data;
  8788. if (!line || !menu)
  8789. return false;
  8790. p_rarch->menu_input_dialog_keyboard_display = true;
  8791. /* Only copy over the menu label and setting if they exist. */
  8792. if (line->label)
  8793. strlcpy(p_rarch->menu_input_dialog_keyboard_label,
  8794. line->label,
  8795. sizeof(p_rarch->menu_input_dialog_keyboard_label));
  8796. if (line->label_setting)
  8797. strlcpy(p_rarch->menu_input_dialog_keyboard_label_setting,
  8798. line->label_setting,
  8799. sizeof(p_rarch->menu_input_dialog_keyboard_label_setting));
  8800. p_rarch->menu_input_dialog_keyboard_type = line->type;
  8801. p_rarch->menu_input_dialog_keyboard_idx = line->idx;
  8802. if (p_rarch->keyboard_line.buffer)
  8803. free(p_rarch->keyboard_line.buffer);
  8804. p_rarch->keyboard_line.buffer = NULL;
  8805. p_rarch->keyboard_line.ptr = 0;
  8806. p_rarch->keyboard_line.size = 0;
  8807. p_rarch->keyboard_line.cb = NULL;
  8808. p_rarch->keyboard_line.userdata = NULL;
  8809. p_rarch->keyboard_line.enabled = false;
  8810. #ifdef HAVE_ACCESSIBILITY
  8811. if (is_accessibility_enabled(p_rarch))
  8812. accessibility_speak_priority(p_rarch, "Keyboard input:", 10);
  8813. #endif
  8814. p_rarch->menu_input_dialog_keyboard_buffer =
  8815. input_keyboard_start_line(menu,
  8816. &p_rarch->keyboard_line,
  8817. line->cb);
  8818. /* While reading keyboard line input, we have to block all hotkeys. */
  8819. p_rarch->keyboard_mapping_blocked= true;
  8820. return true;
  8821. }
  8822. static void osk_update_last_codepoint(
  8823. unsigned *last_codepoint,
  8824. unsigned *last_codepoint_len,
  8825. const char *word)
  8826. {
  8827. const char *letter = word;
  8828. const char *pos = letter;
  8829. for (;;)
  8830. {
  8831. unsigned codepoint = utf8_walk(&letter);
  8832. if (letter[0] == 0)
  8833. {
  8834. *last_codepoint = codepoint;
  8835. *last_codepoint_len = (unsigned)(letter - pos);
  8836. break;
  8837. }
  8838. pos = letter;
  8839. }
  8840. }
  8841. bool menu_input_dialog_get_display_kb(void)
  8842. {
  8843. struct rarch_state *p_rarch = &rarch_st;
  8844. #ifdef HAVE_LIBNX
  8845. SwkbdConfig kbd;
  8846. Result rc;
  8847. /* Indicates that we are "typing" from the swkbd
  8848. * result to RetroArch with repeated calls to input_keyboard_event
  8849. * This prevents input_keyboard_event from calling back
  8850. * menu_input_dialog_get_display_kb, looping indefinintely */
  8851. static bool typing = false;
  8852. if (typing)
  8853. return false;
  8854. /* swkbd only works on "real" titles */
  8855. if ( __nx_applet_type != AppletType_Application
  8856. && __nx_applet_type != AppletType_SystemApplication)
  8857. return p_rarch->menu_input_dialog_keyboard_display;
  8858. if (!p_rarch->menu_input_dialog_keyboard_display)
  8859. return false;
  8860. rc = swkbdCreate(&kbd, 0);
  8861. if (R_SUCCEEDED(rc))
  8862. {
  8863. unsigned i;
  8864. char buf[LIBNX_SWKBD_LIMIT] = {'\0'};
  8865. swkbdConfigMakePresetDefault(&kbd);
  8866. swkbdConfigSetGuideText(&kbd,
  8867. p_rarch->menu_input_dialog_keyboard_label);
  8868. rc = swkbdShow(&kbd, buf, sizeof(buf));
  8869. swkbdClose(&kbd);
  8870. /* RetroArch uses key-by-key input
  8871. so we need to simulate it */
  8872. typing = true;
  8873. for (i = 0; i < LIBNX_SWKBD_LIMIT; i++)
  8874. {
  8875. /* In case a previous "Enter" press closed the keyboard */
  8876. if (!p_rarch->menu_input_dialog_keyboard_display)
  8877. break;
  8878. if (buf[i] == '\n' || buf[i] == '\0')
  8879. input_keyboard_event(true, '\n', '\n', 0, RETRO_DEVICE_KEYBOARD);
  8880. else
  8881. {
  8882. const char *word = &buf[i];
  8883. /* input_keyboard_line_append expects a null-terminated
  8884. string, so just make one (yes, the touch keyboard is
  8885. a list of "null-terminated characters") */
  8886. char oldchar = buf[i+1];
  8887. buf[i+1] = '\0';
  8888. input_keyboard_line_append(&p_rarch->keyboard_line, word);
  8889. if (word[0] == 0)
  8890. {
  8891. p_rarch->osk_last_codepoint = 0;
  8892. p_rarch->osk_last_codepoint_len = 0;
  8893. }
  8894. else
  8895. osk_update_last_codepoint(
  8896. &p_rarch->osk_last_codepoint,
  8897. &p_rarch->osk_last_codepoint_len,
  8898. word);
  8899. buf[i+1] = oldchar;
  8900. }
  8901. }
  8902. /* fail-safe */
  8903. if (p_rarch->menu_input_dialog_keyboard_display)
  8904. input_keyboard_event(true, '\n', '\n', 0, RETRO_DEVICE_KEYBOARD);
  8905. typing = false;
  8906. libnx_apply_overclock();
  8907. return false;
  8908. }
  8909. libnx_apply_overclock();
  8910. #endif
  8911. return p_rarch->menu_input_dialog_keyboard_display;
  8912. }
  8913. /* Checks if the menu is still running */
  8914. bool menu_driver_is_alive(void)
  8915. {
  8916. struct rarch_state *p_rarch = &rarch_st;
  8917. return p_rarch->menu_driver_alive;
  8918. }
  8919. #endif
  8920. #if defined(HAVE_RUNAHEAD)
  8921. #if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
  8922. static char *strcpy_alloc(const char *src)
  8923. {
  8924. char *result = NULL;
  8925. size_t len = strlen(src);
  8926. if (len == 0)
  8927. return NULL;
  8928. result = (char*)malloc(len + 1);
  8929. strcpy_literal(result, src);
  8930. return result;
  8931. }
  8932. #endif
  8933. #endif
  8934. /* MESSAGE QUEUE */
  8935. static void retroarch_msg_queue_deinit(struct rarch_state *p_rarch)
  8936. {
  8937. RUNLOOP_MSG_QUEUE_LOCK(p_rarch);
  8938. msg_queue_deinitialize(&p_rarch->runloop_msg_queue);
  8939. RUNLOOP_MSG_QUEUE_UNLOCK(p_rarch);
  8940. #ifdef HAVE_THREADS
  8941. slock_free(p_rarch->runloop_msg_queue_lock);
  8942. p_rarch->runloop_msg_queue_lock = NULL;
  8943. #endif
  8944. p_rarch->runloop_msg_queue_size = 0;
  8945. }
  8946. static void retroarch_msg_queue_init(struct rarch_state *p_rarch)
  8947. {
  8948. retroarch_msg_queue_deinit(p_rarch);
  8949. msg_queue_initialize(&p_rarch->runloop_msg_queue, 8);
  8950. #ifdef HAVE_THREADS
  8951. p_rarch->runloop_msg_queue_lock = slock_new();
  8952. #endif
  8953. }
  8954. #ifdef HAVE_THREADS
  8955. static void retroarch_autosave_deinit(struct rarch_state *p_rarch)
  8956. {
  8957. const bool rarch_use_sram = p_rarch->rarch_use_sram;
  8958. if (rarch_use_sram)
  8959. autosave_deinit();
  8960. }
  8961. #endif
  8962. /* COMMAND */
  8963. #if defined(HAVE_COMMAND)
  8964. #if (defined(HAVE_STDIN_CMD) || defined(HAVE_NETWORK_CMD))
  8965. static void command_reply(
  8966. struct rarch_state *p_rarch,
  8967. const char * data, size_t len)
  8968. {
  8969. const enum cmd_source_t lastcmd_source = p_rarch->lastcmd_source;
  8970. switch (lastcmd_source)
  8971. {
  8972. case CMD_STDIN:
  8973. #ifdef HAVE_STDIN_CMD
  8974. fwrite(data, 1,len, stdout);
  8975. #endif
  8976. break;
  8977. case CMD_NETWORK:
  8978. #ifdef HAVE_NETWORK_CMD
  8979. sendto(p_rarch->lastcmd_net_fd, data, len, 0,
  8980. (struct sockaddr*)&p_rarch->lastcmd_net_source,
  8981. p_rarch->lastcmd_net_source_len);
  8982. #endif
  8983. break;
  8984. case CMD_NONE:
  8985. default:
  8986. break;
  8987. }
  8988. }
  8989. #endif
  8990. static bool command_version(const char* arg)
  8991. {
  8992. char reply[256] = {0};
  8993. #if (defined(HAVE_STDIN_CMD) || defined(HAVE_NETWORK_CMD))
  8994. struct rarch_state *p_rarch = &rarch_st;
  8995. #endif
  8996. snprintf(reply, sizeof(reply), "%s\n", PACKAGE_VERSION);
  8997. #if (defined(HAVE_STDIN_CMD) || defined(HAVE_NETWORK_CMD))
  8998. command_reply(p_rarch, reply, strlen(reply));
  8999. #endif
  9000. return true;
  9001. }
  9002. static bool command_get_status(const char* arg)
  9003. {
  9004. char reply[4096] = {0};
  9005. bool contentless = false;
  9006. bool is_inited = false;
  9007. struct rarch_state *p_rarch = &rarch_st;
  9008. content_get_status(&contentless, &is_inited);
  9009. if (!is_inited)
  9010. strcpy_literal(reply, "GET_STATUS CONTENTLESS");
  9011. else
  9012. {
  9013. /* add some content info */
  9014. const char *status = "PLAYING";
  9015. const char *content_name = path_basename(path_get(RARCH_PATH_BASENAME)); /* filename only without ext */
  9016. int content_crc32 = content_get_crc();
  9017. const char* system_id = NULL;
  9018. core_info_t *core_info = NULL;
  9019. core_info_get_current_core(&core_info);
  9020. if (p_rarch->runloop_paused)
  9021. status = "PAUSED";
  9022. if (core_info)
  9023. system_id = core_info->system_id;
  9024. if (!system_id)
  9025. system_id = p_rarch->runloop_system.info.library_name;
  9026. snprintf(reply, sizeof(reply), "GET_STATUS %s %s,%s,crc32=%x\n", status, system_id, content_name, content_crc32);
  9027. }
  9028. command_reply(p_rarch, reply, strlen(reply));
  9029. return true;
  9030. }
  9031. static bool command_show_osd_msg(const char* arg)
  9032. {
  9033. runloop_msg_queue_push(arg, 1, 180, false, NULL,
  9034. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  9035. return true;
  9036. }
  9037. static bool command_get_config_param(const char* arg)
  9038. {
  9039. char reply[8192] = {0};
  9040. struct rarch_state *p_rarch = &rarch_st;
  9041. const char *value = "unsupported";
  9042. settings_t *settings = p_rarch->configuration_settings;
  9043. bool video_fullscreen = settings->bools.video_fullscreen;
  9044. const char *dir_runtime_log = settings->paths.directory_runtime_log;
  9045. const char *log_dir = settings->paths.log_dir;
  9046. const char *directory_cache = settings->paths.directory_cache;
  9047. const char *directory_system = settings->paths.directory_system;
  9048. const char *path_username = settings->paths.username;
  9049. if (string_is_equal(arg, "video_fullscreen"))
  9050. {
  9051. if (video_fullscreen)
  9052. value = "true";
  9053. else
  9054. value = "false";
  9055. }
  9056. else if (string_is_equal(arg, "savefile_directory"))
  9057. value = p_rarch->dir_savefile;
  9058. else if (string_is_equal(arg, "savestate_directory"))
  9059. value = p_rarch->dir_savestate;
  9060. else if (string_is_equal(arg, "runtime_log_directory"))
  9061. value = dir_runtime_log;
  9062. else if (string_is_equal(arg, "log_dir"))
  9063. value = log_dir;
  9064. else if (string_is_equal(arg, "cache_directory"))
  9065. value = directory_cache;
  9066. else if (string_is_equal(arg, "system_directory"))
  9067. value = directory_system;
  9068. else if (string_is_equal(arg, "netplay_nickname"))
  9069. value = path_username;
  9070. /* TODO: query any string */
  9071. snprintf(reply, sizeof(reply), "GET_CONFIG_PARAM %s %s\n", arg, value);
  9072. command_reply(p_rarch, reply, strlen(reply));
  9073. return true;
  9074. }
  9075. #if defined(HAVE_CHEEVOS)
  9076. static bool command_read_ram(const char *arg)
  9077. {
  9078. unsigned i;
  9079. char *reply = NULL;
  9080. const uint8_t *data = NULL;
  9081. char *reply_at = NULL;
  9082. unsigned int nbytes = 0;
  9083. unsigned int alloc_size = 0;
  9084. unsigned int addr = -1;
  9085. unsigned int len = 0;
  9086. struct rarch_state *p_rarch = &rarch_st;
  9087. if (sscanf(arg, "%x %u", &addr, &nbytes) != 2)
  9088. return true;
  9089. /* We allocate more than needed, saving 20 bytes is not really relevant */
  9090. alloc_size = 40 + nbytes * 3;
  9091. reply = (char*)malloc(alloc_size);
  9092. reply[0] = '\0';
  9093. reply_at = reply + snprintf(
  9094. reply, alloc_size - 1, "READ_CORE_RAM" " %x", addr);
  9095. if ((data = rcheevos_patch_address(addr)))
  9096. {
  9097. for (i = 0; i < nbytes; i++)
  9098. snprintf(reply_at + 3 * i, 4, " %.2X", data[i]);
  9099. reply_at[3 * nbytes] = '\n';
  9100. len = reply_at + 3 * nbytes + 1 - reply;
  9101. }
  9102. else
  9103. {
  9104. strlcpy(reply_at, " -1\n", sizeof(reply) - strlen(reply));
  9105. len = reply_at + STRLEN_CONST(" -1\n") - reply;
  9106. }
  9107. command_reply(p_rarch, reply, len);
  9108. free(reply);
  9109. return true;
  9110. }
  9111. static bool command_write_ram(const char *arg)
  9112. {
  9113. unsigned int addr = (unsigned int)strtoul(arg, (char**)&arg, 16);
  9114. uint8_t *data = (uint8_t *)rcheevos_patch_address(addr);
  9115. if (!data)
  9116. return false;
  9117. if (rcheevos_hardcore_active())
  9118. {
  9119. RARCH_LOG("Achievements hardcore mode disabled by WRITE_CORE_RAM\n");
  9120. rcheevos_pause_hardcore();
  9121. }
  9122. while (*arg)
  9123. {
  9124. *data = strtoul(arg, (char**)&arg, 16);
  9125. data++;
  9126. }
  9127. return true;
  9128. }
  9129. #endif
  9130. static const rarch_memory_descriptor_t* command_memory_get_descriptor(const rarch_memory_map_t* mmap, unsigned address)
  9131. {
  9132. const rarch_memory_descriptor_t* desc = mmap->descriptors;
  9133. const rarch_memory_descriptor_t* end = desc + mmap->num_descriptors;
  9134. for (; desc < end; desc++)
  9135. {
  9136. if (desc->core.select == 0)
  9137. {
  9138. /* if select is 0, attempt to explicitly match the address */
  9139. if (address >= desc->core.start && address < desc->core.start + desc->core.len)
  9140. return desc;
  9141. }
  9142. else
  9143. {
  9144. /* otherwise, attempt to match the address by matching the select bits */
  9145. if (((desc->core.start ^ address) & desc->core.select) == 0)
  9146. {
  9147. /* sanity check - make sure the descriptor is large enough to hold the target address */
  9148. if (address - desc->core.start < desc->core.len)
  9149. return desc;
  9150. }
  9151. }
  9152. }
  9153. return NULL;
  9154. }
  9155. static uint8_t* command_memory_get_pointer(unsigned address, unsigned int* max_bytes, int for_write, char* reply_at, size_t len)
  9156. {
  9157. const rarch_system_info_t* system = runloop_get_system_info();
  9158. if (!system || system->mmaps.num_descriptors == 0)
  9159. strlcpy(reply_at, " -1 no memory map defined\n", len);
  9160. else
  9161. {
  9162. const rarch_memory_descriptor_t* desc = command_memory_get_descriptor(&system->mmaps, address);
  9163. if (!desc)
  9164. strlcpy(reply_at, " -1 no descriptor for address\n", len);
  9165. else if (!desc->core.ptr)
  9166. strlcpy(reply_at, " -1 no data for descriptor\n", len);
  9167. else if (for_write && (desc->core.flags & RETRO_MEMDESC_CONST))
  9168. strlcpy(reply_at, " -1 descriptor data is readonly\n", len);
  9169. else
  9170. {
  9171. const size_t offset = address - desc->core.start;
  9172. *max_bytes = (desc->core.len - offset);
  9173. return (uint8_t*)desc->core.ptr + desc->core.offset + offset;
  9174. }
  9175. }
  9176. *max_bytes = 0;
  9177. return NULL;
  9178. }
  9179. static bool command_read_memory(const char *arg)
  9180. {
  9181. unsigned i;
  9182. char* reply = NULL;
  9183. char* reply_at = NULL;
  9184. const uint8_t* data = NULL;
  9185. unsigned int nbytes = 0;
  9186. unsigned int alloc_size = 0;
  9187. unsigned int address = -1;
  9188. unsigned int len = 0;
  9189. struct rarch_state *p_rarch = &rarch_st;
  9190. unsigned int max_bytes = 0;
  9191. if (sscanf(arg, "%x %u", &address, &nbytes) != 2)
  9192. return false;
  9193. /* Ensure large enough to return all requested bytes or an error message */
  9194. alloc_size = 64 + nbytes * 3;
  9195. reply = (char*)malloc(alloc_size);
  9196. reply_at = reply + snprintf(reply, alloc_size - 1, "READ_CORE_MEMORY %x", address);
  9197. data = command_memory_get_pointer(address, &max_bytes, 0, reply_at, alloc_size - strlen(reply));
  9198. if (data)
  9199. {
  9200. if (nbytes > max_bytes)
  9201. nbytes = max_bytes;
  9202. for (i = 0; i < nbytes; i++)
  9203. snprintf(reply_at + 3 * i, 4, " %02X", data[i]);
  9204. reply_at[3 * nbytes] = '\n';
  9205. len = reply_at + 3 * nbytes + 1 - reply;
  9206. }
  9207. else
  9208. len = strlen(reply);
  9209. command_reply(p_rarch, reply, len);
  9210. free(reply);
  9211. return true;
  9212. }
  9213. static bool command_write_memory(const char *arg)
  9214. {
  9215. unsigned int address = (unsigned int)strtoul(arg, (char**)&arg, 16);
  9216. unsigned int max_bytes = 0;
  9217. struct rarch_state *p_rarch = &rarch_st;
  9218. char reply[128] = "";
  9219. char *reply_at = reply + snprintf(reply, sizeof(reply) - 1, "WRITE_CORE_MEMORY %x", address);
  9220. uint8_t *data = command_memory_get_pointer(address, &max_bytes, 1, reply_at, sizeof(reply) - strlen(reply) - 1);
  9221. if (data)
  9222. {
  9223. uint8_t* start = data;
  9224. while (*arg && max_bytes > 0)
  9225. {
  9226. --max_bytes;
  9227. *data = strtoul(arg, (char**)&arg, 16);
  9228. data++;
  9229. }
  9230. snprintf(reply_at, sizeof(reply) - strlen(reply) - 1,
  9231. " %u\n", (unsigned)(data - start));
  9232. #ifdef HAVE_CHEEVOS
  9233. if (rcheevos_hardcore_active())
  9234. {
  9235. RARCH_LOG("Achievements hardcore mode disabled by WRITE_CORE_MEMORY\n");
  9236. rcheevos_pause_hardcore();
  9237. }
  9238. #endif
  9239. }
  9240. command_reply(p_rarch, reply, strlen(reply));
  9241. return true;
  9242. }
  9243. #ifdef HAVE_NETWORK_CMD
  9244. static bool command_get_arg(const char *tok,
  9245. const char **arg, unsigned *index)
  9246. {
  9247. unsigned i;
  9248. for (i = 0; i < ARRAY_SIZE(map); i++)
  9249. {
  9250. if (string_is_equal(tok, map[i].str))
  9251. {
  9252. if (arg)
  9253. *arg = NULL;
  9254. if (index)
  9255. *index = i;
  9256. return true;
  9257. }
  9258. }
  9259. for (i = 0; i < ARRAY_SIZE(action_map); i++)
  9260. {
  9261. const char *str = strstr(tok, action_map[i].str);
  9262. if (str == tok)
  9263. {
  9264. const char *argument = str + strlen(action_map[i].str);
  9265. if (*argument != ' ' && *argument != '\0')
  9266. return false;
  9267. if (arg)
  9268. *arg = argument + 1;
  9269. if (index)
  9270. *index = i;
  9271. return true;
  9272. }
  9273. }
  9274. return false;
  9275. }
  9276. static bool command_network_init(command_t *handle, uint16_t port)
  9277. {
  9278. struct addrinfo *res = NULL;
  9279. int fd = socket_init((void**)&res, port,
  9280. NULL, SOCKET_TYPE_DATAGRAM);
  9281. RARCH_LOG("%s %hu.\n",
  9282. msg_hash_to_str(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT),
  9283. (unsigned short)port);
  9284. if (fd < 0)
  9285. goto error;
  9286. handle->net_fd = fd;
  9287. if (!socket_nonblock(handle->net_fd))
  9288. goto error;
  9289. if (!socket_bind(handle->net_fd, (void*)res))
  9290. {
  9291. RARCH_ERR("%s.\n",
  9292. msg_hash_to_str(MSG_FAILED_TO_BIND_SOCKET));
  9293. goto error;
  9294. }
  9295. freeaddrinfo_retro(res);
  9296. return true;
  9297. error:
  9298. if (res)
  9299. freeaddrinfo_retro(res);
  9300. return false;
  9301. }
  9302. static bool command_verify(const char *cmd)
  9303. {
  9304. unsigned i;
  9305. if (command_get_arg(cmd, NULL, NULL))
  9306. return true;
  9307. RARCH_ERR("Command \"%s\" is not recognized by the program.\n", cmd);
  9308. RARCH_ERR("\tValid commands:\n");
  9309. for (i = 0; i < sizeof(map) / sizeof(map[0]); i++)
  9310. RARCH_ERR("\t\t%s\n", map[i].str);
  9311. for (i = 0; i < sizeof(action_map) / sizeof(action_map[0]); i++)
  9312. RARCH_ERR("\t\t%s %s\n", action_map[i].str, action_map[i].arg_desc);
  9313. return false;
  9314. }
  9315. static bool command_network_send(const char *cmd_)
  9316. {
  9317. char *command = NULL;
  9318. char *save = NULL;
  9319. const char *cmd = NULL;
  9320. if (!network_init())
  9321. return false;
  9322. if (!(command = strdup(cmd_)))
  9323. return false;
  9324. cmd = strtok_r(command, ";", &save);
  9325. if (cmd)
  9326. {
  9327. uint16_t port = DEFAULT_NETWORK_CMD_PORT;
  9328. const char *port_ = NULL;
  9329. const char *host = strtok_r(NULL, ";", &save);
  9330. if (host)
  9331. port_ = strtok_r(NULL, ";", &save);
  9332. else
  9333. {
  9334. #ifdef _WIN32
  9335. host = "127.0.0.1";
  9336. #else
  9337. host = "localhost";
  9338. #endif
  9339. }
  9340. if (port_)
  9341. port = strtoul(port_, NULL, 0);
  9342. RARCH_LOG("%s: \"%s\" to %s:%hu\n",
  9343. msg_hash_to_str(MSG_SENDING_COMMAND),
  9344. cmd, host, (unsigned short)port);
  9345. if (command_verify(cmd) && udp_send_packet(host, port, cmd))
  9346. {
  9347. free(command);
  9348. return true;
  9349. }
  9350. }
  9351. free(command);
  9352. return false;
  9353. }
  9354. #endif
  9355. #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORK_CMD) && defined(HAVE_COMMAND)
  9356. static void command_parse_sub_msg(command_t *handle, const char *tok)
  9357. {
  9358. const char *arg = NULL;
  9359. unsigned index = 0;
  9360. if (command_get_arg(tok, &arg, &index))
  9361. {
  9362. if (arg)
  9363. {
  9364. if (!action_map[index].action(arg))
  9365. RARCH_ERR("Command \"%s\" failed.\n", arg);
  9366. }
  9367. else
  9368. handle->state[map[index].id] = true;
  9369. }
  9370. else
  9371. RARCH_WARN("%s \"%s\" %s.\n",
  9372. msg_hash_to_str(MSG_UNRECOGNIZED_COMMAND),
  9373. tok,
  9374. msg_hash_to_str(MSG_RECEIVED));
  9375. }
  9376. static void command_parse_msg(
  9377. struct rarch_state *p_rarch,
  9378. command_t *handle,
  9379. char *buf, enum cmd_source_t source)
  9380. {
  9381. char *save = NULL;
  9382. const char *tok = strtok_r(buf, "\n", &save);
  9383. p_rarch->lastcmd_source = source;
  9384. while (tok)
  9385. {
  9386. command_parse_sub_msg(handle, tok);
  9387. tok = strtok_r(NULL, "\n", &save);
  9388. }
  9389. p_rarch->lastcmd_source = CMD_NONE;
  9390. }
  9391. static void command_network_poll(
  9392. struct rarch_state *p_rarch,
  9393. command_t *handle)
  9394. {
  9395. fd_set fds;
  9396. struct timeval tmp_tv = {0};
  9397. if (handle->net_fd < 0)
  9398. return;
  9399. FD_ZERO(&fds);
  9400. FD_SET(handle->net_fd, &fds);
  9401. if (socket_select(handle->net_fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0)
  9402. return;
  9403. if (!FD_ISSET(handle->net_fd, &fds))
  9404. return;
  9405. for (;;)
  9406. {
  9407. ssize_t ret;
  9408. char buf[1024];
  9409. buf[0] = '\0';
  9410. p_rarch->lastcmd_net_fd = handle->net_fd;
  9411. p_rarch->lastcmd_net_source_len = sizeof(p_rarch->lastcmd_net_source);
  9412. ret = recvfrom(handle->net_fd, buf,
  9413. sizeof(buf) - 1, 0,
  9414. (struct sockaddr*)&p_rarch->lastcmd_net_source,
  9415. &p_rarch->lastcmd_net_source_len);
  9416. if (ret <= 0)
  9417. break;
  9418. buf[ret] = '\0';
  9419. command_parse_msg(p_rarch, handle, buf, CMD_NETWORK);
  9420. }
  9421. }
  9422. #endif
  9423. static bool command_free(command_t *handle)
  9424. {
  9425. #ifdef HAVE_NETWORK_CMD
  9426. if (handle && handle->net_fd >= 0)
  9427. socket_close(handle->net_fd);
  9428. #endif
  9429. free(handle);
  9430. return true;
  9431. }
  9432. #ifdef HAVE_STDIN_CMD
  9433. static bool command_stdin_init(command_t *handle)
  9434. {
  9435. #ifndef _WIN32
  9436. #ifdef HAVE_NETWORKING
  9437. if (!socket_nonblock(STDIN_FILENO))
  9438. return false;
  9439. #endif
  9440. #endif
  9441. handle->stdin_enable = true;
  9442. return true;
  9443. }
  9444. static void command_stdin_poll(
  9445. struct rarch_state *p_rarch,
  9446. command_t *handle)
  9447. {
  9448. ptrdiff_t msg_len;
  9449. char *last_newline = NULL;
  9450. ssize_t ret = read_stdin(
  9451. handle->stdin_buf + handle->stdin_buf_ptr,
  9452. STDIN_BUF_SIZE - handle->stdin_buf_ptr - 1);
  9453. if (ret == 0)
  9454. return;
  9455. handle->stdin_buf_ptr += ret;
  9456. handle->stdin_buf[handle->stdin_buf_ptr] = '\0';
  9457. last_newline =
  9458. strrchr(handle->stdin_buf, '\n');
  9459. if (!last_newline)
  9460. {
  9461. /* We're receiving bogus data in pipe
  9462. * (no terminating newline), flush out the buffer. */
  9463. if (handle->stdin_buf_ptr + 1 >= STDIN_BUF_SIZE)
  9464. {
  9465. handle->stdin_buf_ptr = 0;
  9466. handle->stdin_buf[0] = '\0';
  9467. }
  9468. return;
  9469. }
  9470. *last_newline++ = '\0';
  9471. msg_len = last_newline - handle->stdin_buf;
  9472. #if defined(HAVE_NETWORKING)
  9473. command_parse_msg(p_rarch,
  9474. handle, handle->stdin_buf, CMD_STDIN);
  9475. #endif
  9476. memmove(handle->stdin_buf, last_newline,
  9477. handle->stdin_buf_ptr - msg_len);
  9478. handle->stdin_buf_ptr -= msg_len;
  9479. }
  9480. #endif
  9481. static bool command_network_new(
  9482. command_t *handle,
  9483. bool stdin_enable,
  9484. bool network_enable,
  9485. uint16_t port)
  9486. {
  9487. #ifdef HAVE_NETWORK_CMD
  9488. handle->net_fd = -1;
  9489. if (network_enable && !command_network_init(handle, port))
  9490. goto error;
  9491. #endif
  9492. #ifdef HAVE_STDIN_CMD
  9493. handle->stdin_enable = stdin_enable;
  9494. if (stdin_enable && !command_stdin_init(handle))
  9495. goto error;
  9496. #endif
  9497. return true;
  9498. #if defined(HAVE_NETWORK_CMD) || defined(HAVE_STDIN_CMD)
  9499. error:
  9500. command_free(handle);
  9501. return false;
  9502. #endif
  9503. }
  9504. #endif
  9505. static bool retroarch_apply_shader(
  9506. enum rarch_shader_type type,
  9507. const char *preset_path, bool message)
  9508. {
  9509. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  9510. char msg[256];
  9511. struct rarch_state *p_rarch = &rarch_st;
  9512. settings_t *settings = p_rarch->configuration_settings;
  9513. const char *core_name = p_rarch->runloop_system.info.library_name;
  9514. const char *preset_file = NULL;
  9515. #ifdef HAVE_MENU
  9516. struct video_shader *shader = menu_shader_get();
  9517. #endif
  9518. /* Disallow loading shaders when no core is loaded */
  9519. if (string_is_empty(core_name))
  9520. return false;
  9521. if (!string_is_empty(preset_path))
  9522. preset_file = path_basename(preset_path);
  9523. p_rarch->runtime_shader_preset[0] = '\0';
  9524. /* TODO/FIXME - This loads the shader into the video driver
  9525. * But then we load the shader from disk twice more to put it in the menu
  9526. * We need to reconfigure this at some point to only load it once */
  9527. if (p_rarch->current_video->set_shader)
  9528. {
  9529. if ((p_rarch->current_video->set_shader(
  9530. p_rarch->video_driver_data, type, preset_path)))
  9531. {
  9532. configuration_set_bool(settings, settings->bools.video_shader_enable, true);
  9533. if (!string_is_empty(preset_path))
  9534. {
  9535. strlcpy(p_rarch->runtime_shader_preset, preset_path,
  9536. sizeof(p_rarch->runtime_shader_preset));
  9537. #ifdef HAVE_MENU
  9538. /* reflect in shader manager */
  9539. if (menu_shader_manager_set_preset(
  9540. shader, type, preset_path, false))
  9541. shader->modified = false;
  9542. #endif
  9543. }
  9544. if (message)
  9545. {
  9546. /* Display message */
  9547. if (preset_file)
  9548. snprintf(msg, sizeof(msg),
  9549. "%s: \"%s\"",
  9550. msg_hash_to_str(MSG_SHADER),
  9551. preset_file);
  9552. else
  9553. {
  9554. strlcpy(msg, msg_hash_to_str(MSG_SHADER), sizeof(msg));
  9555. strlcat(msg, ": ", sizeof(msg));
  9556. strlcat(msg, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE), sizeof(msg));
  9557. }
  9558. #ifdef HAVE_GFX_WIDGETS
  9559. if (p_rarch->widgets_active)
  9560. gfx_widget_set_generic_message(&p_rarch->dispwidget_st,
  9561. msg, 2000);
  9562. else
  9563. #endif
  9564. runloop_msg_queue_push(msg, 1, 120, true, NULL,
  9565. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  9566. }
  9567. RARCH_LOG("%s \"%s\".\n",
  9568. msg_hash_to_str(MSG_APPLYING_SHADER),
  9569. preset_path ? preset_path : "null");
  9570. return true;
  9571. }
  9572. }
  9573. #ifdef HAVE_MENU
  9574. /* reflect in shader manager */
  9575. menu_shader_manager_set_preset(shader, type, NULL, false);
  9576. #endif
  9577. /* Display error message */
  9578. fill_pathname_join_delim(msg,
  9579. msg_hash_to_str(MSG_FAILED_TO_APPLY_SHADER_PRESET),
  9580. preset_file ? preset_file : "null",
  9581. ' ',
  9582. sizeof(msg));
  9583. runloop_msg_queue_push(
  9584. msg, 1, 180, true, NULL,
  9585. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR);
  9586. #endif
  9587. return false;
  9588. }
  9589. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  9590. static bool command_set_shader(const char *arg)
  9591. {
  9592. enum rarch_shader_type type = video_shader_parse_type(arg);
  9593. struct rarch_state *p_rarch = &rarch_st;
  9594. settings_t *settings = p_rarch->configuration_settings;
  9595. if (!string_is_empty(arg))
  9596. {
  9597. if (!video_shader_is_supported(type))
  9598. return false;
  9599. /* rebase on shader directory */
  9600. if (!path_is_absolute(arg))
  9601. {
  9602. char abs_arg[PATH_MAX_LENGTH];
  9603. const char *ref_path = settings->paths.directory_video_shader;
  9604. fill_pathname_join(abs_arg,
  9605. ref_path, arg, sizeof(abs_arg));
  9606. arg = abs_arg;
  9607. }
  9608. }
  9609. return retroarch_apply_shader(type, arg, true);
  9610. }
  9611. #endif
  9612. /* TRANSLATION */
  9613. #ifdef HAVE_TRANSLATE
  9614. static bool task_auto_translate_callback(struct rarch_state *p_rarch)
  9615. {
  9616. bool was_paused = p_rarch->runloop_paused;
  9617. command_event(CMD_EVENT_AI_SERVICE_CALL, &was_paused);
  9618. return true;
  9619. }
  9620. /* TODO/FIXME - Doesn't currently work. Fix this. */
  9621. static bool is_ai_service_speech_running(void)
  9622. {
  9623. #ifdef HAVE_AUDIOMIXER
  9624. enum audio_mixer_state res = audio_driver_mixer_get_stream_state(10);
  9625. bool ret = (res == AUDIO_STREAM_STATE_NONE) || (res == AUDIO_STREAM_STATE_STOPPED);
  9626. if (!ret)
  9627. return true;
  9628. #endif
  9629. return false;
  9630. }
  9631. static bool ai_service_speech_stop(void)
  9632. {
  9633. #ifdef HAVE_AUDIOMIXER
  9634. audio_driver_mixer_stop_stream(10);
  9635. audio_driver_mixer_remove_stream(10);
  9636. #endif
  9637. return false;
  9638. }
  9639. static void task_auto_translate_handler(retro_task_t *task)
  9640. {
  9641. int *mode_ptr = (int*)task->user_data;
  9642. struct rarch_state *p_rarch = &rarch_st;
  9643. if (task_get_cancelled(task))
  9644. goto task_finished;
  9645. switch (*mode_ptr)
  9646. {
  9647. case 1: /* Speech Mode */
  9648. #ifdef HAVE_AUDIOMIXER
  9649. if (!is_ai_service_speech_running())
  9650. goto task_finished;
  9651. #endif
  9652. break;
  9653. case 2: /* Narrator Mode */
  9654. #ifdef HAVE_ACCESSIBILITY
  9655. if (!is_narrator_running(p_rarch))
  9656. goto task_finished;
  9657. #endif
  9658. break;
  9659. default:
  9660. break;
  9661. }
  9662. return;
  9663. task_finished:
  9664. if (p_rarch->ai_service_auto == 1)
  9665. p_rarch->ai_service_auto = 2;
  9666. task_set_finished(task, true);
  9667. if (*mode_ptr == 1 || *mode_ptr == 2)
  9668. task_auto_translate_callback(p_rarch);
  9669. if (task->user_data)
  9670. free(task->user_data);
  9671. }
  9672. static bool call_auto_translate_task(
  9673. struct rarch_state *p_rarch,
  9674. bool *was_paused)
  9675. {
  9676. settings_t *settings = p_rarch->configuration_settings;
  9677. int ai_service_mode = settings->uints.ai_service_mode;
  9678. /*Image Mode*/
  9679. if (ai_service_mode == 0)
  9680. {
  9681. if (p_rarch->ai_service_auto == 1)
  9682. p_rarch->ai_service_auto = 2;
  9683. command_event(CMD_EVENT_AI_SERVICE_CALL, was_paused);
  9684. return true;
  9685. }
  9686. else /* Speech or Narrator Mode */
  9687. {
  9688. int* mode = NULL;
  9689. retro_task_t *t = task_init();
  9690. if (!t)
  9691. return false;
  9692. mode = (int*)malloc(sizeof(int));
  9693. *mode = ai_service_mode;
  9694. t->handler = task_auto_translate_handler;
  9695. t->user_data = mode;
  9696. t->mute = true;
  9697. task_queue_push(t);
  9698. }
  9699. return true;
  9700. }
  9701. static void handle_translation_cb(
  9702. retro_task_t *task, void *task_data,
  9703. void *user_data, const char *error)
  9704. {
  9705. size_t pitch;
  9706. unsigned width, height;
  9707. unsigned image_width, image_height;
  9708. uint8_t* raw_output_data = NULL;
  9709. char* raw_image_file_data = NULL;
  9710. struct scaler_ctx* scaler = NULL;
  9711. http_transfer_data_t *data = (http_transfer_data_t*)task_data;
  9712. int new_image_size = 0;
  9713. #ifdef HAVE_AUDIOMIXER
  9714. int new_sound_size = 0;
  9715. #endif
  9716. const void* dummy_data = NULL;
  9717. void* raw_image_data = NULL;
  9718. void* raw_image_data_alpha = NULL;
  9719. void* raw_sound_data = NULL;
  9720. int retval = 0;
  9721. rjson_t* json = NULL;
  9722. int json_current_key = 0;
  9723. char* err_string = NULL;
  9724. char* text_string = NULL;
  9725. char* auto_string = NULL;
  9726. char* key_string = NULL;
  9727. struct rarch_state *p_rarch = &rarch_st;
  9728. settings_t* settings = p_rarch->configuration_settings;
  9729. bool was_paused = p_rarch->runloop_paused;
  9730. const enum retro_pixel_format
  9731. video_driver_pix_fmt = p_rarch->video_driver_pix_fmt;
  9732. #ifdef HAVE_GFX_WIDGETS
  9733. bool gfx_widgets_paused = p_rarch->gfx_widgets_paused;
  9734. /* When auto mode is on, we turn off the overlay
  9735. * once we have the result for the next call.*/
  9736. if (p_rarch->dispwidget_st.ai_service_overlay_state != 0
  9737. && p_rarch->ai_service_auto == 2)
  9738. gfx_widgets_ai_service_overlay_unload(&p_rarch->dispwidget_st);
  9739. #endif
  9740. #ifdef DEBUG
  9741. if (p_rarch->ai_service_auto != 2)
  9742. RARCH_LOG("RESULT FROM AI SERVICE...\n");
  9743. #endif
  9744. if (!data || error || !data->data)
  9745. goto finish;
  9746. json = rjson_open_buffer(data->data, data->len);
  9747. if (!json)
  9748. goto finish;
  9749. /* Parse JSON body for the image and sound data */
  9750. for (;;)
  9751. {
  9752. static const char* keys[] = { "image", "sound", "text", "error", "auto", "press" };
  9753. const char *str = NULL;
  9754. size_t str_len = 0;
  9755. enum rjson_type json_type = rjson_next(json);
  9756. if (json_type == RJSON_DONE || json_type == RJSON_ERROR)
  9757. break;
  9758. if (json_type != RJSON_STRING)
  9759. continue;
  9760. if (rjson_get_context_type(json) != RJSON_OBJECT)
  9761. continue;
  9762. str = rjson_get_string(json, &str_len);
  9763. if ((rjson_get_context_count(json) & 1) == 1)
  9764. {
  9765. int i;
  9766. json_current_key = -1;
  9767. for (i = 0; i != (sizeof(keys)/sizeof(keys[0])); i++)
  9768. {
  9769. if (string_is_equal(str, keys[i]))
  9770. {
  9771. json_current_key = i;
  9772. break;
  9773. }
  9774. }
  9775. }
  9776. else
  9777. {
  9778. switch (json_current_key)
  9779. {
  9780. case 0: /* image */
  9781. raw_image_file_data = (char*)unbase64(str,
  9782. (int)str_len, &new_image_size);
  9783. break;
  9784. #ifdef HAVE_AUDIOMIXER
  9785. case 1: /* sound */
  9786. raw_sound_data = (void*)unbase64(str,
  9787. (int)str_len, &new_sound_size);
  9788. break;
  9789. #endif
  9790. case 2: /* text */
  9791. text_string = strdup(str);
  9792. break;
  9793. case 3: /* error */
  9794. err_string = strdup(str);
  9795. break;
  9796. case 4: /* auto */
  9797. auto_string = strdup(str);
  9798. break;
  9799. case 5: /* press */
  9800. key_string = strdup(str);
  9801. break;
  9802. }
  9803. json_current_key = -1;
  9804. }
  9805. }
  9806. if (string_is_equal(err_string, "No text found."))
  9807. {
  9808. #ifdef DEBUG
  9809. RARCH_LOG("No text found...\n");
  9810. #endif
  9811. if (text_string)
  9812. {
  9813. free(text_string);
  9814. text_string = NULL;
  9815. }
  9816. text_string = (char*)malloc(15);
  9817. strlcpy(text_string, err_string, 15);
  9818. #ifdef HAVE_GFX_WIDGETS
  9819. if (gfx_widgets_paused)
  9820. {
  9821. /* In this case we have to unpause and then repause for a frame */
  9822. p_rarch->dispwidget_st.ai_service_overlay_state = 2;
  9823. command_event(CMD_EVENT_UNPAUSE, NULL);
  9824. }
  9825. #endif
  9826. }
  9827. if ( !raw_image_file_data
  9828. && !raw_sound_data
  9829. && !text_string
  9830. && (p_rarch->ai_service_auto != 2)
  9831. && !key_string)
  9832. {
  9833. error = "Invalid JSON body.";
  9834. goto finish;
  9835. }
  9836. if (raw_image_file_data)
  9837. {
  9838. /* Get the video frame dimensions reference */
  9839. video_driver_cached_frame_get(&dummy_data, &width, &height, &pitch);
  9840. /* try two different modes for text display *
  9841. * In the first mode, we use display widget overlays, but they require
  9842. * the video poke interface to be able to load image buffers.
  9843. *
  9844. * The other method is to draw to the video buffer directly, which needs
  9845. * a software core to be running. */
  9846. #ifdef HAVE_GFX_WIDGETS
  9847. if (p_rarch->video_driver_poke
  9848. && p_rarch->video_driver_poke->load_texture
  9849. && p_rarch->video_driver_poke->unload_texture)
  9850. {
  9851. bool ai_res;
  9852. enum image_type_enum image_type;
  9853. /* Write to overlay */
  9854. if ( raw_image_file_data[0] == 'B' &&
  9855. raw_image_file_data[1] == 'M')
  9856. image_type = IMAGE_TYPE_BMP;
  9857. else if (raw_image_file_data[1] == 'P' &&
  9858. raw_image_file_data[2] == 'N' &&
  9859. raw_image_file_data[3] == 'G')
  9860. image_type = IMAGE_TYPE_PNG;
  9861. else
  9862. {
  9863. RARCH_LOG("Invalid image type returned from server.\n");
  9864. goto finish;
  9865. }
  9866. ai_res = gfx_widgets_ai_service_overlay_load(
  9867. &p_rarch->dispwidget_st,
  9868. raw_image_file_data, (unsigned)new_image_size,
  9869. image_type);
  9870. if (!ai_res)
  9871. {
  9872. RARCH_LOG("Video driver not supported for AI Service.");
  9873. runloop_msg_queue_push(
  9874. /* msg_hash_to_str(MSG_VIDEO_DRIVER_NOT_SUPPORTED), */
  9875. "Video driver not supported.",
  9876. 1, 180, true,
  9877. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  9878. }
  9879. else if (gfx_widgets_paused)
  9880. {
  9881. /* In this case we have to unpause and then repause for a frame */
  9882. #ifdef HAVE_TRANSLATE
  9883. /* Unpausing state */
  9884. p_rarch->dispwidget_st.ai_service_overlay_state = 2;
  9885. #endif
  9886. command_event(CMD_EVENT_UNPAUSE, NULL);
  9887. }
  9888. }
  9889. else
  9890. #endif
  9891. /* Can't use display widget overlays, so try writing to video buffer */
  9892. {
  9893. /* Write to video buffer directly (software cores only) */
  9894. if (raw_image_file_data[0] == 'B' && raw_image_file_data[1] == 'M')
  9895. {
  9896. /* This is a BMP file coming back. */
  9897. /* Get image data (24 bit), and convert to the emulated pixel format */
  9898. image_width =
  9899. ((uint32_t) ((uint8_t)raw_image_file_data[21]) << 24) +
  9900. ((uint32_t) ((uint8_t)raw_image_file_data[20]) << 16) +
  9901. ((uint32_t) ((uint8_t)raw_image_file_data[19]) << 8) +
  9902. ((uint32_t) ((uint8_t)raw_image_file_data[18]) << 0);
  9903. image_height =
  9904. ((uint32_t) ((uint8_t)raw_image_file_data[25]) << 24) +
  9905. ((uint32_t) ((uint8_t)raw_image_file_data[24]) << 16) +
  9906. ((uint32_t) ((uint8_t)raw_image_file_data[23]) << 8) +
  9907. ((uint32_t) ((uint8_t)raw_image_file_data[22]) << 0);
  9908. raw_image_data = (void*)malloc(image_width*image_height*3*sizeof(uint8_t));
  9909. memcpy(raw_image_data,
  9910. raw_image_file_data+54*sizeof(uint8_t),
  9911. image_width*image_height*3*sizeof(uint8_t));
  9912. }
  9913. else if (raw_image_file_data[1] == 'P' && raw_image_file_data[2] == 'N' &&
  9914. raw_image_file_data[3] == 'G')
  9915. {
  9916. rpng_t *rpng = NULL;
  9917. /* PNG coming back from the url */
  9918. image_width =
  9919. ((uint32_t) ((uint8_t)raw_image_file_data[16]) << 24)+
  9920. ((uint32_t) ((uint8_t)raw_image_file_data[17]) << 16)+
  9921. ((uint32_t) ((uint8_t)raw_image_file_data[18]) << 8)+
  9922. ((uint32_t) ((uint8_t)raw_image_file_data[19]) << 0);
  9923. image_height =
  9924. ((uint32_t) ((uint8_t)raw_image_file_data[20]) << 24)+
  9925. ((uint32_t) ((uint8_t)raw_image_file_data[21]) << 16)+
  9926. ((uint32_t) ((uint8_t)raw_image_file_data[22]) << 8)+
  9927. ((uint32_t) ((uint8_t)raw_image_file_data[23]) << 0);
  9928. rpng = rpng_alloc();
  9929. if (!rpng)
  9930. {
  9931. error = "Can't allocate memory.";
  9932. goto finish;
  9933. }
  9934. rpng_set_buf_ptr(rpng, raw_image_file_data, (size_t)new_image_size);
  9935. rpng_start(rpng);
  9936. while (rpng_iterate_image(rpng));
  9937. do
  9938. {
  9939. retval = rpng_process_image(rpng, &raw_image_data_alpha,
  9940. (size_t)new_image_size, &image_width, &image_height);
  9941. } while (retval == IMAGE_PROCESS_NEXT);
  9942. /* Returned output from the png processor is an upside down RGBA
  9943. * image, so we have to change that to RGB first. This should
  9944. * probably be replaced with a scaler call.*/
  9945. {
  9946. unsigned ui;
  9947. int d,tw,th,tc;
  9948. d=0;
  9949. raw_image_data = (void*)malloc(image_width*image_height*3*sizeof(uint8_t));
  9950. for (ui = 0; ui < image_width * image_height * 4; ui++)
  9951. {
  9952. if (ui % 4 != 3)
  9953. {
  9954. tc = d%3;
  9955. th = image_height-d / (3*image_width)-1;
  9956. tw = (d%(image_width*3)) / 3;
  9957. ((uint8_t*) raw_image_data)[tw*3+th*3*image_width+tc] = ((uint8_t *)raw_image_data_alpha)[ui];
  9958. d+=1;
  9959. }
  9960. }
  9961. }
  9962. rpng_free(rpng);
  9963. }
  9964. else
  9965. {
  9966. RARCH_LOG("Output from URL not a valid file type, or is not supported.\n");
  9967. goto finish;
  9968. }
  9969. scaler = (struct scaler_ctx*)calloc(1, sizeof(struct scaler_ctx));
  9970. if (!scaler)
  9971. goto finish;
  9972. if (dummy_data == RETRO_HW_FRAME_BUFFER_VALID)
  9973. {
  9974. /*
  9975. In this case, we used the viewport to grab the image
  9976. and translate it, and we have the translated image in
  9977. the raw_image_data buffer.
  9978. */
  9979. RARCH_LOG("Hardware frame buffer core, but selected video driver isn't supported.\n");
  9980. goto finish;
  9981. }
  9982. /* The assigned pitch may not be reliable. The width of
  9983. the video frame can change during run-time, but the
  9984. pitch may not, so we just assign it as the width
  9985. times the byte depth.
  9986. */
  9987. if (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888)
  9988. {
  9989. raw_output_data = (uint8_t*)malloc(width * height * 4 * sizeof(uint8_t));
  9990. scaler->out_fmt = SCALER_FMT_ARGB8888;
  9991. pitch = width * 4;
  9992. scaler->out_stride = width * 4;
  9993. }
  9994. else
  9995. {
  9996. raw_output_data = (uint8_t*)malloc(width * height * 2 * sizeof(uint8_t));
  9997. scaler->out_fmt = SCALER_FMT_RGB565;
  9998. pitch = width * 2;
  9999. scaler->out_stride = width * 1;
  10000. }
  10001. if (!raw_output_data)
  10002. goto finish;
  10003. scaler->in_fmt = SCALER_FMT_BGR24;
  10004. scaler->in_width = image_width;
  10005. scaler->in_height = image_height;
  10006. scaler->out_width = width;
  10007. scaler->out_height = height;
  10008. scaler->scaler_type = SCALER_TYPE_POINT;
  10009. scaler_ctx_gen_filter(scaler);
  10010. scaler->in_stride = -1 * width * 3;
  10011. scaler_ctx_scale_direct(scaler, raw_output_data,
  10012. (uint8_t*)raw_image_data + (image_height - 1) * width * 3);
  10013. video_driver_frame(raw_output_data, image_width, image_height, pitch);
  10014. }
  10015. }
  10016. #ifdef HAVE_AUDIOMIXER
  10017. if (raw_sound_data)
  10018. {
  10019. audio_mixer_stream_params_t params;
  10020. params.volume = 1.0f;
  10021. params.slot_selection_type = AUDIO_MIXER_SLOT_SELECTION_MANUAL; /* user->slot_selection_type; */
  10022. params.slot_selection_idx = 10;
  10023. params.stream_type = AUDIO_STREAM_TYPE_SYSTEM; /* user->stream_type; */
  10024. params.type = AUDIO_MIXER_TYPE_WAV;
  10025. params.state = AUDIO_STREAM_STATE_PLAYING;
  10026. params.buf = raw_sound_data;
  10027. params.bufsize = new_sound_size;
  10028. params.cb = NULL;
  10029. params.basename = NULL;
  10030. audio_driver_mixer_add_stream(&params);
  10031. if (raw_sound_data)
  10032. {
  10033. free(raw_sound_data);
  10034. raw_sound_data = NULL;
  10035. }
  10036. }
  10037. #endif
  10038. if (key_string)
  10039. {
  10040. char key[8];
  10041. size_t length = strlen(key_string);
  10042. int i = 0;
  10043. int start = 0;
  10044. char t = ' ';
  10045. for (i = 1; i < (int)length; i++)
  10046. {
  10047. t = key_string[i];
  10048. if (i == length-1 || t == ' ' || t == ',')
  10049. {
  10050. if (i == length-1 && t != ' ' && t!= ',')
  10051. i++;
  10052. if (i-start > 7)
  10053. {
  10054. start = i;
  10055. continue;
  10056. }
  10057. strncpy(key, key_string+start, i-start);
  10058. key[i-start] = '\0';
  10059. #ifdef HAVE_ACCESSIBILITY
  10060. #ifdef HAVE_TRANSLATE
  10061. if (string_is_equal(key, "b"))
  10062. p_rarch->ai_gamepad_state[0] = 2;
  10063. if (string_is_equal(key, "y"))
  10064. p_rarch->ai_gamepad_state[1] = 2;
  10065. if (string_is_equal(key, "select"))
  10066. p_rarch->ai_gamepad_state[2] = 2;
  10067. if (string_is_equal(key, "start"))
  10068. p_rarch->ai_gamepad_state[3] = 2;
  10069. if (string_is_equal(key, "up"))
  10070. p_rarch->ai_gamepad_state[4] = 2;
  10071. if (string_is_equal(key, "down"))
  10072. p_rarch->ai_gamepad_state[5] = 2;
  10073. if (string_is_equal(key, "left"))
  10074. p_rarch->ai_gamepad_state[6] = 2;
  10075. if (string_is_equal(key, "right"))
  10076. p_rarch->ai_gamepad_state[7] = 2;
  10077. if (string_is_equal(key, "a"))
  10078. p_rarch->ai_gamepad_state[8] = 2;
  10079. if (string_is_equal(key, "x"))
  10080. p_rarch->ai_gamepad_state[9] = 2;
  10081. if (string_is_equal(key, "l"))
  10082. p_rarch->ai_gamepad_state[10] = 2;
  10083. if (string_is_equal(key, "r"))
  10084. p_rarch->ai_gamepad_state[11] = 2;
  10085. if (string_is_equal(key, "l2"))
  10086. p_rarch->ai_gamepad_state[12] = 2;
  10087. if (string_is_equal(key, "r2"))
  10088. p_rarch->ai_gamepad_state[13] = 2;
  10089. if (string_is_equal(key, "l3"))
  10090. p_rarch->ai_gamepad_state[14] = 2;
  10091. if (string_is_equal(key, "r3"))
  10092. p_rarch->ai_gamepad_state[15] = 2;
  10093. #endif
  10094. #endif
  10095. if (string_is_equal(key, "pause"))
  10096. command_event(CMD_EVENT_PAUSE, NULL);
  10097. if (string_is_equal(key, "unpause"))
  10098. command_event(CMD_EVENT_UNPAUSE, NULL);
  10099. start = i+1;
  10100. }
  10101. }
  10102. }
  10103. #ifdef HAVE_ACCESSIBILITY
  10104. if (text_string && is_accessibility_enabled(p_rarch))
  10105. accessibility_speak_priority(p_rarch, text_string, 10);
  10106. #endif
  10107. finish:
  10108. if (error)
  10109. RARCH_ERR("%s: %s\n", msg_hash_to_str(MSG_DOWNLOAD_FAILED), error);
  10110. if (data)
  10111. {
  10112. if (data->data)
  10113. free(data->data);
  10114. free(data);
  10115. }
  10116. if (user_data)
  10117. free(user_data);
  10118. if (json)
  10119. rjson_free(json);
  10120. if (raw_image_file_data)
  10121. free(raw_image_file_data);
  10122. if (raw_image_data_alpha)
  10123. free(raw_image_data_alpha);
  10124. if (raw_image_data)
  10125. free(raw_image_data);
  10126. if (scaler)
  10127. free(scaler);
  10128. if (err_string)
  10129. free(err_string);
  10130. if (text_string)
  10131. free(text_string);
  10132. if (raw_output_data)
  10133. free(raw_output_data);
  10134. if (string_is_equal(auto_string, "auto"))
  10135. {
  10136. if ( (p_rarch->ai_service_auto != 0)
  10137. && !settings->bools.ai_service_pause)
  10138. call_auto_translate_task(p_rarch, &was_paused);
  10139. }
  10140. if (auto_string)
  10141. free(auto_string);
  10142. if (key_string)
  10143. free(key_string);
  10144. }
  10145. static const char *ai_service_get_str(enum translation_lang id)
  10146. {
  10147. switch (id)
  10148. {
  10149. case TRANSLATION_LANG_EN:
  10150. return "en";
  10151. case TRANSLATION_LANG_ES:
  10152. return "es";
  10153. case TRANSLATION_LANG_FR:
  10154. return "fr";
  10155. case TRANSLATION_LANG_IT:
  10156. return "it";
  10157. case TRANSLATION_LANG_DE:
  10158. return "de";
  10159. case TRANSLATION_LANG_JP:
  10160. return "ja";
  10161. case TRANSLATION_LANG_NL:
  10162. return "nl";
  10163. case TRANSLATION_LANG_CS:
  10164. return "cs";
  10165. case TRANSLATION_LANG_DA:
  10166. return "da";
  10167. case TRANSLATION_LANG_SV:
  10168. return "sv";
  10169. case TRANSLATION_LANG_HR:
  10170. return "hr";
  10171. case TRANSLATION_LANG_KO:
  10172. return "ko";
  10173. case TRANSLATION_LANG_ZH_CN:
  10174. return "zh-CN";
  10175. case TRANSLATION_LANG_ZH_TW:
  10176. return "zh-TW";
  10177. case TRANSLATION_LANG_CA:
  10178. return "ca";
  10179. case TRANSLATION_LANG_BG:
  10180. return "bg";
  10181. case TRANSLATION_LANG_BN:
  10182. return "bn";
  10183. case TRANSLATION_LANG_EU:
  10184. return "eu";
  10185. case TRANSLATION_LANG_AZ:
  10186. return "az";
  10187. case TRANSLATION_LANG_AR:
  10188. return "ar";
  10189. case TRANSLATION_LANG_AST:
  10190. return "ast";
  10191. case TRANSLATION_LANG_SQ:
  10192. return "sq";
  10193. case TRANSLATION_LANG_AF:
  10194. return "af";
  10195. case TRANSLATION_LANG_EO:
  10196. return "eo";
  10197. case TRANSLATION_LANG_ET:
  10198. return "et";
  10199. case TRANSLATION_LANG_TL:
  10200. return "tl";
  10201. case TRANSLATION_LANG_FI:
  10202. return "fi";
  10203. case TRANSLATION_LANG_GL:
  10204. return "gl";
  10205. case TRANSLATION_LANG_KA:
  10206. return "ka";
  10207. case TRANSLATION_LANG_EL:
  10208. return "el";
  10209. case TRANSLATION_LANG_GU:
  10210. return "gu";
  10211. case TRANSLATION_LANG_HT:
  10212. return "ht";
  10213. case TRANSLATION_LANG_HE:
  10214. return "he";
  10215. case TRANSLATION_LANG_HI:
  10216. return "hi";
  10217. case TRANSLATION_LANG_HU:
  10218. return "hu";
  10219. case TRANSLATION_LANG_IS:
  10220. return "is";
  10221. case TRANSLATION_LANG_ID:
  10222. return "id";
  10223. case TRANSLATION_LANG_GA:
  10224. return "ga";
  10225. case TRANSLATION_LANG_KN:
  10226. return "kn";
  10227. case TRANSLATION_LANG_LA:
  10228. return "la";
  10229. case TRANSLATION_LANG_LV:
  10230. return "lv";
  10231. case TRANSLATION_LANG_LT:
  10232. return "lt";
  10233. case TRANSLATION_LANG_MK:
  10234. return "mk";
  10235. case TRANSLATION_LANG_MS:
  10236. return "ms";
  10237. case TRANSLATION_LANG_MT:
  10238. return "mt";
  10239. case TRANSLATION_LANG_NO:
  10240. return "no";
  10241. case TRANSLATION_LANG_FA:
  10242. return "fa";
  10243. case TRANSLATION_LANG_PL:
  10244. return "pl";
  10245. case TRANSLATION_LANG_PT:
  10246. return "pt";
  10247. case TRANSLATION_LANG_RO:
  10248. return "ro";
  10249. case TRANSLATION_LANG_RU:
  10250. return "ru";
  10251. case TRANSLATION_LANG_SR:
  10252. return "sr";
  10253. case TRANSLATION_LANG_SK:
  10254. return "sk";
  10255. case TRANSLATION_LANG_SL:
  10256. return "sl";
  10257. case TRANSLATION_LANG_SW:
  10258. return "sw";
  10259. case TRANSLATION_LANG_TA:
  10260. return "ta";
  10261. case TRANSLATION_LANG_TE:
  10262. return "te";
  10263. case TRANSLATION_LANG_TH:
  10264. return "th";
  10265. case TRANSLATION_LANG_TR:
  10266. return "tr";
  10267. case TRANSLATION_LANG_UK:
  10268. return "uk";
  10269. case TRANSLATION_LANG_UR:
  10270. return "ur";
  10271. case TRANSLATION_LANG_VI:
  10272. return "vi";
  10273. case TRANSLATION_LANG_CY:
  10274. return "cy";
  10275. case TRANSLATION_LANG_YI:
  10276. return "yi";
  10277. case TRANSLATION_LANG_DONT_CARE:
  10278. case TRANSLATION_LANG_LAST:
  10279. break;
  10280. }
  10281. return "";
  10282. }
  10283. /*
  10284. This function does all the stuff needed to translate the game screen,
  10285. using the URL given in the settings. Once the image from the frame
  10286. buffer is sent to the server, the callback will write the translated
  10287. image to the screen.
  10288. Supported client/services (thus far)
  10289. -VGTranslate client ( www.gitlab.com/spherebeaker/vg_translate )
  10290. -Ztranslate client/service ( www.ztranslate.net/docs/service )
  10291. To use a client, download the relevant code/release, configure
  10292. them, and run them on your local machine, or network. Set the
  10293. retroarch configuration to point to your local client (usually
  10294. listening on localhost:4404 ) and enable translation service.
  10295. If you don't want to run a client, you can also use a service,
  10296. which is basically like someone running a client for you. The
  10297. downside here is that your retroarch device will have to have
  10298. an internet connection, and you may have to sign up for it.
  10299. To make your own server, it must listen for a POST request, which
  10300. will consist of a JSON body, with the "image" field as a base64
  10301. encoded string of a 24bit-BMP/PNG that the will be translated.
  10302. The server must output the translated image in the form of a
  10303. JSON body, with the "image" field also as a base64 encoded
  10304. 24bit-BMP, or as an alpha channel png.
  10305. "paused" boolean is passed in to indicate if the current call
  10306. was made during a paused frame. Due to how the menu widgets work,
  10307. if the ai service is called in "auto" mode, then this call will
  10308. be made while the menu widgets unpause the core for a frame to update
  10309. the on-screen widgets. To tell the ai service what the pause
  10310. mode is honestly, we store the runloop_paused variable from before
  10311. the handle_translation_cb wipes the widgets, and pass that in here.
  10312. */
  10313. static bool run_translation_service(
  10314. settings_t *settings,
  10315. struct rarch_state *p_rarch,
  10316. bool paused)
  10317. {
  10318. struct video_viewport vp;
  10319. uint8_t header[54];
  10320. size_t pitch;
  10321. unsigned width, height;
  10322. const void *data = NULL;
  10323. uint8_t *bit24_image = NULL;
  10324. uint8_t *bit24_image_prev = NULL;
  10325. struct scaler_ctx *scaler = (struct scaler_ctx*)
  10326. calloc(1, sizeof(struct scaler_ctx));
  10327. bool error = false;
  10328. uint8_t *bmp_buffer = NULL;
  10329. uint64_t buffer_bytes = 0;
  10330. char *bmp64_buffer = NULL;
  10331. rjsonwriter_t* jsonwriter = NULL;
  10332. const char *json_buffer = NULL;
  10333. int bmp64_length = 0;
  10334. bool TRANSLATE_USE_BMP = false;
  10335. bool use_overlay = false;
  10336. const char *label = NULL;
  10337. char* system_label = NULL;
  10338. core_info_t *core_info = NULL;
  10339. const enum retro_pixel_format
  10340. video_driver_pix_fmt = p_rarch->video_driver_pix_fmt;
  10341. #ifdef HAVE_GFX_WIDGETS
  10342. /* For the case when ai service pause is disabled. */
  10343. if ( (p_rarch->dispwidget_st.ai_service_overlay_state != 0)
  10344. && (p_rarch->ai_service_auto == 1))
  10345. {
  10346. gfx_widgets_ai_service_overlay_unload(&p_rarch->dispwidget_st);
  10347. goto finish;
  10348. }
  10349. #endif
  10350. #ifdef HAVE_GFX_WIDGETS
  10351. if ( p_rarch->video_driver_poke
  10352. && p_rarch->video_driver_poke->load_texture
  10353. && p_rarch->video_driver_poke->unload_texture)
  10354. use_overlay = true;
  10355. #endif
  10356. /* get the core info here so we can pass long the game name */
  10357. core_info_get_current_core(&core_info);
  10358. if (core_info)
  10359. {
  10360. size_t label_len;
  10361. const char *system_id = core_info->system_id
  10362. ? core_info->system_id : "core";
  10363. size_t system_id_len = strlen(system_id);
  10364. const struct playlist_entry *entry = NULL;
  10365. playlist_t *current_playlist = playlist_get_cached();
  10366. if (current_playlist)
  10367. {
  10368. playlist_get_index_by_path(
  10369. current_playlist, path_get(RARCH_PATH_CONTENT), &entry);
  10370. if (entry && !string_is_empty(entry->label))
  10371. label = entry->label;
  10372. }
  10373. if (!label)
  10374. label = path_basename(path_get(RARCH_PATH_BASENAME));
  10375. label_len = strlen(label);
  10376. system_label = (char*)malloc(label_len + system_id_len + 3);
  10377. memcpy(system_label, system_id, system_id_len);
  10378. memcpy(system_label + system_id_len, "__", 2);
  10379. memcpy(system_label + 2 + system_id_len, label, label_len);
  10380. system_label[system_id_len + 2 + label_len] = '\0';
  10381. }
  10382. if (!scaler)
  10383. goto finish;
  10384. video_driver_cached_frame_get(&data, &width, &height, &pitch);
  10385. if (!data)
  10386. goto finish;
  10387. if (data == RETRO_HW_FRAME_BUFFER_VALID)
  10388. {
  10389. /*
  10390. The direct frame capture didn't work, so try getting it
  10391. from the viewport instead. This isn't as good as the
  10392. raw frame buffer, since the viewport may us bilinear
  10393. filtering, or other shaders that will completely trash
  10394. the OCR, but it's better than nothing.
  10395. */
  10396. vp.x = 0;
  10397. vp.y = 0;
  10398. vp.width = 0;
  10399. vp.height = 0;
  10400. vp.full_width = 0;
  10401. vp.full_height = 0;
  10402. video_driver_get_viewport_info(&vp);
  10403. if (!vp.width || !vp.height)
  10404. goto finish;
  10405. bit24_image_prev = (uint8_t*)malloc(vp.width * vp.height * 3);
  10406. bit24_image = (uint8_t*)malloc(width * height * 3);
  10407. if (!bit24_image_prev || !bit24_image)
  10408. goto finish;
  10409. if (!video_driver_read_viewport(bit24_image_prev, false))
  10410. {
  10411. RARCH_LOG("Could not read viewport for translation service...\n");
  10412. goto finish;
  10413. }
  10414. /* TODO: Rescale down to regular resolution */
  10415. scaler->in_fmt = SCALER_FMT_BGR24;
  10416. scaler->out_fmt = SCALER_FMT_BGR24;
  10417. scaler->scaler_type = SCALER_TYPE_POINT;
  10418. scaler->in_width = vp.width;
  10419. scaler->in_height = vp.height;
  10420. scaler->out_width = width;
  10421. scaler->out_height = height;
  10422. scaler_ctx_gen_filter(scaler);
  10423. scaler->in_stride = vp.width*3;
  10424. scaler->out_stride = width*3;
  10425. scaler_ctx_scale_direct(scaler, bit24_image, bit24_image_prev);
  10426. }
  10427. else
  10428. {
  10429. /* This is a software core, so just change the pixel format to 24-bit. */
  10430. bit24_image = (uint8_t*)malloc(width * height * 3);
  10431. if (!bit24_image)
  10432. goto finish;
  10433. if (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888)
  10434. scaler->in_fmt = SCALER_FMT_ARGB8888;
  10435. else
  10436. scaler->in_fmt = SCALER_FMT_RGB565;
  10437. video_frame_convert_to_bgr24(
  10438. scaler,
  10439. (uint8_t *)bit24_image,
  10440. (const uint8_t*)data + ((int)height - 1)*pitch,
  10441. width, height,
  10442. (int)-pitch);
  10443. }
  10444. scaler_ctx_gen_reset(scaler);
  10445. if (!bit24_image)
  10446. {
  10447. error = true;
  10448. goto finish;
  10449. }
  10450. if (TRANSLATE_USE_BMP)
  10451. {
  10452. /*
  10453. At this point, we should have a screenshot in the buffer,
  10454. so allocate an array to contain the BMP image along with
  10455. the BMP header as bytes, and then covert that to a
  10456. b64 encoded array for transport in JSON.
  10457. */
  10458. form_bmp_header(header, width, height, false);
  10459. bmp_buffer = (uint8_t*)malloc(width * height * 3 + 54);
  10460. if (!bmp_buffer)
  10461. goto finish;
  10462. memcpy(bmp_buffer, header, 54 * sizeof(uint8_t));
  10463. memcpy(bmp_buffer + 54,
  10464. bit24_image,
  10465. width * height * 3 * sizeof(uint8_t));
  10466. buffer_bytes = sizeof(uint8_t) * (width * height * 3 + 54);
  10467. }
  10468. else
  10469. {
  10470. pitch = width * 3;
  10471. bmp_buffer = rpng_save_image_bgr24_string(
  10472. bit24_image + width * (height-1) * 3,
  10473. width, height, (signed)-pitch, &buffer_bytes);
  10474. }
  10475. bmp64_buffer = base64((void *)bmp_buffer,
  10476. sizeof(uint8_t) * buffer_bytes,
  10477. &bmp64_length);
  10478. if (!bmp64_buffer)
  10479. goto finish;
  10480. jsonwriter = rjsonwriter_open_memory();
  10481. if (!jsonwriter)
  10482. goto finish;
  10483. rjsonwriter_add_start_object(jsonwriter);
  10484. rjsonwriter_add_space(jsonwriter);
  10485. rjsonwriter_add_string(jsonwriter, "image");
  10486. rjsonwriter_add_colon(jsonwriter);
  10487. rjsonwriter_add_space(jsonwriter);
  10488. rjsonwriter_add_string_len(jsonwriter, bmp64_buffer, bmp64_length);
  10489. /* Form request... */
  10490. if (system_label)
  10491. {
  10492. rjsonwriter_add_comma(jsonwriter);
  10493. rjsonwriter_add_space(jsonwriter);
  10494. rjsonwriter_add_string(jsonwriter, "label");
  10495. rjsonwriter_add_colon(jsonwriter);
  10496. rjsonwriter_add_space(jsonwriter);
  10497. rjsonwriter_add_string(jsonwriter, system_label);
  10498. }
  10499. rjsonwriter_add_comma(jsonwriter);
  10500. rjsonwriter_add_space(jsonwriter);
  10501. rjsonwriter_add_string(jsonwriter, "state");
  10502. rjsonwriter_add_colon(jsonwriter);
  10503. rjsonwriter_add_space(jsonwriter);
  10504. rjsonwriter_add_start_object(jsonwriter);
  10505. rjsonwriter_add_space(jsonwriter);
  10506. rjsonwriter_add_string(jsonwriter, "paused");
  10507. rjsonwriter_add_colon(jsonwriter);
  10508. rjsonwriter_add_space(jsonwriter);
  10509. rjsonwriter_add_unsigned(jsonwriter, (paused ? 1 : 0));
  10510. {
  10511. static const char* state_labels[] = { "b", "y", "select", "start", "up", "down", "left", "right", "a", "x", "l", "r", "l2", "r2", "l3", "r3" };
  10512. int i;
  10513. for (i = 0; i != (sizeof(state_labels)/sizeof(state_labels[0])); i++)
  10514. {
  10515. rjsonwriter_add_comma(jsonwriter);
  10516. rjsonwriter_add_space(jsonwriter);
  10517. rjsonwriter_add_string(jsonwriter, state_labels[i]);
  10518. rjsonwriter_add_colon(jsonwriter);
  10519. rjsonwriter_add_space(jsonwriter);
  10520. rjsonwriter_add_unsigned(jsonwriter,
  10521. #ifdef HAVE_ACCESSIBILITY
  10522. (p_rarch->ai_gamepad_state[i] ? 1 : 0)
  10523. #else
  10524. 0
  10525. #endif
  10526. );
  10527. }
  10528. }
  10529. rjsonwriter_add_space(jsonwriter);
  10530. rjsonwriter_add_end_object(jsonwriter);
  10531. rjsonwriter_add_space(jsonwriter);
  10532. rjsonwriter_add_end_object(jsonwriter);
  10533. json_buffer = rjsonwriter_get_memory_buffer(jsonwriter, NULL);
  10534. if (!json_buffer)
  10535. goto finish; /* ran out of memory */
  10536. #ifdef DEBUG
  10537. if (p_rarch->ai_service_auto != 2)
  10538. RARCH_LOG("Request size: %d\n", bmp64_length);
  10539. #endif
  10540. {
  10541. char separator = '?';
  10542. char new_ai_service_url[PATH_MAX_LENGTH];
  10543. unsigned ai_service_source_lang = settings->uints.ai_service_source_lang;
  10544. unsigned ai_service_target_lang = settings->uints.ai_service_target_lang;
  10545. const char *ai_service_url = settings->arrays.ai_service_url;
  10546. strlcpy(new_ai_service_url, ai_service_url, sizeof(new_ai_service_url));
  10547. /* if query already exists in url, then use &'s instead */
  10548. if (strrchr(new_ai_service_url, '?'))
  10549. separator = '&';
  10550. /* source lang */
  10551. if (ai_service_source_lang != TRANSLATION_LANG_DONT_CARE)
  10552. {
  10553. const char *lang_source = ai_service_get_str(
  10554. (enum translation_lang)ai_service_source_lang);
  10555. if (!string_is_empty(lang_source))
  10556. {
  10557. char temp_string[PATH_MAX_LENGTH];
  10558. snprintf(temp_string,
  10559. sizeof(temp_string),
  10560. "%csource_lang=%s", separator, lang_source);
  10561. separator = '&';
  10562. strlcat(new_ai_service_url,
  10563. temp_string, sizeof(new_ai_service_url));
  10564. }
  10565. }
  10566. /* target lang */
  10567. if (ai_service_target_lang != TRANSLATION_LANG_DONT_CARE)
  10568. {
  10569. const char *lang_target = ai_service_get_str(
  10570. (enum translation_lang)ai_service_target_lang);
  10571. if (!string_is_empty(lang_target))
  10572. {
  10573. char temp_string[PATH_MAX_LENGTH];
  10574. snprintf(temp_string,
  10575. sizeof(temp_string),
  10576. "%ctarget_lang=%s", separator, lang_target);
  10577. separator = '&';
  10578. strlcat(new_ai_service_url, temp_string,
  10579. sizeof(new_ai_service_url));
  10580. }
  10581. }
  10582. /* mode */
  10583. {
  10584. char temp_string[PATH_MAX_LENGTH];
  10585. const char *mode_chr = NULL;
  10586. unsigned ai_service_mode = settings->uints.ai_service_mode;
  10587. /*"image" is included for backwards compatability with
  10588. * vgtranslate < 1.04 */
  10589. temp_string[0] = '\0';
  10590. switch (ai_service_mode)
  10591. {
  10592. case 0:
  10593. if (use_overlay)
  10594. mode_chr = "image,png,png-a";
  10595. else
  10596. mode_chr = "image,png";
  10597. break;
  10598. case 1:
  10599. mode_chr = "sound,wav";
  10600. break;
  10601. case 2:
  10602. mode_chr = "text";
  10603. break;
  10604. case 3:
  10605. if (use_overlay)
  10606. mode_chr = "image,png,png-a,sound,wav";
  10607. else
  10608. mode_chr = "image,png,sound,wav";
  10609. break;
  10610. default:
  10611. break;
  10612. }
  10613. snprintf(temp_string,
  10614. sizeof(temp_string),
  10615. "%coutput=%s", separator, mode_chr);
  10616. separator = '&';
  10617. strlcat(new_ai_service_url, temp_string,
  10618. sizeof(new_ai_service_url));
  10619. }
  10620. #ifdef DEBUG
  10621. if (p_rarch->ai_service_auto != 2)
  10622. RARCH_LOG("SENDING... %s\n", new_ai_service_url);
  10623. #endif
  10624. task_push_http_post_transfer(new_ai_service_url,
  10625. json_buffer, true, NULL, handle_translation_cb, NULL);
  10626. }
  10627. error = false;
  10628. finish:
  10629. if (bit24_image_prev)
  10630. free(bit24_image_prev);
  10631. if (bit24_image)
  10632. free(bit24_image);
  10633. if (scaler)
  10634. free(scaler);
  10635. if (bmp_buffer)
  10636. free(bmp_buffer);
  10637. if (bmp64_buffer)
  10638. free(bmp64_buffer);
  10639. if (system_label)
  10640. free(system_label);
  10641. if (jsonwriter)
  10642. rjsonwriter_free(jsonwriter);
  10643. return !error;
  10644. }
  10645. #endif
  10646. /**
  10647. * command_event_disk_control_append_image:
  10648. * @path : Path to disk image.
  10649. *
  10650. * Appends disk image to disk image list.
  10651. **/
  10652. static bool command_event_disk_control_append_image(
  10653. struct rarch_state *p_rarch,
  10654. const char *path)
  10655. {
  10656. rarch_system_info_t *sys_info = &p_rarch->runloop_system;
  10657. if (!sys_info)
  10658. return false;
  10659. if (!disk_control_append_image(&sys_info->disk_control, path))
  10660. return false;
  10661. #ifdef HAVE_THREADS
  10662. retroarch_autosave_deinit(p_rarch);
  10663. #endif
  10664. /* TODO: Need to figure out what to do with subsystems case. */
  10665. if (path_is_empty(RARCH_PATH_SUBSYSTEM))
  10666. {
  10667. /* Update paths for our new image.
  10668. * If we actually use append_image, we assume that we
  10669. * started out in a single disk case, and that this way
  10670. * of doing it makes the most sense. */
  10671. path_set(RARCH_PATH_NAMES, path);
  10672. path_fill_names(p_rarch);
  10673. }
  10674. command_event(CMD_EVENT_AUTOSAVE_INIT, NULL);
  10675. return true;
  10676. }
  10677. /**
  10678. * event_set_volume:
  10679. * @gain : amount of gain to be applied to current volume level.
  10680. *
  10681. * Adjusts the current audio volume level.
  10682. *
  10683. **/
  10684. static void command_event_set_volume(
  10685. settings_t *settings,
  10686. struct rarch_state *p_rarch, float gain)
  10687. {
  10688. char msg[128];
  10689. float new_volume = settings->floats.audio_volume + gain;
  10690. new_volume = MAX(new_volume, -80.0f);
  10691. new_volume = MIN(new_volume, 12.0f);
  10692. configuration_set_float(settings, settings->floats.audio_volume, new_volume);
  10693. snprintf(msg, sizeof(msg), "%s: %.1f dB",
  10694. msg_hash_to_str(MSG_AUDIO_VOLUME),
  10695. new_volume);
  10696. #if defined(HAVE_GFX_WIDGETS)
  10697. if (p_rarch->widgets_active)
  10698. gfx_widget_volume_update_and_show(new_volume,
  10699. p_rarch->audio_driver_mute_enable);
  10700. else
  10701. #endif
  10702. runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  10703. RARCH_LOG("[Audio]: %s\n", msg);
  10704. audio_set_float(AUDIO_ACTION_VOLUME_GAIN, new_volume);
  10705. }
  10706. /**
  10707. * event_set_mixer_volume:
  10708. * @gain : amount of gain to be applied to current volume level.
  10709. *
  10710. * Adjusts the current audio volume level.
  10711. *
  10712. **/
  10713. static void command_event_set_mixer_volume(
  10714. settings_t *settings,
  10715. struct rarch_state *p_rarch,
  10716. float gain)
  10717. {
  10718. char msg[128];
  10719. float new_volume = settings->floats.audio_mixer_volume + gain;
  10720. new_volume = MAX(new_volume, -80.0f);
  10721. new_volume = MIN(new_volume, 12.0f);
  10722. configuration_set_float(settings, settings->floats.audio_mixer_volume, new_volume);
  10723. snprintf(msg, sizeof(msg), "%s: %.1f dB",
  10724. msg_hash_to_str(MSG_AUDIO_VOLUME),
  10725. new_volume);
  10726. runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  10727. RARCH_LOG("[Audio]: %s\n", msg);
  10728. audio_set_float(AUDIO_ACTION_VOLUME_GAIN, new_volume);
  10729. }
  10730. /**
  10731. * command_event_init_controllers:
  10732. *
  10733. * Initialize libretro controllers.
  10734. **/
  10735. static void command_event_init_controllers(struct rarch_state *p_rarch)
  10736. {
  10737. unsigned i;
  10738. rarch_system_info_t *info = &p_rarch->runloop_system;
  10739. unsigned num_active_users = p_rarch->input_driver_max_users;
  10740. unsigned ports_size = info->ports.size;
  10741. if (!info)
  10742. return;
  10743. for (i = 0; i < MAX_USERS; i++)
  10744. {
  10745. retro_ctx_controller_info_t pad;
  10746. const struct retro_controller_description *desc = NULL;
  10747. unsigned device = (i < num_active_users)
  10748. ? input_config_get_device(i)
  10749. : RETRO_DEVICE_NONE;
  10750. if (i >= ports_size)
  10751. break;
  10752. desc = libretro_find_controller_description(
  10753. &info->ports.data[i], device);
  10754. if (desc && !desc->desc)
  10755. {
  10756. /* If we're trying to connect a completely unknown device,
  10757. * revert back to JOYPAD. */
  10758. if (device != RETRO_DEVICE_JOYPAD && device != RETRO_DEVICE_NONE)
  10759. {
  10760. /* Do not fix device,
  10761. * because any use of dummy core will reset this,
  10762. * which is not a good idea. */
  10763. RARCH_WARN("[Input]: Input device ID %u is unknown to this "
  10764. "libretro implementation. Using RETRO_DEVICE_JOYPAD.\n",
  10765. device);
  10766. device = RETRO_DEVICE_JOYPAD;
  10767. }
  10768. }
  10769. pad.device = device;
  10770. pad.port = i;
  10771. switch (device)
  10772. {
  10773. case RETRO_DEVICE_JOYPAD:
  10774. /* Ideally these checks shouldn't be required but if we always
  10775. * call core_set_controller_port_device input won't work on
  10776. * cores that don't set port information properly */
  10777. if (ports_size != 0)
  10778. core_set_controller_port_device(&pad);
  10779. break;
  10780. case RETRO_DEVICE_NONE:
  10781. default:
  10782. /* Some cores do not properly range check port argument.
  10783. * This is broken behavior of course, but avoid breaking
  10784. * cores needlessly. */
  10785. core_set_controller_port_device(&pad);
  10786. break;
  10787. }
  10788. }
  10789. }
  10790. #ifdef HAVE_CONFIGFILE
  10791. static void command_event_disable_overrides(struct rarch_state *p_rarch)
  10792. {
  10793. /* reload the original config */
  10794. config_unload_override();
  10795. p_rarch->runloop_overrides_active = false;
  10796. }
  10797. #endif
  10798. static void command_event_deinit_core(
  10799. struct rarch_state *p_rarch,
  10800. bool reinit)
  10801. {
  10802. core_unload_game(p_rarch);
  10803. video_driver_set_cached_frame_ptr(NULL);
  10804. if (p_rarch->current_core.inited)
  10805. {
  10806. RARCH_LOG("[Core]: Unloading core..\n");
  10807. p_rarch->current_core.retro_deinit();
  10808. }
  10809. RARCH_LOG("[Core]: Unloading core symbols..\n");
  10810. uninit_libretro_symbols(p_rarch, &p_rarch->current_core);
  10811. p_rarch->current_core.symbols_inited = false;
  10812. if (reinit)
  10813. driver_uninit(p_rarch, DRIVERS_CMD_ALL);
  10814. #ifdef HAVE_CONFIGFILE
  10815. if (p_rarch->runloop_overrides_active)
  10816. command_event_disable_overrides(p_rarch);
  10817. #endif
  10818. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  10819. p_rarch->runtime_shader_preset[0] = '\0';
  10820. #endif
  10821. #ifdef HAVE_CONFIGFILE
  10822. if ( p_rarch->runloop_remaps_core_active
  10823. || p_rarch->runloop_remaps_content_dir_active
  10824. || p_rarch->runloop_remaps_game_active
  10825. )
  10826. input_remapping_set_defaults(true);
  10827. #endif
  10828. }
  10829. #ifdef HAVE_CHEATS
  10830. static void command_event_init_cheats(
  10831. settings_t *settings,
  10832. struct rarch_state *p_rarch)
  10833. {
  10834. bool allow_cheats = true;
  10835. bool apply_cheats_after_load = settings->bools.apply_cheats_after_load;
  10836. const char *path_cheat_db = settings->paths.path_cheat_database;
  10837. #ifdef HAVE_NETWORKING
  10838. allow_cheats &= !netplay_driver_ctl(
  10839. RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL);
  10840. #endif
  10841. #ifdef HAVE_BSV_MOVIE
  10842. allow_cheats &= !(p_rarch->bsv_movie_state_handle != NULL);
  10843. #endif
  10844. if (!allow_cheats)
  10845. return;
  10846. cheat_manager_alloc_if_empty();
  10847. cheat_manager_load_game_specific_cheats(path_cheat_db);
  10848. if (apply_cheats_after_load)
  10849. cheat_manager_apply_cheats();
  10850. }
  10851. #endif
  10852. static void command_event_load_auto_state(
  10853. settings_t *settings,
  10854. global_t *global,
  10855. struct rarch_state *p_rarch)
  10856. {
  10857. char savestate_name_auto[PATH_MAX_LENGTH];
  10858. bool ret = false;
  10859. bool savestate_auto_load = settings->bools.savestate_auto_load;
  10860. if (!global || !savestate_auto_load)
  10861. return;
  10862. #ifdef HAVE_CHEEVOS
  10863. if (rcheevos_hardcore_active())
  10864. return;
  10865. #endif
  10866. #ifdef HAVE_NETWORKING
  10867. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
  10868. return;
  10869. #endif
  10870. savestate_name_auto[0] = '\0';
  10871. fill_pathname_noext(savestate_name_auto, global->name.savestate,
  10872. ".auto", sizeof(savestate_name_auto));
  10873. if (!path_is_valid(savestate_name_auto))
  10874. return;
  10875. ret = content_load_state(savestate_name_auto, false, true);
  10876. RARCH_LOG("%s: %s\n%s \"%s\" %s.\n",
  10877. msg_hash_to_str(MSG_FOUND_AUTO_SAVESTATE_IN),
  10878. savestate_name_auto,
  10879. msg_hash_to_str(MSG_AUTOLOADING_SAVESTATE_FROM),
  10880. savestate_name_auto, ret ? "succeeded" : "failed"
  10881. );
  10882. }
  10883. static void command_event_set_savestate_auto_index(
  10884. settings_t *settings,
  10885. const global_t *global,
  10886. struct rarch_state *p_rarch)
  10887. {
  10888. size_t i;
  10889. char state_dir[PATH_MAX_LENGTH];
  10890. char state_base[PATH_MAX_LENGTH];
  10891. struct string_list *dir_list = NULL;
  10892. unsigned max_idx = 0;
  10893. bool savestate_auto_index = settings->bools.savestate_auto_index;
  10894. bool show_hidden_files = settings->bools.show_hidden_files;
  10895. if (!global || !savestate_auto_index)
  10896. return;
  10897. state_dir[0] = state_base[0] = '\0';
  10898. /* Find the file in the same directory as global->savestate_name
  10899. * with the largest numeral suffix.
  10900. *
  10901. * E.g. /foo/path/content.state, will try to find
  10902. * /foo/path/content.state%d, where %d is the largest number available.
  10903. */
  10904. fill_pathname_basedir(state_dir, global->name.savestate,
  10905. sizeof(state_dir));
  10906. dir_list = dir_list_new_special(state_dir, DIR_LIST_PLAIN, NULL,
  10907. show_hidden_files);
  10908. if (!dir_list)
  10909. return;
  10910. fill_pathname_base(state_base, global->name.savestate,
  10911. sizeof(state_base));
  10912. for (i = 0; i < dir_list->size; i++)
  10913. {
  10914. unsigned idx;
  10915. char elem_base[128] = {0};
  10916. const char *end = NULL;
  10917. const char *dir_elem = dir_list->elems[i].data;
  10918. fill_pathname_base(elem_base, dir_elem, sizeof(elem_base));
  10919. if (strstr(elem_base, state_base) != elem_base)
  10920. continue;
  10921. end = dir_elem + strlen(dir_elem);
  10922. while ((end > dir_elem) && ISDIGIT((int)end[-1]))
  10923. end--;
  10924. idx = (unsigned)strtoul(end, NULL, 0);
  10925. if (idx > max_idx)
  10926. max_idx = idx;
  10927. }
  10928. dir_list_free(dir_list);
  10929. configuration_set_int(settings, settings->ints.state_slot, max_idx);
  10930. RARCH_LOG("%s: #%d\n",
  10931. msg_hash_to_str(MSG_FOUND_LAST_STATE_SLOT),
  10932. max_idx);
  10933. }
  10934. static void command_event_set_savestate_garbage_collect(
  10935. settings_t *settings,
  10936. const global_t *global,
  10937. struct rarch_state *p_rarch)
  10938. {
  10939. size_t i, cnt = 0;
  10940. char state_dir[PATH_MAX_LENGTH];
  10941. char state_base[PATH_MAX_LENGTH];
  10942. struct string_list *dir_list = NULL;
  10943. unsigned min_idx = UINT_MAX;
  10944. const char *oldest_save = NULL;
  10945. unsigned max_to_keep = settings->uints.savestate_max_keep;
  10946. bool show_hidden_files = settings->bools.show_hidden_files;
  10947. if (!global || (max_to_keep == 0))
  10948. return;
  10949. state_dir[0] = '\0';
  10950. state_base[0] = '\0';
  10951. /* Similar to command_event_set_savestate_auto_index(),
  10952. * this will find the lowest numbered save-state */
  10953. fill_pathname_basedir(state_dir, global->name.savestate,
  10954. sizeof(state_dir));
  10955. dir_list = dir_list_new_special(state_dir, DIR_LIST_PLAIN, NULL,
  10956. show_hidden_files);
  10957. if (!dir_list)
  10958. return;
  10959. fill_pathname_base(state_base, global->name.savestate,
  10960. sizeof(state_base));
  10961. for (i = 0; i < dir_list->size; i++)
  10962. {
  10963. unsigned idx;
  10964. char elem_base[128];
  10965. const char *end = NULL;
  10966. const char *dir_elem = dir_list->elems[i].data;
  10967. const char *ext = NULL;
  10968. elem_base[0] = '\0';
  10969. if (string_is_empty(dir_elem))
  10970. continue;
  10971. fill_pathname_base(elem_base, dir_elem, sizeof(elem_base));
  10972. /* Only consider files with a '.state' extension
  10973. * > i.e. Ignore '.state.auto', '.state.bak', etc. */
  10974. ext = path_get_extension(elem_base);
  10975. if (string_is_empty(ext) ||
  10976. !string_starts_with_size(ext, "state", STRLEN_CONST("state")))
  10977. continue;
  10978. /* Check whether this file is associated with
  10979. * the current content */
  10980. if (!string_starts_with(elem_base, state_base))
  10981. continue;
  10982. /* This looks like a valid save */
  10983. cnt++;
  10984. /* > Get index */
  10985. end = dir_elem + strlen(dir_elem);
  10986. while ((end > dir_elem) && ISDIGIT((int)end[-1]))
  10987. end--;
  10988. idx = string_to_unsigned(end);
  10989. /* > Check if this is the lowest index so far */
  10990. if (idx < min_idx)
  10991. {
  10992. min_idx = idx;
  10993. oldest_save = dir_elem;
  10994. }
  10995. }
  10996. /* Only delete one save state per save action
  10997. * > Conservative behaviour, designed to minimise
  10998. * the risk of deleting multiple incorrect files
  10999. * in case of accident */
  11000. if (!string_is_empty(oldest_save) && (cnt > max_to_keep))
  11001. filestream_delete(oldest_save);
  11002. dir_list_free(dir_list);
  11003. }
  11004. static bool event_init_content(
  11005. settings_t *settings,
  11006. struct rarch_state *p_rarch)
  11007. {
  11008. bool contentless = false;
  11009. bool is_inited = false;
  11010. #ifdef HAVE_CHEEVOS
  11011. bool cheevos_enable =
  11012. settings->bools.cheevos_enable;
  11013. bool cheevos_hardcore_mode_enable =
  11014. settings->bools.cheevos_hardcore_mode_enable;
  11015. #endif
  11016. global_t *global = &p_rarch->g_extern;
  11017. const enum rarch_core_type current_core_type = p_rarch->current_core_type;
  11018. content_get_status(&contentless, &is_inited);
  11019. /* TODO/FIXME - just because we have a contentless core does not
  11020. * necessarily mean there should be no SRAM, try to find a solution here */
  11021. p_rarch->rarch_use_sram = (current_core_type == CORE_TYPE_PLAIN)
  11022. && !contentless;
  11023. /* No content to be loaded for dummy core,
  11024. * just successfully exit. */
  11025. if (current_core_type == CORE_TYPE_DUMMY)
  11026. return true;
  11027. content_set_subsystem_info();
  11028. content_get_status(&contentless, &is_inited);
  11029. if (!contentless)
  11030. path_fill_names(p_rarch);
  11031. if (!content_init())
  11032. {
  11033. p_rarch->runloop_core_running = false;
  11034. return false;
  11035. }
  11036. command_event_set_savestate_auto_index(settings, global, p_rarch);
  11037. if (event_load_save_files(p_rarch->rarch_is_sram_load_disabled))
  11038. RARCH_LOG("[SRAM]: %s.\n",
  11039. msg_hash_to_str(MSG_SKIPPING_SRAM_LOAD));
  11040. /*
  11041. Since the operations are asynchronous we can't
  11042. guarantee users will not use auto_load_state to cheat on
  11043. achievements so we forbid auto_load_state from happening
  11044. if cheevos_enable and cheevos_hardcode_mode_enable
  11045. are true.
  11046. */
  11047. #ifdef HAVE_CHEEVOS
  11048. if (!cheevos_enable || !cheevos_hardcore_mode_enable)
  11049. #endif
  11050. command_event_load_auto_state(settings,
  11051. global, p_rarch);
  11052. #ifdef HAVE_BSV_MOVIE
  11053. bsv_movie_deinit(p_rarch);
  11054. if (bsv_movie_init(p_rarch))
  11055. {
  11056. /* Set granularity upon success */
  11057. configuration_set_uint(settings,
  11058. settings->uints.rewind_granularity, 1);
  11059. }
  11060. #endif
  11061. command_event(CMD_EVENT_NETPLAY_INIT, NULL);
  11062. return true;
  11063. }
  11064. static void update_runtime_log(
  11065. struct rarch_state *p_rarch,
  11066. const char *dir_runtime_log,
  11067. const char *dir_playlist,
  11068. bool log_per_core)
  11069. {
  11070. /* Initialise runtime log file */
  11071. runtime_log_t *runtime_log = runtime_log_init(
  11072. p_rarch->runtime_content_path,
  11073. p_rarch->runtime_core_path,
  11074. dir_runtime_log,
  11075. dir_playlist,
  11076. log_per_core);
  11077. if (!runtime_log)
  11078. return;
  11079. /* Add additional runtime */
  11080. runtime_log_add_runtime_usec(runtime_log,
  11081. p_rarch->libretro_core_runtime_usec);
  11082. /* Update 'last played' entry */
  11083. runtime_log_set_last_played_now(runtime_log);
  11084. /* Save runtime log file */
  11085. runtime_log_save(runtime_log);
  11086. /* Clean up */
  11087. free(runtime_log);
  11088. }
  11089. static void command_event_runtime_log_deinit(struct rarch_state *p_rarch)
  11090. {
  11091. char log[PATH_MAX_LENGTH] = {0};
  11092. unsigned hours = 0;
  11093. unsigned minutes = 0;
  11094. unsigned seconds = 0;
  11095. int n = 0;
  11096. runtime_log_convert_usec2hms(
  11097. p_rarch->libretro_core_runtime_usec,
  11098. &hours, &minutes, &seconds);
  11099. n = snprintf(log, sizeof(log),
  11100. "[Core]: Content ran for a total of: %02u hours, %02u minutes, %02u seconds.",
  11101. hours, minutes, seconds);
  11102. if ((n < 0) || (n >= PATH_MAX_LENGTH))
  11103. n = 0; /* Just silence any potential gcc warnings... */
  11104. (void)n;
  11105. RARCH_LOG("%s\n",log);
  11106. /* Only write to file if content has run for a non-zero length of time */
  11107. if (p_rarch->libretro_core_runtime_usec > 0)
  11108. {
  11109. settings_t *settings = p_rarch->configuration_settings;
  11110. bool content_runtime_log = settings->bools.content_runtime_log;
  11111. bool content_runtime_log_aggregate = settings->bools.content_runtime_log_aggregate;
  11112. const char *dir_runtime_log = settings->paths.directory_runtime_log;
  11113. const char *dir_playlist = settings->paths.directory_playlist;
  11114. /* Per core logging */
  11115. if (content_runtime_log)
  11116. update_runtime_log(p_rarch, dir_runtime_log, dir_playlist, true);
  11117. /* Aggregate logging */
  11118. if (content_runtime_log_aggregate)
  11119. update_runtime_log(p_rarch, dir_runtime_log, dir_playlist, false);
  11120. }
  11121. /* Reset runtime + content/core paths, to prevent any
  11122. * possibility of duplicate logging */
  11123. p_rarch->libretro_core_runtime_usec = 0;
  11124. memset(p_rarch->runtime_content_path, 0, sizeof(p_rarch->runtime_content_path));
  11125. memset(p_rarch->runtime_core_path, 0, sizeof(p_rarch->runtime_core_path));
  11126. }
  11127. static void command_event_runtime_log_init(struct rarch_state *p_rarch)
  11128. {
  11129. const char *content_path = path_get(RARCH_PATH_CONTENT);
  11130. const char *core_path = path_get(RARCH_PATH_CORE);
  11131. p_rarch->libretro_core_runtime_last = cpu_features_get_time_usec();
  11132. p_rarch->libretro_core_runtime_usec = 0;
  11133. /* Have to cache content and core path here, otherwise
  11134. * logging fails if new content is loaded without
  11135. * closing existing content
  11136. * i.e. RARCH_PATH_CONTENT and RARCH_PATH_CORE get
  11137. * updated when the new content is loaded, which
  11138. * happens *before* command_event_runtime_log_deinit
  11139. * -> using RARCH_PATH_CONTENT and RARCH_PATH_CORE
  11140. * directly in command_event_runtime_log_deinit
  11141. * can therefore lead to the runtime of the currently
  11142. * loaded content getting written to the *new*
  11143. * content's log file... */
  11144. memset(p_rarch->runtime_content_path,
  11145. 0, sizeof(p_rarch->runtime_content_path));
  11146. memset(p_rarch->runtime_core_path,
  11147. 0, sizeof(p_rarch->runtime_core_path));
  11148. if (!string_is_empty(content_path))
  11149. strlcpy(p_rarch->runtime_content_path,
  11150. content_path,
  11151. sizeof(p_rarch->runtime_content_path));
  11152. if (!string_is_empty(core_path))
  11153. strlcpy(p_rarch->runtime_core_path,
  11154. core_path,
  11155. sizeof(p_rarch->runtime_core_path));
  11156. }
  11157. static void retroarch_set_frame_limit(
  11158. struct rarch_state *p_rarch,
  11159. float fastforward_ratio_orig)
  11160. {
  11161. struct retro_system_av_info *av_info = &p_rarch->video_driver_av_info;
  11162. float fastforward_ratio = (fastforward_ratio_orig == 0.0f)
  11163. ? 1.0f : fastforward_ratio_orig;
  11164. p_rarch->frame_limit_last_time = cpu_features_get_time_usec();
  11165. p_rarch->frame_limit_minimum_time = (retro_time_t)roundf(1000000.0f
  11166. / (av_info->timing.fps * fastforward_ratio));
  11167. }
  11168. static bool command_event_init_core(
  11169. settings_t *settings,
  11170. struct rarch_state *p_rarch,
  11171. enum rarch_core_type type)
  11172. {
  11173. #ifdef HAVE_CONFIGFILE
  11174. bool auto_overrides_enable = settings->bools.auto_overrides_enable;
  11175. bool auto_remaps_enable = settings->bools.auto_remaps_enable;
  11176. const char *dir_input_remapping = settings->paths.directory_input_remapping;
  11177. #endif
  11178. bool show_set_initial_disk_msg = settings->bools.notification_show_set_initial_disk;
  11179. unsigned poll_type_behavior = settings->uints.input_poll_type_behavior;
  11180. float fastforward_ratio = settings->floats.fastforward_ratio;
  11181. rarch_system_info_t *sys_info = &p_rarch->runloop_system;
  11182. if (!init_libretro_symbols(p_rarch,
  11183. type, &p_rarch->current_core))
  11184. return false;
  11185. if (!p_rarch->current_core.retro_run)
  11186. p_rarch->current_core.retro_run = retro_run_null;
  11187. p_rarch->current_core.symbols_inited = true;
  11188. p_rarch->current_core.retro_get_system_info(&sys_info->info);
  11189. if (!sys_info->info.library_name)
  11190. sys_info->info.library_name = msg_hash_to_str(MSG_UNKNOWN);
  11191. if (!sys_info->info.library_version)
  11192. sys_info->info.library_version = "v0";
  11193. fill_pathname_join_concat_noext(
  11194. p_rarch->video_driver_title_buf,
  11195. msg_hash_to_str(MSG_PROGRAM),
  11196. " ",
  11197. sys_info->info.library_name,
  11198. sizeof(p_rarch->video_driver_title_buf));
  11199. strlcat(p_rarch->video_driver_title_buf, " ",
  11200. sizeof(p_rarch->video_driver_title_buf));
  11201. strlcat(p_rarch->video_driver_title_buf,
  11202. sys_info->info.library_version,
  11203. sizeof(p_rarch->video_driver_title_buf));
  11204. strlcpy(sys_info->valid_extensions,
  11205. sys_info->info.valid_extensions ?
  11206. sys_info->info.valid_extensions : DEFAULT_EXT,
  11207. sizeof(sys_info->valid_extensions));
  11208. #ifdef HAVE_CONFIGFILE
  11209. if (auto_overrides_enable)
  11210. p_rarch->runloop_overrides_active =
  11211. config_load_override(&p_rarch->runloop_system);
  11212. #endif
  11213. #ifdef HAVE_CHEEVOS
  11214. /* assume the core supports achievements unless it tells us otherwise */
  11215. rcheevos_set_support_cheevos(true);
  11216. #endif
  11217. /* Load auto-shaders on the next occasion */
  11218. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  11219. p_rarch->shader_presets_need_reload = true;
  11220. p_rarch->shader_delay_timer.timer_begin = false; /* not initialized */
  11221. p_rarch->shader_delay_timer.timer_end = false; /* not expired */
  11222. #endif
  11223. /* reset video format to libretro's default */
  11224. p_rarch->video_driver_pix_fmt = RETRO_PIXEL_FORMAT_0RGB1555;
  11225. p_rarch->current_core.retro_set_environment(rarch_environment_cb);
  11226. #ifdef HAVE_CONFIGFILE
  11227. if (auto_remaps_enable)
  11228. config_load_remap(dir_input_remapping, &p_rarch->runloop_system);
  11229. #endif
  11230. /* Per-core saves: reset redirection paths */
  11231. path_set_redirect(p_rarch);
  11232. video_driver_set_cached_frame_ptr(NULL);
  11233. p_rarch->current_core.retro_init();
  11234. p_rarch->current_core.inited = true;
  11235. /* Attempt to set initial disk index */
  11236. disk_control_set_initial_index(
  11237. &sys_info->disk_control,
  11238. path_get(RARCH_PATH_CONTENT),
  11239. p_rarch->current_savefile_dir);
  11240. if (!event_init_content(settings, p_rarch))
  11241. return false;
  11242. /* Verify that initial disk index was set correctly */
  11243. disk_control_verify_initial_index(&sys_info->disk_control,
  11244. show_set_initial_disk_msg);
  11245. if (!core_load(p_rarch, poll_type_behavior))
  11246. return false;
  11247. retroarch_set_frame_limit(p_rarch, fastforward_ratio);
  11248. command_event_runtime_log_init(p_rarch);
  11249. return true;
  11250. }
  11251. static bool command_event_save_auto_state(
  11252. settings_t *settings,
  11253. global_t *global,
  11254. struct rarch_state *p_rarch)
  11255. {
  11256. bool ret = false;
  11257. char savestate_name_auto[PATH_MAX_LENGTH];
  11258. bool savestate_auto_save = settings->bools.savestate_auto_save;
  11259. const enum rarch_core_type
  11260. current_core_type = p_rarch->current_core_type;
  11261. if (!global || !savestate_auto_save)
  11262. return false;
  11263. if (current_core_type == CORE_TYPE_DUMMY)
  11264. return false;
  11265. if (string_is_empty(path_basename(path_get(RARCH_PATH_BASENAME))))
  11266. return false;
  11267. #ifdef HAVE_CHEEVOS
  11268. if (rcheevos_hardcore_active())
  11269. return false;
  11270. #endif
  11271. savestate_name_auto[0] = '\0';
  11272. fill_pathname_noext(savestate_name_auto, global->name.savestate,
  11273. ".auto", sizeof(savestate_name_auto));
  11274. ret = content_save_state((const char*)savestate_name_auto, true, true);
  11275. RARCH_LOG("%s \"%s\" %s.\n",
  11276. msg_hash_to_str(MSG_AUTO_SAVE_STATE_TO),
  11277. savestate_name_auto, ret ?
  11278. "succeeded" : "failed");
  11279. return true;
  11280. }
  11281. #ifdef HAVE_CONFIGFILE
  11282. static bool command_event_save_config(
  11283. const char *config_path,
  11284. char *s, size_t len)
  11285. {
  11286. char log[PATH_MAX_LENGTH];
  11287. bool path_exists = !string_is_empty(config_path);
  11288. const char *str = path_exists ? config_path :
  11289. path_get(RARCH_PATH_CONFIG);
  11290. if (path_exists && config_save_file(config_path))
  11291. {
  11292. snprintf(s, len, "%s \"%s\".",
  11293. msg_hash_to_str(MSG_SAVED_NEW_CONFIG_TO),
  11294. config_path);
  11295. strcpy_literal(log, "[Config]: ");
  11296. strlcat(log, s, sizeof(log));
  11297. RARCH_LOG("%s\n", log);
  11298. return true;
  11299. }
  11300. if (!string_is_empty(str))
  11301. {
  11302. snprintf(s, len, "%s \"%s\".",
  11303. msg_hash_to_str(MSG_FAILED_SAVING_CONFIG_TO),
  11304. str);
  11305. strcpy_literal(log, "[Config]: ");
  11306. strlcat(log, s, sizeof(log));
  11307. RARCH_ERR("%s\n", log);
  11308. }
  11309. return false;
  11310. }
  11311. /**
  11312. * command_event_save_core_config:
  11313. *
  11314. * Saves a new (core) configuration to a file. Filename is based
  11315. * on heuristics to avoid typing.
  11316. *
  11317. * Returns: true (1) on success, otherwise false (0).
  11318. **/
  11319. static bool command_event_save_core_config(
  11320. struct rarch_state *p_rarch,
  11321. const char *dir_menu_config)
  11322. {
  11323. char msg[128];
  11324. char config_name[PATH_MAX_LENGTH];
  11325. char config_path[PATH_MAX_LENGTH];
  11326. char config_dir[PATH_MAX_LENGTH];
  11327. bool found_path = false;
  11328. bool overrides_active = false;
  11329. const char *core_path = NULL;
  11330. msg[0] = '\0';
  11331. config_dir[0] = '\0';
  11332. if (!string_is_empty(dir_menu_config))
  11333. strlcpy(config_dir, dir_menu_config, sizeof(config_dir));
  11334. else if (!path_is_empty(RARCH_PATH_CONFIG)) /* Fallback */
  11335. fill_pathname_basedir(config_dir, path_get(RARCH_PATH_CONFIG),
  11336. sizeof(config_dir));
  11337. if (string_is_empty(config_dir))
  11338. {
  11339. runloop_msg_queue_push(msg_hash_to_str(MSG_CONFIG_DIRECTORY_NOT_SET), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  11340. RARCH_ERR("[Config]: %s\n", msg_hash_to_str(MSG_CONFIG_DIRECTORY_NOT_SET));
  11341. return false;
  11342. }
  11343. core_path = path_get(RARCH_PATH_CORE);
  11344. config_name[0] = '\0';
  11345. config_path[0] = '\0';
  11346. /* Infer file name based on libretro core. */
  11347. if (path_is_valid(core_path))
  11348. {
  11349. unsigned i;
  11350. RARCH_LOG("%s\n", msg_hash_to_str(MSG_USING_CORE_NAME_FOR_NEW_CONFIG));
  11351. /* In case of collision, find an alternative name. */
  11352. for (i = 0; i < 16; i++)
  11353. {
  11354. char tmp[64] = {0};
  11355. fill_pathname_base_noext(
  11356. config_name,
  11357. core_path,
  11358. sizeof(config_name));
  11359. fill_pathname_join(config_path, config_dir, config_name,
  11360. sizeof(config_path));
  11361. if (i)
  11362. snprintf(tmp, sizeof(tmp), "-%u", i);
  11363. strlcat(tmp, ".cfg", sizeof(tmp));
  11364. strlcat(config_path, tmp, sizeof(config_path));
  11365. if (!path_is_valid(config_path))
  11366. {
  11367. found_path = true;
  11368. break;
  11369. }
  11370. }
  11371. }
  11372. if (!found_path)
  11373. {
  11374. /* Fallback to system time... */
  11375. RARCH_WARN("[Config]: %s\n",
  11376. msg_hash_to_str(MSG_CANNOT_INFER_NEW_CONFIG_PATH));
  11377. fill_dated_filename(config_name, ".cfg", sizeof(config_name));
  11378. fill_pathname_join(config_path, config_dir, config_name,
  11379. sizeof(config_path));
  11380. }
  11381. if (p_rarch->runloop_overrides_active)
  11382. {
  11383. /* Overrides block config file saving,
  11384. * make it appear as overrides weren't enabled
  11385. * for a manual save. */
  11386. p_rarch->runloop_overrides_active = false;
  11387. overrides_active = true;
  11388. }
  11389. #ifdef HAVE_CONFIGFILE
  11390. command_event_save_config(config_path, msg, sizeof(msg));
  11391. #endif
  11392. if (!string_is_empty(msg))
  11393. runloop_msg_queue_push(msg, 1, 180, true, NULL,
  11394. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  11395. p_rarch->runloop_overrides_active = overrides_active;
  11396. return true;
  11397. }
  11398. /**
  11399. * event_save_current_config:
  11400. *
  11401. * Saves current configuration file to disk, and (optionally)
  11402. * autosave state.
  11403. **/
  11404. static void command_event_save_current_config(
  11405. struct rarch_state *p_rarch,
  11406. enum override_type type)
  11407. {
  11408. char msg[128];
  11409. msg[0] = '\0';
  11410. switch (type)
  11411. {
  11412. case OVERRIDE_NONE:
  11413. if (path_is_empty(RARCH_PATH_CONFIG))
  11414. strcpy_literal(msg, "[Config]: Config directory not set, cannot save configuration.");
  11415. else
  11416. command_event_save_config(path_get(RARCH_PATH_CONFIG), msg, sizeof(msg));
  11417. break;
  11418. case OVERRIDE_GAME:
  11419. case OVERRIDE_CORE:
  11420. case OVERRIDE_CONTENT_DIR:
  11421. if (config_save_overrides(type, &p_rarch->runloop_system))
  11422. {
  11423. strlcpy(msg, msg_hash_to_str(MSG_OVERRIDES_SAVED_SUCCESSFULLY), sizeof(msg));
  11424. RARCH_LOG("[Config - Overrides]: %s\n", msg);
  11425. /* set overrides to active so the original config can be
  11426. restored after closing content */
  11427. p_rarch->runloop_overrides_active = true;
  11428. }
  11429. else
  11430. {
  11431. strlcpy(msg, msg_hash_to_str(MSG_OVERRIDES_ERROR_SAVING), sizeof(msg));
  11432. RARCH_ERR("[Config - Overrides]: %s\n", msg);
  11433. }
  11434. break;
  11435. }
  11436. if (!string_is_empty(msg))
  11437. runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  11438. }
  11439. #endif
  11440. static void command_event_undo_save_state(char *s, size_t len)
  11441. {
  11442. if (content_undo_save_buf_is_empty())
  11443. {
  11444. strlcpy(s,
  11445. msg_hash_to_str(MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET), len);
  11446. return;
  11447. }
  11448. if (!content_undo_save_state())
  11449. {
  11450. strlcpy(s,
  11451. msg_hash_to_str(MSG_FAILED_TO_UNDO_SAVE_STATE), len);
  11452. return;
  11453. }
  11454. strlcpy(s,
  11455. msg_hash_to_str(MSG_UNDOING_SAVE_STATE), len);
  11456. }
  11457. static void command_event_undo_load_state(char *s, size_t len)
  11458. {
  11459. if (content_undo_load_buf_is_empty())
  11460. {
  11461. strlcpy(s,
  11462. msg_hash_to_str(MSG_NO_STATE_HAS_BEEN_LOADED_YET),
  11463. len);
  11464. return;
  11465. }
  11466. if (!content_undo_load_state())
  11467. {
  11468. snprintf(s, len, "%s \"%s\".",
  11469. msg_hash_to_str(MSG_FAILED_TO_UNDO_LOAD_STATE),
  11470. "RAM");
  11471. return;
  11472. }
  11473. #ifdef HAVE_NETWORKING
  11474. netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, NULL);
  11475. #endif
  11476. strlcpy(s,
  11477. msg_hash_to_str(MSG_UNDID_LOAD_STATE), len);
  11478. }
  11479. static bool command_event_main_state(
  11480. struct rarch_state *p_rarch,
  11481. unsigned cmd)
  11482. {
  11483. retro_ctx_size_info_t info;
  11484. char msg[128];
  11485. char state_path[16384];
  11486. const global_t *global = &p_rarch->g_extern;
  11487. settings_t *settings = p_rarch->configuration_settings;
  11488. bool ret = false;
  11489. bool push_msg = true;
  11490. state_path[0] = msg[0] = '\0';
  11491. if (global)
  11492. {
  11493. int state_slot = settings->ints.state_slot;
  11494. const char *name_savestate = global->name.savestate;
  11495. if (state_slot > 0)
  11496. snprintf(state_path, sizeof(state_path), "%s%d",
  11497. name_savestate, state_slot);
  11498. else if (state_slot < 0)
  11499. fill_pathname_join_delim(state_path,
  11500. name_savestate, "auto", '.', sizeof(state_path));
  11501. else
  11502. strlcpy(state_path, name_savestate, sizeof(state_path));
  11503. }
  11504. core_serialize_size(&info);
  11505. if (info.size)
  11506. {
  11507. switch (cmd)
  11508. {
  11509. case CMD_EVENT_SAVE_STATE:
  11510. {
  11511. bool savestate_auto_index =
  11512. settings->bools.savestate_auto_index;
  11513. unsigned savestate_max_keep =
  11514. settings->uints.savestate_max_keep;
  11515. bool frame_time_counter_reset_after_save_state =
  11516. settings->bools.frame_time_counter_reset_after_save_state;
  11517. content_save_state(state_path, true, false);
  11518. /* Clean up excess savestates if necessary */
  11519. if (savestate_auto_index && (savestate_max_keep > 0))
  11520. command_event_set_savestate_garbage_collect(settings, global, p_rarch);
  11521. if (frame_time_counter_reset_after_save_state)
  11522. p_rarch->video_driver_frame_time_count = 0;
  11523. ret = true;
  11524. push_msg = false;
  11525. }
  11526. break;
  11527. case CMD_EVENT_LOAD_STATE:
  11528. if (content_load_state(state_path, false, false))
  11529. {
  11530. #ifdef HAVE_CHEEVOS
  11531. if (rcheevos_hardcore_active())
  11532. {
  11533. rcheevos_pause_hardcore();
  11534. runloop_msg_queue_push(msg_hash_to_str(MSG_CHEEVOS_HARDCORE_MODE_DISABLED), 0, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  11535. }
  11536. #endif
  11537. ret = true;
  11538. #ifdef HAVE_NETWORKING
  11539. netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, NULL);
  11540. #endif
  11541. {
  11542. bool frame_time_counter_reset_after_load_state =
  11543. settings->bools.frame_time_counter_reset_after_load_state;
  11544. if (frame_time_counter_reset_after_load_state)
  11545. p_rarch->video_driver_frame_time_count = 0;
  11546. }
  11547. }
  11548. push_msg = false;
  11549. break;
  11550. case CMD_EVENT_UNDO_LOAD_STATE:
  11551. command_event_undo_load_state(msg, sizeof(msg));
  11552. ret = true;
  11553. break;
  11554. case CMD_EVENT_UNDO_SAVE_STATE:
  11555. command_event_undo_save_state(msg, sizeof(msg));
  11556. ret = true;
  11557. break;
  11558. }
  11559. }
  11560. else
  11561. strlcpy(msg, msg_hash_to_str(
  11562. MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES), sizeof(msg));
  11563. if (push_msg)
  11564. runloop_msg_queue_push(msg, 2, 180, true, NULL,
  11565. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  11566. if (!string_is_empty(msg))
  11567. RARCH_LOG("%s\n", msg);
  11568. return ret;
  11569. }
  11570. static bool command_event_resize_windowed_scale(struct rarch_state *p_rarch)
  11571. {
  11572. unsigned idx = 0;
  11573. settings_t *settings = p_rarch->configuration_settings;
  11574. unsigned window_scale = p_rarch->runloop_pending_windowed_scale;
  11575. bool video_fullscreen = settings->bools.video_fullscreen;
  11576. if (window_scale == 0)
  11577. return false;
  11578. configuration_set_float(settings, settings->floats.video_scale, (float)window_scale);
  11579. if (!video_fullscreen)
  11580. command_event(CMD_EVENT_REINIT, NULL);
  11581. rarch_ctl(RARCH_CTL_SET_WINDOWED_SCALE, &idx);
  11582. return true;
  11583. }
  11584. static bool input_driver_grab_mouse(struct rarch_state *p_rarch)
  11585. {
  11586. if (!p_rarch->current_input || !p_rarch->current_input->grab_mouse)
  11587. return false;
  11588. p_rarch->current_input->grab_mouse(p_rarch->current_input_data, true);
  11589. p_rarch->input_driver_grab_mouse_state = true;
  11590. return true;
  11591. }
  11592. static bool input_driver_ungrab_mouse(struct rarch_state *p_rarch)
  11593. {
  11594. if (!p_rarch->current_input || !p_rarch->current_input->grab_mouse)
  11595. return false;
  11596. p_rarch->current_input->grab_mouse(p_rarch->current_input_data, false);
  11597. p_rarch->input_driver_grab_mouse_state = false;
  11598. return true;
  11599. }
  11600. static void command_event_reinit(struct rarch_state *p_rarch,
  11601. const int flags)
  11602. {
  11603. settings_t *settings = p_rarch->configuration_settings;
  11604. #ifdef HAVE_MENU
  11605. bool video_fullscreen = settings->bools.video_fullscreen;
  11606. bool adaptive_vsync = settings->bools.video_adaptive_vsync;
  11607. unsigned swap_interval = settings->uints.video_swap_interval;
  11608. #endif
  11609. enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_REAPPLY;
  11610. video_driver_reinit(flags);
  11611. /* Poll input to avoid possibly stale data to corrupt things. */
  11612. if ( p_rarch->joypad &&
  11613. p_rarch->joypad->poll)
  11614. p_rarch->joypad->poll();
  11615. #ifdef HAVE_MFI
  11616. if ( p_rarch->sec_joypad &&
  11617. p_rarch->sec_joypad->poll)
  11618. p_rarch->sec_joypad->poll();
  11619. #endif
  11620. if ( p_rarch->current_input &&
  11621. p_rarch->current_input->poll)
  11622. p_rarch->current_input->poll(p_rarch->current_input_data);
  11623. command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd);
  11624. #ifdef HAVE_MENU
  11625. p_rarch->dispgfx.framebuf_dirty = true;
  11626. if (video_fullscreen)
  11627. video_driver_hide_mouse();
  11628. if (p_rarch->menu_driver_alive && p_rarch->current_video->set_nonblock_state)
  11629. p_rarch->current_video->set_nonblock_state(
  11630. p_rarch->video_driver_data, false,
  11631. video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
  11632. adaptive_vsync,
  11633. swap_interval);
  11634. #endif
  11635. }
  11636. static void retroarch_pause_checks(struct rarch_state *p_rarch)
  11637. {
  11638. #ifdef HAVE_DISCORD
  11639. discord_userdata_t userdata;
  11640. #endif
  11641. bool is_paused = p_rarch->runloop_paused;
  11642. bool is_idle = p_rarch->runloop_idle;
  11643. #if defined(HAVE_GFX_WIDGETS)
  11644. bool widgets_active = p_rarch->widgets_active;
  11645. if (widgets_active)
  11646. p_rarch->gfx_widgets_paused = is_paused;
  11647. #endif
  11648. if (is_paused)
  11649. {
  11650. RARCH_LOG("[Core]: %s\n", msg_hash_to_str(MSG_PAUSED));
  11651. #if defined(HAVE_GFX_WIDGETS)
  11652. if (!widgets_active)
  11653. #endif
  11654. runloop_msg_queue_push(msg_hash_to_str(MSG_PAUSED), 1,
  11655. 1, true,
  11656. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  11657. if (!is_idle)
  11658. video_driver_cached_frame();
  11659. #ifdef HAVE_DISCORD
  11660. userdata.status = DISCORD_PRESENCE_GAME_PAUSED;
  11661. command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
  11662. #endif
  11663. }
  11664. else
  11665. {
  11666. RARCH_LOG("[Core]: %s\n", msg_hash_to_str(MSG_UNPAUSED));
  11667. }
  11668. #if defined(HAVE_TRANSLATE) && defined(HAVE_GFX_WIDGETS)
  11669. if (p_rarch->dispwidget_st.ai_service_overlay_state == 1)
  11670. gfx_widgets_ai_service_overlay_unload(&p_rarch->dispwidget_st);
  11671. #endif
  11672. }
  11673. static void retroarch_frame_time_free(struct rarch_state *p_rarch)
  11674. {
  11675. memset(&p_rarch->runloop_frame_time, 0,
  11676. sizeof(struct retro_frame_time_callback));
  11677. p_rarch->runloop_frame_time_last = 0;
  11678. p_rarch->runloop_max_frames = 0;
  11679. }
  11680. static void retroarch_audio_buffer_status_free(struct rarch_state *p_rarch)
  11681. {
  11682. memset(&p_rarch->runloop_audio_buffer_status, 0,
  11683. sizeof(struct retro_audio_buffer_status_callback));
  11684. p_rarch->runloop_audio_latency = 0;
  11685. }
  11686. static void retroarch_game_focus_free(struct rarch_state *p_rarch)
  11687. {
  11688. /* Ensure that game focus mode is disabled */
  11689. if (p_rarch->game_focus_state.enabled)
  11690. {
  11691. enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_OFF;
  11692. command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd);
  11693. }
  11694. p_rarch->game_focus_state.enabled = false;
  11695. p_rarch->game_focus_state.core_requested = false;
  11696. }
  11697. static void retroarch_system_info_free(struct rarch_state *p_rarch)
  11698. {
  11699. rarch_system_info_t *sys_info = &p_rarch->runloop_system;
  11700. if (sys_info->subsystem.data)
  11701. free(sys_info->subsystem.data);
  11702. sys_info->subsystem.data = NULL;
  11703. sys_info->subsystem.size = 0;
  11704. if (sys_info->ports.data)
  11705. free(sys_info->ports.data);
  11706. sys_info->ports.data = NULL;
  11707. sys_info->ports.size = 0;
  11708. if (sys_info->mmaps.descriptors)
  11709. free((void *)sys_info->mmaps.descriptors);
  11710. sys_info->mmaps.descriptors = NULL;
  11711. sys_info->mmaps.num_descriptors = 0;
  11712. p_rarch->runloop_key_event = NULL;
  11713. p_rarch->runloop_frontend_key_event = NULL;
  11714. p_rarch->audio_callback.callback = NULL;
  11715. p_rarch->audio_callback.set_state = NULL;
  11716. sys_info->info.library_name = NULL;
  11717. sys_info->info.library_version = NULL;
  11718. sys_info->info.valid_extensions = NULL;
  11719. sys_info->info.need_fullpath = false;
  11720. sys_info->info.block_extract = false;
  11721. memset(&p_rarch->runloop_system, 0, sizeof(rarch_system_info_t));
  11722. }
  11723. static bool libretro_get_system_info(
  11724. struct rarch_state *p_rarch,
  11725. const char *path,
  11726. struct retro_system_info *info,
  11727. bool *load_no_content);
  11728. #ifdef HAVE_RUNAHEAD
  11729. static void runahead_clear_variables(struct rarch_state *p_rarch)
  11730. {
  11731. p_rarch->runahead_save_state_size = 0;
  11732. p_rarch->runahead_save_state_size_known = false;
  11733. p_rarch->runahead_video_driver_is_active = true;
  11734. p_rarch->runahead_available = true;
  11735. p_rarch->runahead_secondary_core_available = true;
  11736. p_rarch->runahead_force_input_dirty = true;
  11737. p_rarch->runahead_last_frame_count = 0;
  11738. }
  11739. #endif
  11740. /**
  11741. * command_event:
  11742. * @cmd : Event command index.
  11743. *
  11744. * Performs program event command with index @cmd.
  11745. *
  11746. * Returns: true (1) on success, otherwise false (0).
  11747. **/
  11748. bool command_event(enum event_command cmd, void *data)
  11749. {
  11750. bool boolean = false;
  11751. struct rarch_state *p_rarch = &rarch_st;
  11752. settings_t *settings = p_rarch->configuration_settings;
  11753. switch (cmd)
  11754. {
  11755. case CMD_EVENT_RELOAD_CONFIG:
  11756. config_load(&p_rarch->g_extern);
  11757. break;
  11758. case CMD_EVENT_SAVE_FILES:
  11759. event_save_files(p_rarch->rarch_use_sram);
  11760. break;
  11761. case CMD_EVENT_OVERLAY_DEINIT:
  11762. #ifdef HAVE_OVERLAY
  11763. retroarch_overlay_deinit(p_rarch);
  11764. #endif
  11765. #if defined(HAVE_TRANSLATE) && defined(HAVE_GFX_WIDGETS)
  11766. /* Because the overlay is a display widget,
  11767. * it's going to be written
  11768. * over the menu, so we unset it here. */
  11769. if (p_rarch->dispwidget_st.ai_service_overlay_state != 0)
  11770. gfx_widgets_ai_service_overlay_unload(&p_rarch->dispwidget_st);
  11771. #endif
  11772. break;
  11773. case CMD_EVENT_OVERLAY_INIT:
  11774. #ifdef HAVE_OVERLAY
  11775. retroarch_overlay_init(p_rarch);
  11776. #endif
  11777. break;
  11778. case CMD_EVENT_CHEAT_INDEX_PLUS:
  11779. #ifdef HAVE_CHEATS
  11780. cheat_manager_index_next();
  11781. #endif
  11782. break;
  11783. case CMD_EVENT_CHEAT_INDEX_MINUS:
  11784. #ifdef HAVE_CHEATS
  11785. cheat_manager_index_prev();
  11786. #endif
  11787. break;
  11788. case CMD_EVENT_CHEAT_TOGGLE:
  11789. #ifdef HAVE_CHEATS
  11790. cheat_manager_toggle();
  11791. #endif
  11792. break;
  11793. case CMD_EVENT_SHADER_NEXT:
  11794. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  11795. dir_check_shader(p_rarch, true, false);
  11796. #endif
  11797. break;
  11798. case CMD_EVENT_SHADER_PREV:
  11799. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  11800. dir_check_shader(p_rarch, false, true);
  11801. #endif
  11802. break;
  11803. case CMD_EVENT_BSV_RECORDING_TOGGLE:
  11804. #ifdef HAVE_BSV_MOVIE
  11805. if (!recording_is_enabled())
  11806. command_event(CMD_EVENT_RECORD_INIT, NULL);
  11807. else
  11808. command_event(CMD_EVENT_RECORD_DEINIT, NULL);
  11809. bsv_movie_check(p_rarch);
  11810. #endif
  11811. break;
  11812. case CMD_EVENT_AI_SERVICE_TOGGLE:
  11813. {
  11814. #ifdef HAVE_TRANSLATE
  11815. bool ai_service_pause = settings->bools.ai_service_pause;
  11816. if (!settings->bools.ai_service_enable)
  11817. break;
  11818. if (ai_service_pause)
  11819. {
  11820. /* pause on call, unpause on second press. */
  11821. if (!p_rarch->runloop_paused)
  11822. {
  11823. command_event(CMD_EVENT_PAUSE, NULL);
  11824. command_event(CMD_EVENT_AI_SERVICE_CALL, NULL);
  11825. }
  11826. else
  11827. {
  11828. #ifdef HAVE_ACCESSIBILITY
  11829. if (is_accessibility_enabled(p_rarch))
  11830. accessibility_speak_priority(p_rarch,
  11831. (char*) msg_hash_to_str(MSG_UNPAUSED), 10);
  11832. #endif
  11833. command_event(CMD_EVENT_UNPAUSE, NULL);
  11834. }
  11835. }
  11836. else
  11837. {
  11838. /* Don't pause - useful for Text-To-Speech since
  11839. * the audio can't currently play while paused.
  11840. * Also useful for cases when users don't want the
  11841. * core's sound to stop while translating.
  11842. *
  11843. * Also, this mode is required for "auto" translation
  11844. * packages, since you don't want to pause for that.
  11845. */
  11846. if (p_rarch->ai_service_auto == 2)
  11847. {
  11848. /* Auto mode was turned on, but we pressed the
  11849. * toggle button, so turn it off now. */
  11850. p_rarch->ai_service_auto = 0;
  11851. #ifdef HAVE_MENU_WIDGETS
  11852. gfx_widgets_ai_service_overlay_unload(&p_rarch->dispwidget_st);
  11853. #endif
  11854. }
  11855. else
  11856. command_event(CMD_EVENT_AI_SERVICE_CALL, NULL);
  11857. }
  11858. #endif
  11859. break;
  11860. }
  11861. case CMD_EVENT_STREAMING_TOGGLE:
  11862. if (streaming_is_enabled())
  11863. command_event(CMD_EVENT_RECORD_DEINIT, NULL);
  11864. else
  11865. {
  11866. streaming_set_state(true);
  11867. command_event(CMD_EVENT_RECORD_INIT, NULL);
  11868. }
  11869. break;
  11870. case CMD_EVENT_RUNAHEAD_TOGGLE:
  11871. {
  11872. char msg[256];
  11873. msg[0] = '\0';
  11874. settings->bools.run_ahead_enabled =
  11875. !(settings->bools.run_ahead_enabled);
  11876. if (!settings->bools.run_ahead_enabled)
  11877. {
  11878. runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_DISABLED),
  11879. 1, 100, false,
  11880. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  11881. }
  11882. else if (!settings->bools.run_ahead_secondary_instance)
  11883. {
  11884. snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_RUNAHEAD_ENABLED),
  11885. settings->uints.run_ahead_frames);
  11886. runloop_msg_queue_push(
  11887. msg, 1, 100, false,
  11888. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  11889. }
  11890. else
  11891. {
  11892. snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_RUNAHEAD_ENABLED_WITH_SECOND_INSTANCE),
  11893. settings->uints.run_ahead_frames);
  11894. runloop_msg_queue_push(
  11895. msg, 1, 100, false,
  11896. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  11897. }
  11898. }
  11899. break;
  11900. case CMD_EVENT_RECORDING_TOGGLE:
  11901. if (recording_is_enabled())
  11902. command_event(CMD_EVENT_RECORD_DEINIT, NULL);
  11903. else
  11904. command_event(CMD_EVENT_RECORD_INIT, NULL);
  11905. break;
  11906. case CMD_EVENT_OSK_TOGGLE:
  11907. if (p_rarch->input_driver_keyboard_linefeed_enable)
  11908. p_rarch->input_driver_keyboard_linefeed_enable = false;
  11909. else
  11910. p_rarch->input_driver_keyboard_linefeed_enable = true;
  11911. break;
  11912. case CMD_EVENT_SET_PER_GAME_RESOLUTION:
  11913. #if defined(GEKKO)
  11914. {
  11915. unsigned width = 0, height = 0;
  11916. command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL);
  11917. if (video_driver_get_video_output_size(&width, &height))
  11918. {
  11919. char msg[128] = {0};
  11920. video_driver_set_video_mode(width, height, true);
  11921. if (width == 0 || height == 0)
  11922. snprintf(msg, sizeof(msg), "%s: DEFAULT",
  11923. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION));
  11924. else
  11925. snprintf(msg, sizeof(msg),"%s: %dx%d",
  11926. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION),
  11927. width, height);
  11928. runloop_msg_queue_push(msg, 1, 100, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  11929. }
  11930. }
  11931. #endif
  11932. break;
  11933. case CMD_EVENT_LOAD_CORE_PERSIST:
  11934. {
  11935. core_info_ctx_find_t info_find;
  11936. rarch_system_info_t *system_info = &p_rarch->runloop_system;
  11937. struct retro_system_info *system = &system_info->info;
  11938. const char *core_path = path_get(RARCH_PATH_CORE);
  11939. #if defined(HAVE_DYNAMIC)
  11940. if (string_is_empty(core_path))
  11941. return false;
  11942. #endif
  11943. if (!libretro_get_system_info(
  11944. p_rarch,
  11945. core_path,
  11946. system,
  11947. &system_info->load_no_content))
  11948. return false;
  11949. info_find.path = core_path;
  11950. if (!core_info_load(&info_find, &p_rarch->core_info_st))
  11951. {
  11952. #ifdef HAVE_DYNAMIC
  11953. return false;
  11954. #endif
  11955. }
  11956. }
  11957. break;
  11958. case CMD_EVENT_LOAD_CORE:
  11959. {
  11960. bool success = false;
  11961. subsystem_current_count = 0;
  11962. content_clear_subsystem();
  11963. success = command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
  11964. (void)success;
  11965. #ifndef HAVE_DYNAMIC
  11966. command_event(CMD_EVENT_QUIT, NULL);
  11967. #else
  11968. if (!success)
  11969. return false;
  11970. #endif
  11971. break;
  11972. }
  11973. case CMD_EVENT_LOAD_STATE:
  11974. #ifdef HAVE_BSV_MOVIE
  11975. /* Immutable - disallow savestate load when
  11976. * we absolutely cannot change game state. */
  11977. if (p_rarch->bsv_movie_state_handle)
  11978. return false;
  11979. #endif
  11980. #ifdef HAVE_CHEEVOS
  11981. if (rcheevos_hardcore_active())
  11982. return false;
  11983. #endif
  11984. if (!command_event_main_state(p_rarch, cmd))
  11985. return false;
  11986. break;
  11987. case CMD_EVENT_UNDO_LOAD_STATE:
  11988. if (!command_event_main_state(p_rarch, cmd))
  11989. return false;
  11990. break;
  11991. case CMD_EVENT_UNDO_SAVE_STATE:
  11992. if (!command_event_main_state(p_rarch, cmd))
  11993. return false;
  11994. break;
  11995. case CMD_EVENT_RESIZE_WINDOWED_SCALE:
  11996. if (!command_event_resize_windowed_scale(p_rarch))
  11997. return false;
  11998. break;
  11999. case CMD_EVENT_MENU_TOGGLE:
  12000. #ifdef HAVE_MENU
  12001. if (p_rarch->menu_driver_alive)
  12002. retroarch_menu_running_finished(false);
  12003. else
  12004. retroarch_menu_running();
  12005. #endif
  12006. break;
  12007. case CMD_EVENT_RESET:
  12008. RARCH_LOG("[Core]: %s.\n", msg_hash_to_str(MSG_RESET));
  12009. runloop_msg_queue_push(msg_hash_to_str(MSG_RESET), 1, 120, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  12010. core_reset();
  12011. #ifdef HAVE_CHEEVOS
  12012. #ifdef HAVE_GFX_WIDGETS
  12013. rcheevos_reset_game(p_rarch->widgets_active);
  12014. #else
  12015. rcheevos_reset_game(false);
  12016. #endif
  12017. #endif
  12018. #if HAVE_NETWORKING
  12019. netplay_driver_ctl(RARCH_NETPLAY_CTL_RESET, NULL);
  12020. #endif
  12021. return false;
  12022. case CMD_EVENT_SAVE_STATE:
  12023. {
  12024. bool savestate_auto_index = settings->bools.savestate_auto_index;
  12025. int state_slot = settings->ints.state_slot;
  12026. if (savestate_auto_index)
  12027. {
  12028. int new_state_slot = state_slot + 1;
  12029. configuration_set_int(settings, settings->ints.state_slot, new_state_slot);
  12030. }
  12031. }
  12032. if (!command_event_main_state(p_rarch, cmd))
  12033. return false;
  12034. break;
  12035. case CMD_EVENT_SAVE_STATE_DECREMENT:
  12036. {
  12037. int state_slot = settings->ints.state_slot;
  12038. /* Slot -1 is (auto) slot. */
  12039. if (state_slot >= 0)
  12040. {
  12041. int new_state_slot = state_slot - 1;
  12042. configuration_set_int(settings, settings->ints.state_slot, new_state_slot);
  12043. }
  12044. }
  12045. break;
  12046. case CMD_EVENT_SAVE_STATE_INCREMENT:
  12047. {
  12048. int new_state_slot = settings->ints.state_slot + 1;
  12049. configuration_set_int(settings, settings->ints.state_slot, new_state_slot);
  12050. }
  12051. break;
  12052. case CMD_EVENT_TAKE_SCREENSHOT:
  12053. #ifdef HAVE_SCREENSHOTS
  12054. {
  12055. const char *dir_screenshot = settings->paths.directory_screenshot;
  12056. if (!take_screenshot(dir_screenshot,
  12057. path_get(RARCH_PATH_BASENAME), false,
  12058. video_driver_cached_frame_has_valid_framebuffer(), false, true))
  12059. return false;
  12060. }
  12061. #endif
  12062. break;
  12063. case CMD_EVENT_UNLOAD_CORE:
  12064. {
  12065. bool contentless = false;
  12066. bool is_inited = false;
  12067. content_ctx_info_t content_info = {0};
  12068. global_t *global = &p_rarch->g_extern;
  12069. rarch_system_info_t *sys_info = &p_rarch->runloop_system;
  12070. content_get_status(&contentless, &is_inited);
  12071. p_rarch->runloop_core_running = false;
  12072. /* Save last selected disk index, if required */
  12073. if (sys_info)
  12074. disk_control_save_image_index(&sys_info->disk_control);
  12075. command_event_runtime_log_deinit(p_rarch);
  12076. command_event_save_auto_state(settings,
  12077. global, p_rarch);
  12078. #ifdef HAVE_CONFIGFILE
  12079. if (p_rarch->runloop_overrides_active)
  12080. {
  12081. command_event_disable_overrides(p_rarch);
  12082. if (!settings->bools.video_fullscreen)
  12083. {
  12084. video_driver_show_mouse();
  12085. input_driver_ungrab_mouse(p_rarch);
  12086. }
  12087. }
  12088. #endif
  12089. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  12090. p_rarch->runtime_shader_preset[0] = '\0';
  12091. #endif
  12092. video_driver_restore_cached(p_rarch, settings);
  12093. #ifdef HAVE_CONFIGFILE
  12094. if ( p_rarch->runloop_remaps_core_active
  12095. || p_rarch->runloop_remaps_content_dir_active
  12096. || p_rarch->runloop_remaps_game_active
  12097. )
  12098. input_remapping_set_defaults(true);
  12099. #endif
  12100. if (is_inited)
  12101. {
  12102. #ifdef HAVE_MENU
  12103. if ( (settings->uints.quit_on_close_content == QUIT_ON_CLOSE_CONTENT_CLI && global->launched_from_cli)
  12104. || settings->uints.quit_on_close_content == QUIT_ON_CLOSE_CONTENT_ENABLED
  12105. )
  12106. command_event(CMD_EVENT_QUIT, NULL);
  12107. #endif
  12108. if (!task_push_start_dummy_core(&content_info))
  12109. return false;
  12110. }
  12111. #ifdef HAVE_DISCORD
  12112. if (discord_is_inited)
  12113. {
  12114. discord_userdata_t userdata;
  12115. userdata.status = DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED;
  12116. command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
  12117. userdata.status = DISCORD_PRESENCE_MENU;
  12118. command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
  12119. }
  12120. #endif
  12121. #ifdef HAVE_DYNAMIC
  12122. path_clear(RARCH_PATH_CORE);
  12123. retroarch_system_info_free(p_rarch);
  12124. #endif
  12125. if (is_inited)
  12126. {
  12127. subsystem_current_count = 0;
  12128. content_clear_subsystem();
  12129. }
  12130. }
  12131. break;
  12132. case CMD_EVENT_CLOSE_CONTENT:
  12133. #ifdef HAVE_MENU
  12134. /* Closing content via hotkey requires toggling menu
  12135. * and resetting the position later on to prevent
  12136. * going to empty Quick Menu */
  12137. if (!p_rarch->menu_driver_alive)
  12138. {
  12139. p_rarch->menu_driver_state.pending_close_content = true;
  12140. command_event(CMD_EVENT_MENU_TOGGLE, NULL);
  12141. }
  12142. #else
  12143. command_event(CMD_EVENT_QUIT, NULL);
  12144. #endif
  12145. break;
  12146. case CMD_EVENT_QUIT:
  12147. if (!retroarch_main_quit())
  12148. return false;
  12149. break;
  12150. case CMD_EVENT_CHEEVOS_HARDCORE_MODE_TOGGLE:
  12151. #ifdef HAVE_CHEEVOS
  12152. rcheevos_toggle_hardcore_paused();
  12153. #endif
  12154. break;
  12155. case CMD_EVENT_REINIT_FROM_TOGGLE:
  12156. p_rarch->rarch_force_fullscreen = false;
  12157. /* this fallthrough is on purpose, it should do
  12158. a CMD_EVENT_REINIT too */
  12159. case CMD_EVENT_REINIT:
  12160. command_event_reinit(p_rarch,
  12161. data ? *(const int*)data : DRIVERS_CMD_ALL);
  12162. break;
  12163. case CMD_EVENT_CHEATS_APPLY:
  12164. #ifdef HAVE_CHEATS
  12165. cheat_manager_apply_cheats();
  12166. #endif
  12167. break;
  12168. case CMD_EVENT_REWIND_DEINIT:
  12169. #ifdef HAVE_REWIND
  12170. state_manager_event_deinit(&p_rarch->rewind_st);
  12171. #endif
  12172. break;
  12173. case CMD_EVENT_REWIND_INIT:
  12174. #ifdef HAVE_REWIND
  12175. {
  12176. bool rewind_enable = settings->bools.rewind_enable;
  12177. size_t rewind_buf_size = settings->sizes.rewind_buffer_size;
  12178. #ifdef HAVE_CHEEVOS
  12179. if (rcheevos_hardcore_active())
  12180. return false;
  12181. #endif
  12182. if (rewind_enable)
  12183. {
  12184. #ifdef HAVE_NETWORKING
  12185. /* Only enable state manager if netplay is not underway
  12186. TODO/FIXME: Add a setting for these tweaks */
  12187. if (!netplay_driver_ctl(
  12188. RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
  12189. #endif
  12190. {
  12191. state_manager_event_init(&p_rarch->rewind_st,
  12192. (unsigned)rewind_buf_size);
  12193. }
  12194. }
  12195. }
  12196. #endif
  12197. break;
  12198. case CMD_EVENT_REWIND_TOGGLE:
  12199. #ifdef HAVE_REWIND
  12200. {
  12201. bool rewind_enable = settings->bools.rewind_enable;
  12202. if (rewind_enable)
  12203. command_event(CMD_EVENT_REWIND_INIT, NULL);
  12204. else
  12205. command_event(CMD_EVENT_REWIND_DEINIT, NULL);
  12206. }
  12207. #endif
  12208. break;
  12209. case CMD_EVENT_AUTOSAVE_INIT:
  12210. #ifdef HAVE_THREADS
  12211. retroarch_autosave_deinit(p_rarch);
  12212. {
  12213. #ifdef HAVE_NETWORKING
  12214. unsigned autosave_interval =
  12215. settings->uints.autosave_interval;
  12216. /* Only enable state manager if netplay is not underway
  12217. TODO/FIXME: Add a setting for these tweaks */
  12218. if ( (autosave_interval != 0)
  12219. && !netplay_driver_ctl(
  12220. RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
  12221. #endif
  12222. p_rarch->runloop_autosave = autosave_init();
  12223. }
  12224. #endif
  12225. break;
  12226. case CMD_EVENT_AUDIO_STOP:
  12227. midi_driver_set_all_sounds_off(p_rarch);
  12228. if (!audio_driver_stop(p_rarch))
  12229. return false;
  12230. break;
  12231. case CMD_EVENT_AUDIO_START:
  12232. if (!audio_driver_start(p_rarch,
  12233. p_rarch->runloop_shutdown_initiated))
  12234. return false;
  12235. break;
  12236. case CMD_EVENT_AUDIO_MUTE_TOGGLE:
  12237. {
  12238. bool audio_mute_enable =
  12239. *(audio_get_bool_ptr(AUDIO_ACTION_MUTE_ENABLE));
  12240. const char *msg = !audio_mute_enable ?
  12241. msg_hash_to_str(MSG_AUDIO_MUTED):
  12242. msg_hash_to_str(MSG_AUDIO_UNMUTED);
  12243. p_rarch->audio_driver_mute_enable =
  12244. !p_rarch->audio_driver_mute_enable;
  12245. #if defined(HAVE_GFX_WIDGETS)
  12246. if (p_rarch->widgets_active)
  12247. gfx_widget_volume_update_and_show(
  12248. settings->floats.audio_volume,
  12249. p_rarch->audio_driver_mute_enable);
  12250. else
  12251. #endif
  12252. runloop_msg_queue_push(msg, 1, 180, true, NULL,
  12253. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  12254. }
  12255. break;
  12256. case CMD_EVENT_SEND_DEBUG_INFO:
  12257. break;
  12258. case CMD_EVENT_FPS_TOGGLE:
  12259. settings->bools.video_fps_show = !(settings->bools.video_fps_show);
  12260. break;
  12261. case CMD_EVENT_OVERLAY_NEXT:
  12262. /* Switch to the next available overlay screen. */
  12263. #ifdef HAVE_OVERLAY
  12264. {
  12265. bool *check_rotation = (bool*)data;
  12266. bool inp_overlay_auto_rotate = settings->bools.input_overlay_auto_rotate;
  12267. float input_overlay_opacity = settings->floats.input_overlay_opacity;
  12268. if (!p_rarch->overlay_ptr)
  12269. return false;
  12270. p_rarch->overlay_ptr->index = p_rarch->overlay_ptr->next_index;
  12271. p_rarch->overlay_ptr->active = &p_rarch->overlay_ptr->overlays[
  12272. p_rarch->overlay_ptr->index];
  12273. input_overlay_load_active(p_rarch,
  12274. p_rarch->overlay_ptr, input_overlay_opacity);
  12275. p_rarch->overlay_ptr->blocked = true;
  12276. p_rarch->overlay_ptr->next_index = (unsigned)((p_rarch->overlay_ptr->index + 1) % p_rarch->overlay_ptr->size);
  12277. /* Check orientation, if required */
  12278. if (inp_overlay_auto_rotate)
  12279. if (check_rotation)
  12280. if (*check_rotation)
  12281. input_overlay_auto_rotate_(p_rarch,
  12282. p_rarch->overlay_ptr);
  12283. }
  12284. #endif
  12285. break;
  12286. case CMD_EVENT_DSP_FILTER_INIT:
  12287. #ifdef HAVE_DSP_FILTER
  12288. {
  12289. const char *path_audio_dsp_plugin = settings->paths.path_audio_dsp_plugin;
  12290. audio_driver_dsp_filter_free();
  12291. if (string_is_empty(path_audio_dsp_plugin))
  12292. break;
  12293. if (!audio_driver_dsp_filter_init(path_audio_dsp_plugin))
  12294. {
  12295. RARCH_ERR("[DSP]: Failed to initialize DSP filter \"%s\".\n",
  12296. path_audio_dsp_plugin);
  12297. }
  12298. }
  12299. #endif
  12300. break;
  12301. case CMD_EVENT_RECORD_DEINIT:
  12302. p_rarch->recording_enable = false;
  12303. streaming_set_state(false);
  12304. if (!recording_deinit(p_rarch))
  12305. return false;
  12306. break;
  12307. case CMD_EVENT_RECORD_INIT:
  12308. p_rarch->recording_enable = true;
  12309. if (!recording_init(settings, p_rarch))
  12310. {
  12311. command_event(CMD_EVENT_RECORD_DEINIT, NULL);
  12312. return false;
  12313. }
  12314. break;
  12315. case CMD_EVENT_HISTORY_DEINIT:
  12316. if (g_defaults.content_history)
  12317. {
  12318. playlist_write_file(g_defaults.content_history);
  12319. playlist_free(g_defaults.content_history);
  12320. }
  12321. g_defaults.content_history = NULL;
  12322. if (g_defaults.music_history)
  12323. {
  12324. playlist_write_file(g_defaults.music_history);
  12325. playlist_free(g_defaults.music_history);
  12326. }
  12327. g_defaults.music_history = NULL;
  12328. #if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
  12329. if (g_defaults.video_history)
  12330. {
  12331. playlist_write_file(g_defaults.video_history);
  12332. playlist_free(g_defaults.video_history);
  12333. }
  12334. g_defaults.video_history = NULL;
  12335. #endif
  12336. #ifdef HAVE_IMAGEVIEWER
  12337. if (g_defaults.image_history)
  12338. {
  12339. playlist_write_file(g_defaults.image_history);
  12340. playlist_free(g_defaults.image_history);
  12341. }
  12342. g_defaults.image_history = NULL;
  12343. #endif
  12344. break;
  12345. case CMD_EVENT_HISTORY_INIT:
  12346. {
  12347. playlist_config_t playlist_config;
  12348. bool history_list_enable = settings->bools.history_list_enable;
  12349. const char *path_content_history = settings->paths.path_content_history;
  12350. const char *path_content_music_history = settings->paths.path_content_music_history;
  12351. #if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
  12352. const char *path_content_video_history = settings->paths.path_content_video_history;
  12353. #endif
  12354. #ifdef HAVE_IMAGEVIEWER
  12355. const char *path_content_image_history = settings->paths.path_content_image_history;
  12356. #endif
  12357. playlist_config.capacity = settings->uints.content_history_size;
  12358. playlist_config.old_format = settings->bools.playlist_use_old_format;
  12359. playlist_config.compress = settings->bools.playlist_compression;
  12360. playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match;
  12361. /* don't use relative paths for content, music, video, and image histories */
  12362. playlist_config_set_base_content_directory(&playlist_config, NULL);
  12363. command_event(CMD_EVENT_HISTORY_DEINIT, NULL);
  12364. if (!history_list_enable)
  12365. return false;
  12366. /* Note: Sorting is disabled by default for
  12367. * all content history playlists */
  12368. RARCH_LOG("[Playlist]: %s: [%s].\n",
  12369. msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
  12370. path_content_history);
  12371. playlist_config_set_path(&playlist_config, path_content_history);
  12372. g_defaults.content_history = playlist_init(&playlist_config);
  12373. playlist_set_sort_mode(
  12374. g_defaults.content_history, PLAYLIST_SORT_MODE_OFF);
  12375. RARCH_LOG("[Playlist]: %s: [%s].\n",
  12376. msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
  12377. path_content_music_history);
  12378. playlist_config_set_path(&playlist_config, path_content_music_history);
  12379. g_defaults.music_history = playlist_init(&playlist_config);
  12380. playlist_set_sort_mode(
  12381. g_defaults.music_history, PLAYLIST_SORT_MODE_OFF);
  12382. #if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
  12383. RARCH_LOG("[Playlist]: %s: [%s].\n",
  12384. msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
  12385. path_content_video_history);
  12386. playlist_config_set_path(&playlist_config, path_content_video_history);
  12387. g_defaults.video_history = playlist_init(&playlist_config);
  12388. playlist_set_sort_mode(
  12389. g_defaults.video_history, PLAYLIST_SORT_MODE_OFF);
  12390. #endif
  12391. #ifdef HAVE_IMAGEVIEWER
  12392. RARCH_LOG("[Playlist]: %s: [%s].\n",
  12393. msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
  12394. path_content_image_history);
  12395. playlist_config_set_path(&playlist_config, path_content_image_history);
  12396. g_defaults.image_history = playlist_init(&playlist_config);
  12397. playlist_set_sort_mode(
  12398. g_defaults.image_history, PLAYLIST_SORT_MODE_OFF);
  12399. #endif
  12400. }
  12401. break;
  12402. case CMD_EVENT_CORE_INFO_DEINIT:
  12403. core_info_deinit_list();
  12404. core_info_free_current_core(&p_rarch->core_info_st);
  12405. break;
  12406. case CMD_EVENT_CORE_INFO_INIT:
  12407. {
  12408. char ext_name[255];
  12409. const char *dir_libretro = settings->paths.directory_libretro;
  12410. const char *path_libretro_info = settings->paths.path_libretro_info;
  12411. bool show_hidden_files = settings->bools.show_hidden_files;
  12412. ext_name[0] = '\0';
  12413. command_event(CMD_EVENT_CORE_INFO_DEINIT, NULL);
  12414. if (!frontend_driver_get_core_extension(ext_name, sizeof(ext_name)))
  12415. return false;
  12416. if (!string_is_empty(dir_libretro))
  12417. core_info_init_list(path_libretro_info,
  12418. dir_libretro,
  12419. ext_name,
  12420. show_hidden_files
  12421. );
  12422. }
  12423. break;
  12424. case CMD_EVENT_CORE_DEINIT:
  12425. {
  12426. struct retro_hw_render_callback *hwr = NULL;
  12427. rarch_system_info_t *sys_info = &p_rarch->runloop_system;
  12428. /* Save last selected disk index, if required */
  12429. if (sys_info)
  12430. disk_control_save_image_index(&sys_info->disk_control);
  12431. command_event_runtime_log_deinit(p_rarch);
  12432. content_reset_savestate_backups();
  12433. hwr = VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
  12434. #ifdef HAVE_CHEEVOS
  12435. rcheevos_unload();
  12436. #endif
  12437. command_event_deinit_core(p_rarch, true);
  12438. #ifdef HAVE_RUNAHEAD
  12439. /* If 'runahead_available' is false, then
  12440. * runahead is enabled by the user but an
  12441. * error occurred while the core was running
  12442. * (typically a save state issue). In this
  12443. * case we have to 'manually' reset the runahead
  12444. * runtime variables, otherwise runahead will
  12445. * remain disabled until the user restarts
  12446. * RetroArch */
  12447. if (!p_rarch->runahead_available)
  12448. runahead_clear_variables(p_rarch);
  12449. #endif
  12450. if (hwr)
  12451. memset(hwr, 0, sizeof(*hwr));
  12452. break;
  12453. }
  12454. case CMD_EVENT_CORE_INIT:
  12455. {
  12456. enum rarch_core_type *type = (enum rarch_core_type*)data;
  12457. rarch_system_info_t *sys_info = &p_rarch->runloop_system;
  12458. content_reset_savestate_backups();
  12459. /* Ensure that disk control interface is reset */
  12460. if (sys_info)
  12461. disk_control_set_ext_callback(&sys_info->disk_control, NULL);
  12462. if (!type || !command_event_init_core(settings, p_rarch, *type))
  12463. return false;
  12464. }
  12465. break;
  12466. case CMD_EVENT_VIDEO_APPLY_STATE_CHANGES:
  12467. video_driver_apply_state_changes();
  12468. break;
  12469. case CMD_EVENT_VIDEO_SET_BLOCKING_STATE:
  12470. {
  12471. bool adaptive_vsync = settings->bools.video_adaptive_vsync;
  12472. unsigned swap_interval = settings->uints.video_swap_interval;
  12473. if (p_rarch->current_video->set_nonblock_state)
  12474. p_rarch->current_video->set_nonblock_state(
  12475. p_rarch->video_driver_data, false,
  12476. video_driver_test_all_flags(
  12477. GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
  12478. adaptive_vsync, swap_interval);
  12479. }
  12480. break;
  12481. case CMD_EVENT_VIDEO_SET_ASPECT_RATIO:
  12482. video_driver_set_aspect_ratio();
  12483. break;
  12484. case CMD_EVENT_OVERLAY_SET_SCALE_FACTOR:
  12485. #ifdef HAVE_OVERLAY
  12486. {
  12487. overlay_layout_desc_t layout_desc;
  12488. layout_desc.scale_landscape = settings->floats.input_overlay_scale_landscape;
  12489. layout_desc.aspect_adjust_landscape = settings->floats.input_overlay_aspect_adjust_landscape;
  12490. layout_desc.x_separation_landscape = settings->floats.input_overlay_x_separation_landscape;
  12491. layout_desc.y_separation_landscape = settings->floats.input_overlay_y_separation_landscape;
  12492. layout_desc.x_offset_landscape = settings->floats.input_overlay_x_offset_landscape;
  12493. layout_desc.y_offset_landscape = settings->floats.input_overlay_y_offset_landscape;
  12494. layout_desc.scale_portrait = settings->floats.input_overlay_scale_portrait;
  12495. layout_desc.aspect_adjust_portrait = settings->floats.input_overlay_aspect_adjust_portrait;
  12496. layout_desc.x_separation_portrait = settings->floats.input_overlay_x_separation_portrait;
  12497. layout_desc.y_separation_portrait = settings->floats.input_overlay_y_separation_portrait;
  12498. layout_desc.x_offset_portrait = settings->floats.input_overlay_x_offset_portrait;
  12499. layout_desc.y_offset_portrait = settings->floats.input_overlay_y_offset_portrait;
  12500. layout_desc.auto_scale = settings->bools.input_overlay_auto_scale;
  12501. input_overlay_set_scale_factor(p_rarch, p_rarch->overlay_ptr, &layout_desc);
  12502. }
  12503. #endif
  12504. break;
  12505. case CMD_EVENT_OVERLAY_SET_ALPHA_MOD:
  12506. /* Sets a modulating factor for alpha channel. Default is 1.0.
  12507. * The alpha factor is applied for all overlays. */
  12508. #ifdef HAVE_OVERLAY
  12509. {
  12510. float input_overlay_opacity = settings->floats.input_overlay_opacity;
  12511. input_overlay_set_alpha_mod(p_rarch,
  12512. p_rarch->overlay_ptr, input_overlay_opacity);
  12513. }
  12514. #endif
  12515. break;
  12516. case CMD_EVENT_AUDIO_REINIT:
  12517. driver_uninit(p_rarch, DRIVER_AUDIO_MASK);
  12518. drivers_init(p_rarch, DRIVER_AUDIO_MASK);
  12519. break;
  12520. case CMD_EVENT_SHUTDOWN:
  12521. #if defined(__linux__) && !defined(ANDROID)
  12522. runloop_msg_queue_push(msg_hash_to_str(MSG_VALUE_SHUTTING_DOWN), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  12523. command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
  12524. command_event(CMD_EVENT_QUIT, NULL);
  12525. system("shutdown -P now");
  12526. #endif
  12527. break;
  12528. case CMD_EVENT_REBOOT:
  12529. #if defined(__linux__) && !defined(ANDROID)
  12530. runloop_msg_queue_push(msg_hash_to_str(MSG_VALUE_REBOOTING), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  12531. command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
  12532. command_event(CMD_EVENT_QUIT, NULL);
  12533. system("shutdown -r now");
  12534. #endif
  12535. break;
  12536. case CMD_EVENT_RESUME:
  12537. retroarch_menu_running_finished(false);
  12538. if (p_rarch->main_ui_companion_is_on_foreground)
  12539. ui_companion_driver_toggle(settings, p_rarch, false);
  12540. break;
  12541. case CMD_EVENT_ADD_TO_FAVORITES:
  12542. {
  12543. struct string_list *str_list = (struct string_list*)data;
  12544. /* Check whether favourties playlist is at capacity */
  12545. if (playlist_size(g_defaults.content_favorites) >=
  12546. playlist_capacity(g_defaults.content_favorites))
  12547. {
  12548. runloop_msg_queue_push(
  12549. msg_hash_to_str(MSG_ADD_TO_FAVORITES_FAILED), 1, 180, true, NULL,
  12550. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR);
  12551. return false;
  12552. }
  12553. if (str_list)
  12554. {
  12555. if (str_list->size >= 6)
  12556. {
  12557. struct playlist_entry entry = {0};
  12558. bool playlist_sort_alphabetical = settings->bools.playlist_sort_alphabetical;
  12559. entry.path = str_list->elems[0].data; /* content_path */
  12560. entry.label = str_list->elems[1].data; /* content_label */
  12561. entry.core_path = str_list->elems[2].data; /* core_path */
  12562. entry.core_name = str_list->elems[3].data; /* core_name */
  12563. entry.crc32 = str_list->elems[4].data; /* crc32 */
  12564. entry.db_name = str_list->elems[5].data; /* db_name */
  12565. /* Write playlist entry */
  12566. if (playlist_push(g_defaults.content_favorites, &entry))
  12567. {
  12568. enum playlist_sort_mode current_sort_mode =
  12569. playlist_get_sort_mode(g_defaults.content_favorites);
  12570. /* New addition - need to resort if option is enabled */
  12571. if ((playlist_sort_alphabetical && (current_sort_mode == PLAYLIST_SORT_MODE_DEFAULT)) ||
  12572. (current_sort_mode == PLAYLIST_SORT_MODE_ALPHABETICAL))
  12573. playlist_qsort(g_defaults.content_favorites);
  12574. playlist_write_file(g_defaults.content_favorites);
  12575. runloop_msg_queue_push(msg_hash_to_str(MSG_ADDED_TO_FAVORITES), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  12576. }
  12577. }
  12578. }
  12579. break;
  12580. }
  12581. case CMD_EVENT_RESET_CORE_ASSOCIATION:
  12582. {
  12583. const char *core_name = "DETECT";
  12584. const char *core_path = "DETECT";
  12585. size_t *playlist_index = (size_t*)data;
  12586. struct playlist_entry entry = {0};
  12587. /* the update function reads our entry as const,
  12588. * so these casts are safe */
  12589. entry.core_path = (char*)core_path;
  12590. entry.core_name = (char*)core_name;
  12591. command_playlist_update_write(
  12592. NULL, *playlist_index, &entry);
  12593. runloop_msg_queue_push(msg_hash_to_str(MSG_RESET_CORE_ASSOCIATION), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  12594. break;
  12595. }
  12596. case CMD_EVENT_RESTART_RETROARCH:
  12597. if (!frontend_driver_set_fork(FRONTEND_FORK_RESTART))
  12598. return false;
  12599. #ifndef HAVE_DYNAMIC
  12600. command_event(CMD_EVENT_QUIT, NULL);
  12601. #endif
  12602. break;
  12603. case CMD_EVENT_MENU_RESET_TO_DEFAULT_CONFIG:
  12604. config_set_defaults(&p_rarch->g_extern);
  12605. break;
  12606. case CMD_EVENT_MENU_SAVE_CURRENT_CONFIG:
  12607. #if !defined(HAVE_DYNAMIC)
  12608. config_save_file_salamander();
  12609. #endif
  12610. #ifdef HAVE_CONFIGFILE
  12611. command_event_save_current_config(p_rarch, OVERRIDE_NONE);
  12612. #endif
  12613. break;
  12614. case CMD_EVENT_MENU_SAVE_CURRENT_CONFIG_OVERRIDE_CORE:
  12615. #ifdef HAVE_CONFIGFILE
  12616. command_event_save_current_config(p_rarch, OVERRIDE_CORE);
  12617. #endif
  12618. break;
  12619. case CMD_EVENT_MENU_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR:
  12620. #ifdef HAVE_CONFIGFILE
  12621. command_event_save_current_config(p_rarch, OVERRIDE_CONTENT_DIR);
  12622. #endif
  12623. break;
  12624. case CMD_EVENT_MENU_SAVE_CURRENT_CONFIG_OVERRIDE_GAME:
  12625. #ifdef HAVE_CONFIGFILE
  12626. command_event_save_current_config(p_rarch, OVERRIDE_GAME);
  12627. #endif
  12628. break;
  12629. case CMD_EVENT_MENU_SAVE_CONFIG:
  12630. #ifdef HAVE_CONFIGFILE
  12631. if (!command_event_save_core_config(p_rarch,
  12632. settings->paths.directory_menu_config))
  12633. return false;
  12634. #endif
  12635. break;
  12636. case CMD_EVENT_SHADER_PRESET_LOADED:
  12637. ui_companion_event_command(cmd);
  12638. break;
  12639. case CMD_EVENT_SHADERS_APPLY_CHANGES:
  12640. #ifdef HAVE_MENU
  12641. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  12642. menu_shader_manager_apply_changes(menu_shader_get(),
  12643. settings->paths.directory_video_shader,
  12644. settings->paths.directory_menu_config
  12645. );
  12646. #endif
  12647. #endif
  12648. ui_companion_event_command(cmd);
  12649. break;
  12650. case CMD_EVENT_PAUSE_TOGGLE:
  12651. boolean = p_rarch->runloop_paused;
  12652. boolean = !boolean;
  12653. #ifdef HAVE_ACCESSIBILITY
  12654. if (is_accessibility_enabled(p_rarch))
  12655. {
  12656. if (boolean)
  12657. accessibility_speak_priority(p_rarch,
  12658. (char*) msg_hash_to_str(MSG_PAUSED), 10);
  12659. else
  12660. accessibility_speak_priority(p_rarch,
  12661. (char*) msg_hash_to_str(MSG_UNPAUSED), 10);
  12662. }
  12663. #endif
  12664. p_rarch->runloop_paused = boolean;
  12665. retroarch_pause_checks(p_rarch);
  12666. break;
  12667. case CMD_EVENT_UNPAUSE:
  12668. boolean = false;
  12669. p_rarch->runloop_paused = boolean;
  12670. retroarch_pause_checks(p_rarch);
  12671. break;
  12672. case CMD_EVENT_PAUSE:
  12673. boolean = true;
  12674. p_rarch->runloop_paused = boolean;
  12675. retroarch_pause_checks(p_rarch);
  12676. break;
  12677. case CMD_EVENT_MENU_PAUSE_LIBRETRO:
  12678. #ifdef HAVE_MENU
  12679. if (p_rarch->menu_driver_alive)
  12680. {
  12681. bool menu_pause_libretro = settings->bools.menu_pause_libretro;
  12682. if (menu_pause_libretro)
  12683. command_event(CMD_EVENT_AUDIO_STOP, NULL);
  12684. else
  12685. command_event(CMD_EVENT_AUDIO_START, NULL);
  12686. }
  12687. else
  12688. {
  12689. bool menu_pause_libretro = settings->bools.menu_pause_libretro;
  12690. if (menu_pause_libretro)
  12691. command_event(CMD_EVENT_AUDIO_START, NULL);
  12692. }
  12693. #endif
  12694. break;
  12695. #ifdef HAVE_NETWORKING
  12696. case CMD_EVENT_NETPLAY_GAME_WATCH:
  12697. netplay_driver_ctl(RARCH_NETPLAY_CTL_GAME_WATCH, NULL);
  12698. break;
  12699. case CMD_EVENT_NETPLAY_DEINIT:
  12700. deinit_netplay(p_rarch);
  12701. break;
  12702. case CMD_EVENT_NETWORK_INIT:
  12703. network_init();
  12704. break;
  12705. /* init netplay manually */
  12706. case CMD_EVENT_NETPLAY_INIT:
  12707. {
  12708. char *hostname = (char*)data;
  12709. const char *netplay_server = settings->paths.netplay_server;
  12710. unsigned netplay_port = settings->uints.netplay_port;
  12711. command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
  12712. if (!init_netplay(p_rarch,
  12713. NULL,
  12714. hostname
  12715. ? hostname
  12716. : netplay_server, netplay_port))
  12717. {
  12718. command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
  12719. return false;
  12720. }
  12721. /* Disable rewind & SRAM autosave if it was enabled
  12722. * TODO/FIXME: Add a setting for these tweaks */
  12723. #ifdef HAVE_REWIND
  12724. state_manager_event_deinit(&p_rarch->rewind_st);
  12725. #endif
  12726. #ifdef HAVE_THREADS
  12727. autosave_deinit();
  12728. #endif
  12729. }
  12730. break;
  12731. /* Initialize netplay via lobby when content is loaded */
  12732. case CMD_EVENT_NETPLAY_INIT_DIRECT:
  12733. {
  12734. /* buf is expected to be address|port */
  12735. static struct string_list *hostname = NULL;
  12736. char *buf = (char *)data;
  12737. unsigned netplay_port = settings->uints.netplay_port;
  12738. hostname = string_split(buf, "|");
  12739. command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
  12740. RARCH_LOG("[Netplay]: Connecting to %s:%d (direct)\n",
  12741. hostname->elems[0].data, !string_is_empty(hostname->elems[1].data)
  12742. ? atoi(hostname->elems[1].data)
  12743. : netplay_port);
  12744. if (!init_netplay(
  12745. p_rarch,
  12746. NULL,
  12747. hostname->elems[0].data,
  12748. !string_is_empty(hostname->elems[1].data)
  12749. ? atoi(hostname->elems[1].data)
  12750. : netplay_port))
  12751. {
  12752. command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
  12753. string_list_free(hostname);
  12754. return false;
  12755. }
  12756. string_list_free(hostname);
  12757. /* Disable rewind if it was enabled
  12758. TODO/FIXME: Add a setting for these tweaks */
  12759. #ifdef HAVE_REWIND
  12760. state_manager_event_deinit(&p_rarch->rewind_st);
  12761. #endif
  12762. #ifdef HAVE_THREADS
  12763. autosave_deinit();
  12764. #endif
  12765. }
  12766. break;
  12767. /* init netplay via lobby when content is not loaded */
  12768. case CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED:
  12769. {
  12770. static struct string_list *hostname = NULL;
  12771. /* buf is expected to be address|port */
  12772. char *buf = (char *)data;
  12773. unsigned netplay_port = settings->uints.netplay_port;
  12774. hostname = string_split(buf, "|");
  12775. command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
  12776. RARCH_LOG("[Netplay]: Connecting to %s:%d (deferred)\n",
  12777. hostname->elems[0].data, !string_is_empty(hostname->elems[1].data)
  12778. ? atoi(hostname->elems[1].data)
  12779. : netplay_port);
  12780. if (!init_netplay_deferred(p_rarch,
  12781. hostname->elems[0].data,
  12782. !string_is_empty(hostname->elems[1].data)
  12783. ? atoi(hostname->elems[1].data)
  12784. : netplay_port))
  12785. {
  12786. command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
  12787. string_list_free(hostname);
  12788. return false;
  12789. }
  12790. string_list_free(hostname);
  12791. /* Disable rewind if it was enabled
  12792. * TODO/FIXME: Add a setting for these tweaks */
  12793. #ifdef HAVE_REWIND
  12794. state_manager_event_deinit(&p_rarch->rewind_st);
  12795. #endif
  12796. #ifdef HAVE_THREADS
  12797. autosave_deinit();
  12798. #endif
  12799. }
  12800. break;
  12801. case CMD_EVENT_NETPLAY_ENABLE_HOST:
  12802. {
  12803. #ifdef HAVE_MENU
  12804. bool contentless = false;
  12805. bool is_inited = false;
  12806. content_get_status(&contentless, &is_inited);
  12807. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
  12808. command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
  12809. netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_SERVER, NULL);
  12810. /* If we haven't yet started, this will load on its own */
  12811. if (!is_inited)
  12812. {
  12813. runloop_msg_queue_push(
  12814. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED),
  12815. 1, 480, true,
  12816. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  12817. return false;
  12818. }
  12819. /* Enable Netplay itself */
  12820. if (!command_event(CMD_EVENT_NETPLAY_INIT, NULL))
  12821. return false;
  12822. #endif
  12823. break;
  12824. }
  12825. case CMD_EVENT_NETPLAY_DISCONNECT:
  12826. {
  12827. netplay_driver_ctl(RARCH_NETPLAY_CTL_DISCONNECT, NULL);
  12828. netplay_driver_ctl(RARCH_NETPLAY_CTL_DISABLE, NULL);
  12829. {
  12830. bool rewind_enable = settings->bools.rewind_enable;
  12831. unsigned autosave_interval = settings->uints.autosave_interval;
  12832. #ifdef HAVE_REWIND
  12833. /* Re-enable rewind if it was enabled
  12834. * TODO/FIXME: Add a setting for these tweaks */
  12835. if (rewind_enable)
  12836. command_event(CMD_EVENT_REWIND_INIT, NULL);
  12837. #endif
  12838. if (autosave_interval != 0)
  12839. command_event(CMD_EVENT_AUTOSAVE_INIT, NULL);
  12840. }
  12841. break;
  12842. }
  12843. case CMD_EVENT_NETPLAY_HOST_TOGGLE:
  12844. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL) &&
  12845. netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_SERVER, NULL))
  12846. command_event(CMD_EVENT_NETPLAY_DISCONNECT, NULL);
  12847. else if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL) &&
  12848. !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_SERVER, NULL) &&
  12849. netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_CONNECTED, NULL))
  12850. command_event(CMD_EVENT_NETPLAY_DISCONNECT, NULL);
  12851. else
  12852. command_event(CMD_EVENT_NETPLAY_ENABLE_HOST, NULL);
  12853. break;
  12854. #else
  12855. case CMD_EVENT_NETPLAY_DEINIT:
  12856. case CMD_EVENT_NETWORK_INIT:
  12857. case CMD_EVENT_NETPLAY_INIT:
  12858. case CMD_EVENT_NETPLAY_INIT_DIRECT:
  12859. case CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED:
  12860. case CMD_EVENT_NETPLAY_HOST_TOGGLE:
  12861. case CMD_EVENT_NETPLAY_DISCONNECT:
  12862. case CMD_EVENT_NETPLAY_ENABLE_HOST:
  12863. case CMD_EVENT_NETPLAY_GAME_WATCH:
  12864. return false;
  12865. #endif
  12866. case CMD_EVENT_FULLSCREEN_TOGGLE:
  12867. {
  12868. bool *userdata = (bool*)data;
  12869. bool video_fullscreen = settings->bools.video_fullscreen;
  12870. bool ra_is_forced_fs = p_rarch->rarch_force_fullscreen;
  12871. bool new_fullscreen_state = !video_fullscreen && !ra_is_forced_fs;
  12872. if (!video_driver_has_windowed())
  12873. return false;
  12874. p_rarch->rarch_is_switching_display_mode = true;
  12875. /* we toggled manually, write the new value to settings */
  12876. configuration_set_bool(settings, settings->bools.video_fullscreen,
  12877. new_fullscreen_state);
  12878. /* Need to grab this setting's value again */
  12879. video_fullscreen = new_fullscreen_state;
  12880. /* we toggled manually, the CLI arg is irrelevant now */
  12881. if (ra_is_forced_fs)
  12882. p_rarch->rarch_force_fullscreen = false;
  12883. /* If we go fullscreen we drop all drivers and
  12884. * reinitialize to be safe. */
  12885. command_event(CMD_EVENT_REINIT, NULL);
  12886. if (video_fullscreen)
  12887. {
  12888. video_driver_hide_mouse();
  12889. if (!settings->bools.video_windowed_fullscreen)
  12890. input_driver_grab_mouse(p_rarch);
  12891. }
  12892. else
  12893. {
  12894. video_driver_show_mouse();
  12895. if (!settings->bools.video_windowed_fullscreen)
  12896. input_driver_ungrab_mouse(p_rarch);
  12897. }
  12898. p_rarch->rarch_is_switching_display_mode = false;
  12899. if (userdata && *userdata == true)
  12900. video_driver_cached_frame();
  12901. }
  12902. break;
  12903. case CMD_EVENT_LOG_FILE_DEINIT:
  12904. retro_main_log_file_deinit();
  12905. break;
  12906. case CMD_EVENT_DISK_APPEND_IMAGE:
  12907. {
  12908. const char *path = (const char*)data;
  12909. rarch_system_info_t *sys_info = &p_rarch->runloop_system;
  12910. if (string_is_empty(path) || !sys_info)
  12911. return false;
  12912. if (disk_control_enabled(&sys_info->disk_control))
  12913. {
  12914. bool success = false;
  12915. #if defined(HAVE_MENU)
  12916. bool refresh = false;
  12917. /* Get initial disk eject state */
  12918. bool initial_disk_ejected = disk_control_get_eject_state(&sys_info->disk_control);
  12919. #endif
  12920. /* Append disk image */
  12921. success = command_event_disk_control_append_image(p_rarch, path);
  12922. #if defined(HAVE_MENU)
  12923. /* Appending a disk image may or may not affect
  12924. * the disk tray eject status. If status has changed,
  12925. * must refresh the disk options menu */
  12926. if (initial_disk_ejected != disk_control_get_eject_state(&sys_info->disk_control))
  12927. {
  12928. menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
  12929. menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
  12930. }
  12931. #endif
  12932. return success;
  12933. }
  12934. else
  12935. runloop_msg_queue_push(
  12936. msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
  12937. 1, 120, true,
  12938. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  12939. }
  12940. break;
  12941. case CMD_EVENT_DISK_EJECT_TOGGLE:
  12942. {
  12943. rarch_system_info_t *sys_info = &p_rarch->runloop_system;
  12944. bool *show_msg = (bool*)data;
  12945. if (!sys_info)
  12946. return false;
  12947. if (disk_control_enabled(&sys_info->disk_control))
  12948. {
  12949. bool eject = !disk_control_get_eject_state(&sys_info->disk_control);
  12950. bool verbose = true;
  12951. bool refresh = false;
  12952. if (show_msg)
  12953. verbose = *show_msg;
  12954. disk_control_set_eject_state(&sys_info->disk_control, eject, verbose);
  12955. #if defined(HAVE_MENU)
  12956. /* It is necessary to refresh the disk options
  12957. * menu when toggling the tray state */
  12958. menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
  12959. menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
  12960. #endif
  12961. }
  12962. else
  12963. runloop_msg_queue_push(
  12964. msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
  12965. 1, 120, true,
  12966. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  12967. }
  12968. break;
  12969. case CMD_EVENT_DISK_NEXT:
  12970. {
  12971. rarch_system_info_t *sys_info = &p_rarch->runloop_system;
  12972. bool *show_msg = (bool*)data;
  12973. if (!sys_info)
  12974. return false;
  12975. if (disk_control_enabled(&sys_info->disk_control))
  12976. {
  12977. bool verbose = true;
  12978. if (show_msg)
  12979. verbose = *show_msg;
  12980. disk_control_set_index_next(&sys_info->disk_control, verbose);
  12981. }
  12982. else
  12983. runloop_msg_queue_push(
  12984. msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
  12985. 1, 120, true,
  12986. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  12987. }
  12988. break;
  12989. case CMD_EVENT_DISK_PREV:
  12990. {
  12991. rarch_system_info_t *sys_info = &p_rarch->runloop_system;
  12992. bool *show_msg = (bool*)data;
  12993. if (!sys_info)
  12994. return false;
  12995. if (disk_control_enabled(&sys_info->disk_control))
  12996. {
  12997. bool verbose = true;
  12998. if (show_msg)
  12999. verbose = *show_msg;
  13000. disk_control_set_index_prev(&sys_info->disk_control, verbose);
  13001. }
  13002. else
  13003. runloop_msg_queue_push(
  13004. msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
  13005. 1, 120, true,
  13006. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  13007. }
  13008. break;
  13009. case CMD_EVENT_DISK_INDEX:
  13010. {
  13011. rarch_system_info_t *sys_info = &p_rarch->runloop_system;
  13012. unsigned *index = (unsigned*)data;
  13013. if (!sys_info || !index)
  13014. return false;
  13015. /* Note: Menu itself provides visual feedback - no
  13016. * need to print info message to screen */
  13017. if (disk_control_enabled(&sys_info->disk_control))
  13018. disk_control_set_index(&sys_info->disk_control, *index, false);
  13019. else
  13020. runloop_msg_queue_push(
  13021. msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
  13022. 1, 120, true,
  13023. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  13024. }
  13025. break;
  13026. case CMD_EVENT_RUMBLE_STOP:
  13027. {
  13028. unsigned i;
  13029. for (i = 0; i < MAX_USERS; i++)
  13030. {
  13031. input_driver_set_rumble_state(i, RETRO_RUMBLE_STRONG, 0);
  13032. input_driver_set_rumble_state(i, RETRO_RUMBLE_WEAK, 0);
  13033. }
  13034. }
  13035. break;
  13036. case CMD_EVENT_GRAB_MOUSE_TOGGLE:
  13037. {
  13038. bool ret = false;
  13039. bool grab_mouse_state = p_rarch->input_driver_grab_mouse_state;
  13040. grab_mouse_state = !grab_mouse_state;
  13041. if (grab_mouse_state)
  13042. ret = input_driver_grab_mouse(p_rarch);
  13043. else
  13044. ret = input_driver_ungrab_mouse(p_rarch);
  13045. if (!ret)
  13046. return false;
  13047. RARCH_LOG("[Input]: %s => %s\n",
  13048. msg_hash_to_str(MSG_GRAB_MOUSE_STATE),
  13049. grab_mouse_state ? "ON" : "OFF");
  13050. if (grab_mouse_state)
  13051. video_driver_hide_mouse();
  13052. else
  13053. video_driver_show_mouse();
  13054. }
  13055. break;
  13056. case CMD_EVENT_UI_COMPANION_TOGGLE:
  13057. ui_companion_driver_toggle(settings, p_rarch, true);
  13058. break;
  13059. case CMD_EVENT_GAME_FOCUS_TOGGLE:
  13060. {
  13061. bool video_fullscreen =
  13062. settings->bools.video_fullscreen || p_rarch->rarch_force_fullscreen;
  13063. enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_TOGGLE;
  13064. bool current_enable_state = p_rarch->game_focus_state.enabled;
  13065. bool apply_update = false;
  13066. bool show_message = false;
  13067. if (data)
  13068. game_focus_cmd = *((enum input_game_focus_cmd_type*)data);
  13069. switch (game_focus_cmd)
  13070. {
  13071. case GAME_FOCUS_CMD_OFF:
  13072. /* Force game focus off */
  13073. p_rarch->game_focus_state.enabled = false;
  13074. if (p_rarch->game_focus_state.enabled != current_enable_state)
  13075. {
  13076. apply_update = true;
  13077. show_message = true;
  13078. }
  13079. break;
  13080. case GAME_FOCUS_CMD_ON:
  13081. /* Force game focus on */
  13082. p_rarch->game_focus_state.enabled = true;
  13083. if (p_rarch->game_focus_state.enabled != current_enable_state)
  13084. {
  13085. apply_update = true;
  13086. show_message = true;
  13087. }
  13088. break;
  13089. case GAME_FOCUS_CMD_TOGGLE:
  13090. /* Invert current game focus state */
  13091. p_rarch->game_focus_state.enabled = !p_rarch->game_focus_state.enabled;
  13092. #ifdef HAVE_MENU
  13093. /* If menu is currently active, disable
  13094. * 'toggle on' functionality */
  13095. if (p_rarch->menu_driver_alive)
  13096. p_rarch->game_focus_state.enabled = false;
  13097. #endif
  13098. if (p_rarch->game_focus_state.enabled != current_enable_state)
  13099. {
  13100. apply_update = true;
  13101. show_message = true;
  13102. }
  13103. break;
  13104. case GAME_FOCUS_CMD_REAPPLY:
  13105. /* Reapply current game focus state */
  13106. apply_update = true;
  13107. show_message = false;
  13108. break;
  13109. default:
  13110. break;
  13111. }
  13112. if (apply_update)
  13113. {
  13114. if (p_rarch->game_focus_state.enabled)
  13115. {
  13116. input_driver_grab_mouse(p_rarch);
  13117. video_driver_hide_mouse();
  13118. }
  13119. else if (!video_fullscreen)
  13120. {
  13121. input_driver_ungrab_mouse(p_rarch);
  13122. video_driver_show_mouse();
  13123. }
  13124. p_rarch->input_driver_block_hotkey = p_rarch->game_focus_state.enabled;
  13125. p_rarch->keyboard_mapping_blocked = p_rarch->game_focus_state.enabled;
  13126. if (show_message)
  13127. runloop_msg_queue_push(
  13128. p_rarch->game_focus_state.enabled ?
  13129. msg_hash_to_str(MSG_GAME_FOCUS_ON) :
  13130. msg_hash_to_str(MSG_GAME_FOCUS_OFF),
  13131. 1, 60, true,
  13132. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  13133. RARCH_LOG("[Input]: %s => %s\n",
  13134. "Game Focus",
  13135. p_rarch->game_focus_state.enabled ? "ON" : "OFF");
  13136. }
  13137. }
  13138. break;
  13139. case CMD_EVENT_VOLUME_UP:
  13140. command_event_set_volume(settings, p_rarch, 0.5f);
  13141. break;
  13142. case CMD_EVENT_VOLUME_DOWN:
  13143. command_event_set_volume(settings, p_rarch, -0.5f);
  13144. break;
  13145. case CMD_EVENT_MIXER_VOLUME_UP:
  13146. command_event_set_mixer_volume(settings, p_rarch, 0.5f);
  13147. break;
  13148. case CMD_EVENT_MIXER_VOLUME_DOWN:
  13149. command_event_set_mixer_volume(settings, p_rarch, -0.5f);
  13150. break;
  13151. case CMD_EVENT_SET_FRAME_LIMIT:
  13152. retroarch_set_frame_limit(p_rarch,
  13153. settings->floats.fastforward_ratio);
  13154. break;
  13155. case CMD_EVENT_DISCORD_INIT:
  13156. #ifdef HAVE_DISCORD
  13157. {
  13158. bool discord_enable = settings ? settings->bools.discord_enable : false;
  13159. const char *discord_app_id = settings ? settings->arrays.discord_app_id : NULL;
  13160. discord_state_t *discord_st = &p_rarch->discord_st;
  13161. if (!settings)
  13162. return false;
  13163. if (!discord_enable)
  13164. return false;
  13165. if (discord_st->ready)
  13166. return true;
  13167. discord_init(discord_st,
  13168. discord_app_id,
  13169. p_rarch->launch_arguments);
  13170. }
  13171. #endif
  13172. break;
  13173. case CMD_EVENT_DISCORD_UPDATE:
  13174. {
  13175. #ifdef HAVE_DISCORD
  13176. discord_state_t *discord_st = &p_rarch->discord_st;
  13177. if (!data || !discord_st->ready)
  13178. return false;
  13179. discord_userdata_t *userdata = (discord_userdata_t*)data;
  13180. if (discord_st->ready)
  13181. discord_update(userdata->status);
  13182. #endif
  13183. }
  13184. break;
  13185. case CMD_EVENT_AI_SERVICE_CALL:
  13186. {
  13187. #ifdef HAVE_TRANSLATE
  13188. unsigned ai_service_mode = settings->uints.ai_service_mode;
  13189. if (ai_service_mode == 1 && is_ai_service_speech_running())
  13190. {
  13191. ai_service_speech_stop();
  13192. #ifdef HAVE_ACCESSIBILITY
  13193. if (is_accessibility_enabled(p_rarch))
  13194. accessibility_speak_priority(p_rarch, "stopped.", 10);
  13195. #endif
  13196. }
  13197. #ifdef HAVE_ACCESSIBILITY
  13198. else if (is_accessibility_enabled(p_rarch) &&
  13199. ai_service_mode == 2 &&
  13200. is_narrator_running(p_rarch))
  13201. accessibility_speak_priority(p_rarch, "stopped.", 10);
  13202. #endif
  13203. else
  13204. {
  13205. bool paused = p_rarch->runloop_paused;
  13206. if (data)
  13207. paused = *((bool*)data);
  13208. if (p_rarch->ai_service_auto == 0 && !settings->bools.ai_service_pause)
  13209. p_rarch->ai_service_auto = 1;
  13210. if (p_rarch->ai_service_auto != 2)
  13211. RARCH_LOG("AI Service Called...\n");
  13212. run_translation_service(p_rarch->configuration_settings,
  13213. p_rarch, paused);
  13214. }
  13215. #endif
  13216. break;
  13217. }
  13218. case CMD_EVENT_NONE:
  13219. return false;
  13220. }
  13221. return true;
  13222. }
  13223. /* FRONTEND */
  13224. void retroarch_override_setting_set(
  13225. enum rarch_override_setting enum_idx, void *data)
  13226. {
  13227. struct rarch_state *p_rarch = &rarch_st;
  13228. switch (enum_idx)
  13229. {
  13230. case RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE:
  13231. {
  13232. unsigned *val = (unsigned*)data;
  13233. if (val)
  13234. {
  13235. unsigned bit = *val;
  13236. BIT256_SET(p_rarch->has_set_libretro_device, bit);
  13237. }
  13238. }
  13239. break;
  13240. case RARCH_OVERRIDE_SETTING_VERBOSITY:
  13241. p_rarch->has_set_verbosity = true;
  13242. break;
  13243. case RARCH_OVERRIDE_SETTING_LIBRETRO:
  13244. p_rarch->has_set_libretro = true;
  13245. break;
  13246. case RARCH_OVERRIDE_SETTING_LIBRETRO_DIRECTORY:
  13247. p_rarch->has_set_libretro_directory = true;
  13248. break;
  13249. case RARCH_OVERRIDE_SETTING_SAVE_PATH:
  13250. p_rarch->has_set_save_path = true;
  13251. break;
  13252. case RARCH_OVERRIDE_SETTING_STATE_PATH:
  13253. p_rarch->has_set_state_path = true;
  13254. break;
  13255. #ifdef HAVE_NETWORKING
  13256. case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
  13257. p_rarch->has_set_netplay_mode = true;
  13258. break;
  13259. case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
  13260. p_rarch->has_set_netplay_ip_address = true;
  13261. break;
  13262. case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
  13263. p_rarch->has_set_netplay_ip_port = true;
  13264. break;
  13265. case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
  13266. p_rarch->has_set_netplay_stateless_mode = true;
  13267. break;
  13268. case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
  13269. p_rarch->has_set_netplay_check_frames = true;
  13270. break;
  13271. #endif
  13272. case RARCH_OVERRIDE_SETTING_UPS_PREF:
  13273. #ifdef HAVE_PATCH
  13274. p_rarch->has_set_ups_pref = true;
  13275. #endif
  13276. break;
  13277. case RARCH_OVERRIDE_SETTING_BPS_PREF:
  13278. #ifdef HAVE_PATCH
  13279. p_rarch->has_set_bps_pref = true;
  13280. #endif
  13281. break;
  13282. case RARCH_OVERRIDE_SETTING_IPS_PREF:
  13283. #ifdef HAVE_PATCH
  13284. p_rarch->has_set_ips_pref = true;
  13285. #endif
  13286. break;
  13287. case RARCH_OVERRIDE_SETTING_LOG_TO_FILE:
  13288. p_rarch->has_set_log_to_file = true;
  13289. break;
  13290. case RARCH_OVERRIDE_SETTING_NONE:
  13291. default:
  13292. break;
  13293. }
  13294. }
  13295. void retroarch_override_setting_unset(
  13296. enum rarch_override_setting enum_idx, void *data)
  13297. {
  13298. struct rarch_state *p_rarch = &rarch_st;
  13299. switch (enum_idx)
  13300. {
  13301. case RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE:
  13302. {
  13303. unsigned *val = (unsigned*)data;
  13304. if (val)
  13305. {
  13306. unsigned bit = *val;
  13307. BIT256_CLEAR(p_rarch->has_set_libretro_device, bit);
  13308. }
  13309. }
  13310. break;
  13311. case RARCH_OVERRIDE_SETTING_VERBOSITY:
  13312. p_rarch->has_set_verbosity = false;
  13313. break;
  13314. case RARCH_OVERRIDE_SETTING_LIBRETRO:
  13315. p_rarch->has_set_libretro = false;
  13316. break;
  13317. case RARCH_OVERRIDE_SETTING_LIBRETRO_DIRECTORY:
  13318. p_rarch->has_set_libretro_directory = false;
  13319. break;
  13320. case RARCH_OVERRIDE_SETTING_SAVE_PATH:
  13321. p_rarch->has_set_save_path = false;
  13322. break;
  13323. case RARCH_OVERRIDE_SETTING_STATE_PATH:
  13324. p_rarch->has_set_state_path = false;
  13325. break;
  13326. #ifdef HAVE_NETWORKING
  13327. case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
  13328. p_rarch->has_set_netplay_mode = false;
  13329. break;
  13330. case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
  13331. p_rarch->has_set_netplay_ip_address = false;
  13332. break;
  13333. case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
  13334. p_rarch->has_set_netplay_ip_port = false;
  13335. break;
  13336. case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
  13337. p_rarch->has_set_netplay_stateless_mode = false;
  13338. break;
  13339. case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
  13340. p_rarch->has_set_netplay_check_frames = false;
  13341. break;
  13342. #endif
  13343. case RARCH_OVERRIDE_SETTING_UPS_PREF:
  13344. #ifdef HAVE_PATCH
  13345. p_rarch->has_set_ups_pref = false;
  13346. #endif
  13347. break;
  13348. case RARCH_OVERRIDE_SETTING_BPS_PREF:
  13349. #ifdef HAVE_PATCH
  13350. p_rarch->has_set_bps_pref = false;
  13351. #endif
  13352. break;
  13353. case RARCH_OVERRIDE_SETTING_IPS_PREF:
  13354. #ifdef HAVE_PATCH
  13355. p_rarch->has_set_ips_pref = false;
  13356. #endif
  13357. break;
  13358. case RARCH_OVERRIDE_SETTING_LOG_TO_FILE:
  13359. p_rarch->has_set_log_to_file = false;
  13360. break;
  13361. case RARCH_OVERRIDE_SETTING_NONE:
  13362. default:
  13363. break;
  13364. }
  13365. }
  13366. static void retroarch_override_setting_free_state(void)
  13367. {
  13368. unsigned i;
  13369. for (i = 0; i < RARCH_OVERRIDE_SETTING_LAST; i++)
  13370. {
  13371. if (i == RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE)
  13372. {
  13373. unsigned j;
  13374. for (j = 0; j < MAX_USERS; j++)
  13375. retroarch_override_setting_unset(
  13376. (enum rarch_override_setting)(i), &j);
  13377. }
  13378. else
  13379. retroarch_override_setting_unset(
  13380. (enum rarch_override_setting)(i), NULL);
  13381. }
  13382. }
  13383. static void global_free(struct rarch_state *p_rarch)
  13384. {
  13385. global_t *global = NULL;
  13386. content_deinit();
  13387. path_deinit_subsystem(p_rarch);
  13388. command_event(CMD_EVENT_RECORD_DEINIT, NULL);
  13389. command_event(CMD_EVENT_LOG_FILE_DEINIT, NULL);
  13390. p_rarch->rarch_is_sram_load_disabled = false;
  13391. p_rarch->rarch_is_sram_save_disabled = false;
  13392. p_rarch->rarch_use_sram = false;
  13393. #ifdef HAVE_PATCH
  13394. rarch_ctl(RARCH_CTL_UNSET_BPS_PREF, NULL);
  13395. rarch_ctl(RARCH_CTL_UNSET_IPS_PREF, NULL);
  13396. rarch_ctl(RARCH_CTL_UNSET_UPS_PREF, NULL);
  13397. p_rarch->rarch_patch_blocked = false;
  13398. #endif
  13399. #ifdef HAVE_CONFIGFILE
  13400. p_rarch->rarch_block_config_read = false;
  13401. p_rarch->runloop_overrides_active = false;
  13402. p_rarch->runloop_remaps_core_active = false;
  13403. p_rarch->runloop_remaps_game_active = false;
  13404. p_rarch->runloop_remaps_content_dir_active = false;
  13405. #endif
  13406. p_rarch->current_core.has_set_input_descriptors = false;
  13407. p_rarch->current_core.has_set_subsystems = false;
  13408. global = &p_rarch->g_extern;
  13409. path_clear_all();
  13410. dir_clear_all();
  13411. if (global)
  13412. {
  13413. if (!string_is_empty(global->name.remapfile))
  13414. free(global->name.remapfile);
  13415. memset(global, 0, sizeof(struct global));
  13416. }
  13417. retroarch_override_setting_free_state();
  13418. }
  13419. /**
  13420. * main_exit:
  13421. *
  13422. * Cleanly exit RetroArch.
  13423. *
  13424. * Also saves configuration files to disk,
  13425. * and (optionally) autosave state.
  13426. **/
  13427. void main_exit(void *args)
  13428. {
  13429. struct rarch_state *p_rarch = &rarch_st;
  13430. #ifdef HAVE_MENU
  13431. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  13432. #endif
  13433. settings_t *settings = p_rarch->configuration_settings;
  13434. bool config_save_on_exit = settings->bools.config_save_on_exit;
  13435. video_driver_restore_cached(p_rarch, settings);
  13436. if (config_save_on_exit)
  13437. command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
  13438. #if defined(HAVE_GFX_WIDGETS)
  13439. /* Do not want display widgets to live any more. */
  13440. p_rarch->widgets_persisting = false;
  13441. #endif
  13442. #ifdef HAVE_MENU
  13443. /* Do not want menu context to live any more. */
  13444. if (menu_st)
  13445. menu_st->data_own = false;
  13446. #endif
  13447. rarch_ctl(RARCH_CTL_MAIN_DEINIT, NULL);
  13448. if (p_rarch->runloop_perfcnt_enable)
  13449. {
  13450. RARCH_LOG("[PERF]: Performance counters (RetroArch):\n");
  13451. log_counters(p_rarch->perf_counters_rarch, p_rarch->perf_ptr_rarch);
  13452. }
  13453. #if defined(HAVE_LOGGER) && !defined(ANDROID)
  13454. logger_shutdown();
  13455. #endif
  13456. frontend_driver_deinit(args);
  13457. frontend_driver_exitspawn(
  13458. path_get_ptr(RARCH_PATH_CORE),
  13459. path_get_realsize(RARCH_PATH_CORE),
  13460. p_rarch->launch_arguments);
  13461. p_rarch->has_set_username = false;
  13462. p_rarch->rarch_is_inited = false;
  13463. p_rarch->rarch_error_on_init = false;
  13464. #ifdef HAVE_CONFIGFILE
  13465. p_rarch->rarch_block_config_read = false;
  13466. #endif
  13467. retroarch_msg_queue_deinit(p_rarch);
  13468. driver_uninit(p_rarch, DRIVERS_CMD_ALL);
  13469. command_event(CMD_EVENT_LOG_FILE_DEINIT, NULL);
  13470. rarch_ctl(RARCH_CTL_STATE_FREE, NULL);
  13471. global_free(p_rarch);
  13472. task_queue_deinit();
  13473. if (p_rarch->configuration_settings)
  13474. free(p_rarch->configuration_settings);
  13475. p_rarch->configuration_settings = NULL;
  13476. ui_companion_driver_deinit(p_rarch);
  13477. frontend_driver_shutdown(false);
  13478. retroarch_deinit_drivers(p_rarch, &p_rarch->retro_ctx);
  13479. ui_companion_driver_free();
  13480. frontend_driver_free();
  13481. rtime_deinit();
  13482. #if defined(ANDROID)
  13483. play_feature_delivery_deinit();
  13484. #endif
  13485. #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
  13486. CoUninitialize();
  13487. #endif
  13488. }
  13489. /**
  13490. * main_entry:
  13491. *
  13492. * Main function of RetroArch.
  13493. *
  13494. * If HAVE_MAIN is not defined, will contain main loop and will not
  13495. * be exited from until we exit the program. Otherwise, will
  13496. * just do initialization.
  13497. *
  13498. * Returns: varies per platform.
  13499. **/
  13500. int rarch_main(int argc, char *argv[], void *data)
  13501. {
  13502. struct rarch_state *p_rarch = &rarch_st;
  13503. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  13504. p_rarch->shader_presets_need_reload = true;
  13505. #endif
  13506. #ifdef HAVE_RUNAHEAD
  13507. p_rarch->runahead_video_driver_is_active = true;
  13508. p_rarch->runahead_available = true;
  13509. p_rarch->runahead_secondary_core_available = true;
  13510. p_rarch->runahead_force_input_dirty = true;
  13511. #endif
  13512. #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
  13513. if (FAILED(CoInitialize(NULL)))
  13514. {
  13515. RARCH_ERR("FATAL: Failed to initialize the COM interface\n");
  13516. return 1;
  13517. }
  13518. #endif
  13519. rtime_init();
  13520. #if defined(ANDROID)
  13521. play_feature_delivery_init();
  13522. #endif
  13523. libretro_free_system_info(&p_rarch->runloop_system.info);
  13524. command_event(CMD_EVENT_HISTORY_DEINIT, NULL);
  13525. rarch_favorites_deinit();
  13526. p_rarch->configuration_settings = (settings_t*)calloc(1, sizeof(settings_t));
  13527. retroarch_deinit_drivers(p_rarch, &p_rarch->retro_ctx);
  13528. rarch_ctl(RARCH_CTL_STATE_FREE, NULL);
  13529. global_free(p_rarch);
  13530. frontend_driver_init_first(data);
  13531. if (p_rarch->rarch_is_inited)
  13532. driver_uninit(p_rarch, DRIVERS_CMD_ALL);
  13533. #ifdef HAVE_THREAD_STORAGE
  13534. sthread_tls_create(&p_rarch->rarch_tls);
  13535. sthread_tls_set(&p_rarch->rarch_tls, MAGIC_POINTER);
  13536. #endif
  13537. p_rarch->video_driver_active = true;
  13538. p_rarch->audio_driver_active = true;
  13539. {
  13540. uint8_t i;
  13541. for (i = 0; i < MAX_USERS; i++)
  13542. input_config_set_device(i, RETRO_DEVICE_JOYPAD);
  13543. }
  13544. retroarch_msg_queue_init(p_rarch);
  13545. if (frontend_driver_is_inited())
  13546. {
  13547. content_ctx_info_t info;
  13548. info.argc = argc;
  13549. info.argv = argv;
  13550. info.args = data;
  13551. info.environ_get = frontend_driver_environment_get_ptr();
  13552. if (!task_push_load_content_from_cli(
  13553. NULL,
  13554. NULL,
  13555. &info,
  13556. CORE_TYPE_PLAIN,
  13557. NULL,
  13558. NULL))
  13559. return 1;
  13560. }
  13561. ui_companion_driver_init_first(p_rarch->configuration_settings,
  13562. p_rarch);
  13563. #if !defined(HAVE_MAIN) || defined(HAVE_QT)
  13564. for (;;)
  13565. {
  13566. int ret;
  13567. bool app_exit = false;
  13568. #ifdef HAVE_QT
  13569. ui_companion_qt.application->process_events();
  13570. #endif
  13571. ret = runloop_iterate();
  13572. task_queue_check();
  13573. #ifdef HAVE_QT
  13574. app_exit = ui_companion_qt.application->exiting;
  13575. #endif
  13576. if (ret == -1 || app_exit)
  13577. {
  13578. #ifdef HAVE_QT
  13579. ui_companion_qt.application->quit();
  13580. #endif
  13581. break;
  13582. }
  13583. }
  13584. main_exit(data);
  13585. #endif
  13586. return 0;
  13587. }
  13588. #if defined(EMSCRIPTEN)
  13589. void RWebAudioRecalibrateTime(void);
  13590. void emscripten_mainloop(void)
  13591. {
  13592. int ret;
  13593. static unsigned emscripten_frame_count = 0;
  13594. struct rarch_state *p_rarch = &rarch_st;
  13595. settings_t *settings = p_rarch->configuration_settings;
  13596. bool black_frame_insertion = settings->uints.video_black_frame_insertion;
  13597. bool input_driver_nonblock_state = p_rarch->input_driver_nonblock_state;
  13598. bool runloop_is_slowmotion = p_rarch->runloop_slowmotion;
  13599. bool runloop_is_paused = p_rarch->runloop_paused;
  13600. RWebAudioRecalibrateTime();
  13601. emscripten_frame_count++;
  13602. /* Disable BFI during fast forward, slow-motion,
  13603. * and pause to prevent flicker. */
  13604. if (
  13605. black_frame_insertion
  13606. && !input_driver_nonblock_state
  13607. && !runloop_is_slowmotion
  13608. && !runloop_is_paused)
  13609. {
  13610. if ((emscripten_frame_count % (black_frame_insertion+1)) != 0)
  13611. {
  13612. glClear(GL_COLOR_BUFFER_BIT);
  13613. if (p_rarch->current_video_context.swap_buffers)
  13614. p_rarch->current_video_context.swap_buffers(
  13615. p_rarch->video_context_data);
  13616. return;
  13617. }
  13618. }
  13619. ret = runloop_iterate();
  13620. task_queue_check();
  13621. if (ret != -1)
  13622. return;
  13623. main_exit(NULL);
  13624. emscripten_force_exit(0);
  13625. }
  13626. #endif
  13627. #ifndef HAVE_MAIN
  13628. #ifdef __cplusplus
  13629. extern "C"
  13630. #endif
  13631. int main(int argc, char *argv[])
  13632. {
  13633. return rarch_main(argc, argv, NULL);
  13634. }
  13635. #endif
  13636. /* CORE OPTIONS */
  13637. static const char *core_option_manager_parse_value_label(
  13638. const char *value, const char *value_label)
  13639. {
  13640. /* 'value_label' may be NULL */
  13641. const char *label = string_is_empty(value_label) ?
  13642. value : value_label;
  13643. if (string_is_empty(label))
  13644. return NULL;
  13645. /* Any label starting with a digit (or +/-)
  13646. * cannot be a boolean string, and requires
  13647. * no further processing */
  13648. if (ISDIGIT((unsigned char)*label) ||
  13649. (*label == '+') ||
  13650. (*label == '-'))
  13651. return label;
  13652. /* Core devs have a habit of using arbitrary
  13653. * strings to label boolean values (i.e. enabled,
  13654. * Enabled, on, On, ON, true, True, TRUE, disabled,
  13655. * Disabled, off, Off, OFF, false, False, FALSE).
  13656. * These should all be converted to standard ON/OFF
  13657. * strings
  13658. * > Note: We require some duplication here
  13659. * (e.g. MENU_ENUM_LABEL_ENABLED *and*
  13660. * MENU_ENUM_LABEL_VALUE_ENABLED) in order
  13661. * to match both localised and non-localised
  13662. * strings. This function is not performance
  13663. * critical, so these extra comparisons do
  13664. * no harm */
  13665. if (string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)) ||
  13666. string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ENABLED)) ||
  13667. string_is_equal_noncase(label, "enable") ||
  13668. string_is_equal_noncase(label, "on") ||
  13669. string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON)) ||
  13670. string_is_equal_noncase(label, "true") ||
  13671. string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_TRUE)))
  13672. label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON);
  13673. else if (string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) ||
  13674. string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISABLED)) ||
  13675. string_is_equal_noncase(label, "disable") ||
  13676. string_is_equal_noncase(label, "off") ||
  13677. string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)) ||
  13678. string_is_equal_noncase(label, "false") ||
  13679. string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FALSE)))
  13680. label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
  13681. return label;
  13682. }
  13683. static bool core_option_manager_parse_variable(
  13684. core_option_manager_t *opt, size_t idx,
  13685. const struct retro_variable *var,
  13686. config_file_t *config_src)
  13687. {
  13688. size_t i;
  13689. union string_list_elem_attr attr;
  13690. const char *val_start = NULL;
  13691. char *value = NULL;
  13692. char *desc_end = NULL;
  13693. struct core_option *option = (struct core_option*)&opt->opts[idx];
  13694. struct config_entry_list
  13695. *entry = NULL;
  13696. /* All options are visible by default */
  13697. option->visible = true;
  13698. if (!string_is_empty(var->key))
  13699. option->key = strdup(var->key);
  13700. if (!string_is_empty(var->value))
  13701. value = strdup(var->value);
  13702. if (!string_is_empty(value))
  13703. desc_end = strstr(value, "; ");
  13704. if (!desc_end)
  13705. goto error;
  13706. *desc_end = '\0';
  13707. if (!string_is_empty(value))
  13708. option->desc = strdup(value);
  13709. val_start = desc_end + 2;
  13710. option->vals = string_split(val_start, "|");
  13711. if (!option->vals)
  13712. goto error;
  13713. /* Legacy core option interface has no concept
  13714. * of value labels
  13715. * > Use actual values for display purposes */
  13716. attr.i = 0;
  13717. option->val_labels = string_list_new();
  13718. if (!option->val_labels)
  13719. goto error;
  13720. /* > Loop over values and 'extract' labels */
  13721. for (i = 0; i < option->vals->size; i++)
  13722. {
  13723. const char *value = option->vals->elems[i].data;
  13724. const char *value_label = core_option_manager_parse_value_label(
  13725. value, NULL);
  13726. /* Redundant safely check... */
  13727. value_label = string_is_empty(value_label) ?
  13728. value : value_label;
  13729. /* Append value label string */
  13730. string_list_append(option->val_labels, value_label, attr);
  13731. }
  13732. /* Legacy core option interface always uses first
  13733. * defined value as the default */
  13734. option->default_index = 0;
  13735. option->index = 0;
  13736. if (config_src)
  13737. entry = config_get_entry(config_src, option->key);
  13738. else
  13739. entry = config_get_entry(opt->conf, option->key);
  13740. /* Set current config value */
  13741. if (entry && !string_is_empty(entry->value))
  13742. {
  13743. for (i = 0; i < option->vals->size; i++)
  13744. {
  13745. if (string_is_equal(option->vals->elems[i].data, entry->value))
  13746. {
  13747. option->index = i;
  13748. break;
  13749. }
  13750. }
  13751. }
  13752. free(value);
  13753. return true;
  13754. error:
  13755. free(value);
  13756. return false;
  13757. }
  13758. static bool core_option_manager_parse_option(
  13759. core_option_manager_t *opt, size_t idx,
  13760. const struct retro_core_option_definition *option_def,
  13761. config_file_t *config_src)
  13762. {
  13763. size_t i;
  13764. union string_list_elem_attr attr;
  13765. struct config_entry_list
  13766. *entry = NULL;
  13767. size_t num_vals = 0;
  13768. struct core_option *option = (struct core_option*)&opt->opts[idx];
  13769. const struct retro_core_option_value
  13770. *values = option_def->values;
  13771. /* All options are visible by default */
  13772. option->visible = true;
  13773. if (!string_is_empty(option_def->key))
  13774. option->key = strdup(option_def->key);
  13775. if (!string_is_empty(option_def->desc))
  13776. option->desc = strdup(option_def->desc);
  13777. if (!string_is_empty(option_def->info))
  13778. option->info = strdup(option_def->info);
  13779. /* Get number of values */
  13780. for (;;)
  13781. {
  13782. if (string_is_empty(values[num_vals].value))
  13783. break;
  13784. num_vals++;
  13785. }
  13786. if (num_vals < 1)
  13787. return false;
  13788. /* Initialise string lists */
  13789. attr.i = 0;
  13790. option->vals = string_list_new();
  13791. option->val_labels = string_list_new();
  13792. if (!option->vals || !option->val_labels)
  13793. return false;
  13794. /* Initialise default value */
  13795. option->default_index = 0;
  13796. option->index = 0;
  13797. /* Extract value/label pairs */
  13798. for (i = 0; i < num_vals; i++)
  13799. {
  13800. const char *value = values[i].value;
  13801. const char *value_label = values[i].label;
  13802. /* Append value string
  13803. * > We know that 'value' is always valid */
  13804. string_list_append(option->vals, value, attr);
  13805. /* Value label requires additional processing */
  13806. value_label = core_option_manager_parse_value_label(
  13807. value, value_label);
  13808. /* > Redundant safely check... */
  13809. value_label = string_is_empty(value_label) ?
  13810. value : value_label;
  13811. /* Append value label string */
  13812. string_list_append(option->val_labels, value_label, attr);
  13813. /* Check whether this value is the default setting */
  13814. if (!string_is_empty(option_def->default_value))
  13815. {
  13816. if (string_is_equal(option_def->default_value, value))
  13817. {
  13818. option->default_index = i;
  13819. option->index = i;
  13820. }
  13821. }
  13822. }
  13823. if (config_src)
  13824. entry = config_get_entry(config_src, option->key);
  13825. else
  13826. entry = config_get_entry(opt->conf, option->key);
  13827. /* Set current config value */
  13828. if (entry && !string_is_empty(entry->value))
  13829. {
  13830. for (i = 0; i < option->vals->size; i++)
  13831. {
  13832. if (string_is_equal(option->vals->elems[i].data, entry->value))
  13833. {
  13834. option->index = i;
  13835. break;
  13836. }
  13837. }
  13838. }
  13839. return true;
  13840. }
  13841. /**
  13842. * core_option_manager_free:
  13843. * @opt : options manager handle
  13844. *
  13845. * Frees core option manager handle.
  13846. **/
  13847. static void core_option_manager_free(core_option_manager_t *opt)
  13848. {
  13849. size_t i;
  13850. if (!opt)
  13851. return;
  13852. for (i = 0; i < opt->size; i++)
  13853. {
  13854. if (opt->opts[i].desc)
  13855. free(opt->opts[i].desc);
  13856. if (opt->opts[i].info)
  13857. free(opt->opts[i].info);
  13858. if (opt->opts[i].key)
  13859. free(opt->opts[i].key);
  13860. if (opt->opts[i].vals)
  13861. string_list_free(opt->opts[i].vals);
  13862. if (opt->opts[i].val_labels)
  13863. string_list_free(opt->opts[i].val_labels);
  13864. opt->opts[i].desc = NULL;
  13865. opt->opts[i].info = NULL;
  13866. opt->opts[i].key = NULL;
  13867. opt->opts[i].vals = NULL;
  13868. }
  13869. if (opt->conf)
  13870. config_file_free(opt->conf);
  13871. free(opt->opts);
  13872. free(opt);
  13873. }
  13874. /**
  13875. * core_option_manager_new_vars:
  13876. * @conf_path : Filesystem path to write core option config file to.
  13877. * @src_conf_path : Filesystem path from which to load initial config settings.
  13878. * @vars : Pointer to variable array handle.
  13879. *
  13880. * Legacy version of core_option_manager_new().
  13881. * Creates and initializes a core manager handle.
  13882. *
  13883. * Returns: handle to new core manager handle, otherwise NULL.
  13884. **/
  13885. static core_option_manager_t *core_option_manager_new_vars(
  13886. const char *conf_path, const char *src_conf_path,
  13887. const struct retro_variable *vars)
  13888. {
  13889. const struct retro_variable *var;
  13890. size_t size = 0;
  13891. config_file_t *config_src = NULL;
  13892. core_option_manager_t *opt = (core_option_manager_t*)
  13893. malloc(sizeof(*opt));
  13894. if (!opt)
  13895. return NULL;
  13896. opt->conf = NULL;
  13897. opt->conf_path[0] = '\0';
  13898. opt->opts = NULL;
  13899. opt->size = 0;
  13900. opt->updated = false;
  13901. if (!string_is_empty(conf_path))
  13902. if (!(opt->conf = config_file_new_from_path_to_string(conf_path)))
  13903. if (!(opt->conf = config_file_new_alloc()))
  13904. goto error;
  13905. strlcpy(opt->conf_path, conf_path, sizeof(opt->conf_path));
  13906. /* Load source config file, if required */
  13907. if (!string_is_empty(src_conf_path))
  13908. config_src = config_file_new_from_path_to_string(src_conf_path);
  13909. for (var = vars; var->key && var->value; var++)
  13910. size++;
  13911. if (size == 0)
  13912. goto error;
  13913. opt->opts = (struct core_option*)calloc(size, sizeof(*opt->opts));
  13914. if (!opt->opts)
  13915. goto error;
  13916. opt->size = size;
  13917. size = 0;
  13918. for (var = vars; var->key && var->value; size++, var++)
  13919. {
  13920. if (!core_option_manager_parse_variable(opt, size, var, config_src))
  13921. goto error;
  13922. }
  13923. if (config_src)
  13924. config_file_free(config_src);
  13925. return opt;
  13926. error:
  13927. if (config_src)
  13928. config_file_free(config_src);
  13929. core_option_manager_free(opt);
  13930. return NULL;
  13931. }
  13932. /**
  13933. * core_option_manager_new:
  13934. * @conf_path : Filesystem path to write core option config file to.
  13935. * @src_conf_path : Filesystem path from which to load initial config settings.
  13936. * @option_defs : Pointer to variable array handle.
  13937. *
  13938. * Creates and initializes a core manager handle.
  13939. *
  13940. * Returns: handle to new core manager handle, otherwise NULL.
  13941. **/
  13942. static core_option_manager_t *core_option_manager_new(
  13943. const char *conf_path, const char *src_conf_path,
  13944. const struct retro_core_option_definition *option_defs)
  13945. {
  13946. const struct retro_core_option_definition *option_def;
  13947. size_t size = 0;
  13948. config_file_t *config_src = NULL;
  13949. core_option_manager_t *opt = (core_option_manager_t*)
  13950. malloc(sizeof(*opt));
  13951. if (!opt)
  13952. return NULL;
  13953. opt->conf = NULL;
  13954. opt->conf_path[0] = '\0';
  13955. opt->opts = NULL;
  13956. opt->size = 0;
  13957. opt->updated = false;
  13958. if (!string_is_empty(conf_path))
  13959. if (!(opt->conf = config_file_new_from_path_to_string(conf_path)))
  13960. if (!(opt->conf = config_file_new_alloc()))
  13961. goto error;
  13962. strlcpy(opt->conf_path, conf_path, sizeof(opt->conf_path));
  13963. /* Load source config file, if required */
  13964. if (!string_is_empty(src_conf_path))
  13965. config_src = config_file_new_from_path_to_string(src_conf_path);
  13966. /* Note: 'option_def->info == NULL' is valid */
  13967. for (option_def = option_defs;
  13968. option_def->key && option_def->desc && option_def->values[0].value;
  13969. option_def++)
  13970. size++;
  13971. if (size == 0)
  13972. goto error;
  13973. opt->opts = (struct core_option*)calloc(size, sizeof(*opt->opts));
  13974. if (!opt->opts)
  13975. goto error;
  13976. opt->size = size;
  13977. size = 0;
  13978. /* Note: 'option_def->info == NULL' is valid */
  13979. for (option_def = option_defs;
  13980. option_def->key && option_def->desc && option_def->values[0].value;
  13981. size++, option_def++)
  13982. if (!core_option_manager_parse_option(opt, size, option_def, config_src))
  13983. goto error;
  13984. if (config_src)
  13985. config_file_free(config_src);
  13986. return opt;
  13987. error:
  13988. if (config_src)
  13989. config_file_free(config_src);
  13990. core_option_manager_free(opt);
  13991. return NULL;
  13992. }
  13993. /**
  13994. * core_option_manager_flush:
  13995. * @opt : options manager handle
  13996. *
  13997. * Writes core option key-pair values to file.
  13998. **/
  13999. static void core_option_manager_flush(
  14000. config_file_t *conf,
  14001. core_option_manager_t *opt)
  14002. {
  14003. size_t i;
  14004. for (i = 0; i < opt->size; i++)
  14005. {
  14006. struct core_option *option = (struct core_option*)&opt->opts[i];
  14007. if (option)
  14008. config_set_string(conf, option->key,
  14009. opt->opts[i].vals->elems[opt->opts[i].index].data);
  14010. }
  14011. }
  14012. /**
  14013. * core_option_manager_get_desc:
  14014. * @opt : options manager handle
  14015. * @index : index identifier of the option
  14016. *
  14017. * Gets description for an option.
  14018. *
  14019. * Returns: Description for an option.
  14020. **/
  14021. const char *core_option_manager_get_desc(
  14022. core_option_manager_t *opt, size_t idx)
  14023. {
  14024. if (!opt)
  14025. return NULL;
  14026. if (idx >= opt->size)
  14027. return NULL;
  14028. return opt->opts[idx].desc;
  14029. }
  14030. /**
  14031. * core_option_manager_get_info:
  14032. * @opt : options manager handle
  14033. * @idx : idx identifier of the option
  14034. *
  14035. * Gets information text for an option.
  14036. *
  14037. * Returns: Information text for an option.
  14038. **/
  14039. const char *core_option_manager_get_info(
  14040. core_option_manager_t *opt, size_t idx)
  14041. {
  14042. if (!opt)
  14043. return NULL;
  14044. if (idx >= opt->size)
  14045. return NULL;
  14046. return opt->opts[idx].info;
  14047. }
  14048. /**
  14049. * core_option_manager_get_val:
  14050. * @opt : options manager handle
  14051. * @index : index identifier of the option
  14052. *
  14053. * Gets value for an option.
  14054. *
  14055. * Returns: Value for an option.
  14056. **/
  14057. const char *core_option_manager_get_val(core_option_manager_t *opt, size_t idx)
  14058. {
  14059. struct core_option *option = NULL;
  14060. if (!opt)
  14061. return NULL;
  14062. if (idx >= opt->size)
  14063. return NULL;
  14064. option = (struct core_option*)&opt->opts[idx];
  14065. return option->vals->elems[option->index].data;
  14066. }
  14067. /**
  14068. * core_option_manager_get_val_label:
  14069. * @opt : options manager handle
  14070. * @idx : idx identifier of the option
  14071. *
  14072. * Gets value label for an option.
  14073. *
  14074. * Returns: Value label for an option.
  14075. **/
  14076. const char *core_option_manager_get_val_label(core_option_manager_t *opt, size_t idx)
  14077. {
  14078. struct core_option *option = NULL;
  14079. if (!opt)
  14080. return NULL;
  14081. if (idx >= opt->size)
  14082. return NULL;
  14083. option = (struct core_option*)&opt->opts[idx];
  14084. return option->val_labels->elems[option->index].data;
  14085. }
  14086. /**
  14087. * core_option_manager_get_visible:
  14088. * @opt : options manager handle
  14089. * @idx : idx identifier of the option
  14090. *
  14091. * Gets whether option should be visible when displaying
  14092. * core options in the frontend
  14093. *
  14094. * Returns: 'true' if option should be displayed by the frontend.
  14095. **/
  14096. bool core_option_manager_get_visible(core_option_manager_t *opt,
  14097. size_t idx)
  14098. {
  14099. if (!opt)
  14100. return false;
  14101. if (idx >= opt->size)
  14102. return false;
  14103. return opt->opts[idx].visible;
  14104. }
  14105. void core_option_manager_set_val(core_option_manager_t *opt,
  14106. size_t idx, size_t val_idx)
  14107. {
  14108. struct core_option *option = NULL;
  14109. if (!opt)
  14110. return;
  14111. if (idx >= opt->size)
  14112. return;
  14113. option = (struct core_option*)&opt->opts[idx];
  14114. option->index = val_idx % option->vals->size;
  14115. opt->updated = true;
  14116. #ifdef HAVE_CHEEVOS
  14117. rcheevos_validate_config_settings();
  14118. #endif
  14119. }
  14120. static void core_option_manager_adjust_val(core_option_manager_t* opt,
  14121. size_t idx, int adjustment)
  14122. {
  14123. struct core_option* option = NULL;
  14124. if (!opt)
  14125. return;
  14126. if (idx >= opt->size)
  14127. return;
  14128. option = (struct core_option*)&opt->opts[idx];
  14129. option->index = (option->index + option->vals->size + adjustment) % option->vals->size;
  14130. opt->updated = true;
  14131. #ifdef HAVE_CHEEVOS
  14132. rcheevos_validate_config_settings();
  14133. #endif
  14134. }
  14135. /**
  14136. * core_option_manager_set_default:
  14137. * @opt : pointer to core option manager object.
  14138. * @idx : index of core option to be reset to defaults.
  14139. *
  14140. * Reset core option specified by @idx and sets default value for option.
  14141. **/
  14142. void core_option_manager_set_default(core_option_manager_t *opt, size_t idx)
  14143. {
  14144. if (!opt)
  14145. return;
  14146. if (idx >= opt->size)
  14147. return;
  14148. opt->opts[idx].index = opt->opts[idx].default_index;
  14149. opt->updated = true;
  14150. #ifdef HAVE_CHEEVOS
  14151. rcheevos_validate_config_settings();
  14152. #endif
  14153. }
  14154. static struct retro_core_option_definition *core_option_manager_get_definitions(
  14155. const struct retro_core_options_intl *core_options_intl)
  14156. {
  14157. size_t i;
  14158. size_t num_options = 0;
  14159. struct retro_core_option_definition *option_defs_us = NULL;
  14160. struct retro_core_option_definition *option_defs_local = NULL;
  14161. struct retro_core_option_definition *option_defs = NULL;
  14162. if (!core_options_intl)
  14163. return NULL;
  14164. option_defs_us = core_options_intl->us;
  14165. option_defs_local = core_options_intl->local;
  14166. if (!option_defs_us)
  14167. return NULL;
  14168. /* Determine number of options */
  14169. for (;;)
  14170. {
  14171. if (string_is_empty(option_defs_us[num_options].key))
  14172. break;
  14173. num_options++;
  14174. }
  14175. if (num_options < 1)
  14176. return NULL;
  14177. /* Allocate output option_defs array
  14178. * > One extra entry required for terminating NULL entry
  14179. * > Note that calloc() sets terminating NULL entry and
  14180. * correctly 'nullifies' each values array */
  14181. option_defs = (struct retro_core_option_definition *)calloc(
  14182. num_options + 1, sizeof(struct retro_core_option_definition));
  14183. if (!option_defs)
  14184. return NULL;
  14185. /* Loop through options... */
  14186. for (i = 0; i < num_options; i++)
  14187. {
  14188. size_t j;
  14189. size_t num_values = 0;
  14190. const char *key = option_defs_us[i].key;
  14191. const char *local_desc = NULL;
  14192. const char *local_info = NULL;
  14193. struct retro_core_option_value *local_values = NULL;
  14194. /* Key is always taken from us english defs */
  14195. option_defs[i].key = key;
  14196. /* Default value is always taken from us english defs */
  14197. option_defs[i].default_value = option_defs_us[i].default_value;
  14198. /* Try to find corresponding entry in local defs array */
  14199. if (option_defs_local)
  14200. {
  14201. size_t index = 0;
  14202. for (;;)
  14203. {
  14204. const char *local_key = option_defs_local[index].key;
  14205. if (string_is_empty(local_key))
  14206. break;
  14207. if (string_is_equal(key, local_key))
  14208. {
  14209. local_desc = option_defs_local[index].desc;
  14210. local_info = option_defs_local[index].info;
  14211. local_values = option_defs_local[index].values;
  14212. break;
  14213. }
  14214. index++;
  14215. }
  14216. }
  14217. /* Set desc and info strings */
  14218. option_defs[i].desc = string_is_empty(local_desc) ? option_defs_us[i].desc : local_desc;
  14219. option_defs[i].info = string_is_empty(local_info) ? option_defs_us[i].info : local_info;
  14220. /* Determine number of values
  14221. * (always taken from us english defs) */
  14222. for (;;)
  14223. {
  14224. if (string_is_empty(option_defs_us[i].values[num_values].value))
  14225. break;
  14226. num_values++;
  14227. }
  14228. /* Copy values */
  14229. for (j = 0; j < num_values; j++)
  14230. {
  14231. const char *value = option_defs_us[i].values[j].value;
  14232. const char *local_label = NULL;
  14233. /* Value string is always taken from us english defs */
  14234. option_defs[i].values[j].value = value;
  14235. /* Try to find corresponding entry in local defs values array */
  14236. if (local_values)
  14237. {
  14238. size_t value_index = 0;
  14239. for (;;)
  14240. {
  14241. const char *local_value = local_values[value_index].value;
  14242. if (string_is_empty(local_value))
  14243. break;
  14244. if (string_is_equal(value, local_value))
  14245. {
  14246. local_label = local_values[value_index].label;
  14247. break;
  14248. }
  14249. value_index++;
  14250. }
  14251. }
  14252. /* Set value label string */
  14253. option_defs[i].values[j].label = string_is_empty(local_label) ?
  14254. option_defs_us[i].values[j].label : local_label;
  14255. }
  14256. }
  14257. return option_defs;
  14258. }
  14259. static void core_option_manager_set_display(core_option_manager_t *opt,
  14260. const char *key, bool visible)
  14261. {
  14262. size_t i;
  14263. if (!opt || string_is_empty(key))
  14264. return;
  14265. for (i = 0; i < opt->size; i++)
  14266. {
  14267. if (string_is_empty(opt->opts[i].key))
  14268. continue;
  14269. if (string_is_equal(opt->opts[i].key, key))
  14270. {
  14271. opt->opts[i].visible = visible;
  14272. return;
  14273. }
  14274. }
  14275. }
  14276. /* DYNAMIC LIBRETRO CORE */
  14277. const struct retro_subsystem_info *libretro_find_subsystem_info(
  14278. const struct retro_subsystem_info *info, unsigned num_info,
  14279. const char *ident)
  14280. {
  14281. unsigned i;
  14282. for (i = 0; i < num_info; i++)
  14283. {
  14284. if (string_is_equal(info[i].ident, ident))
  14285. return &info[i];
  14286. else if (string_is_equal(info[i].desc, ident))
  14287. return &info[i];
  14288. }
  14289. return NULL;
  14290. }
  14291. /**
  14292. * libretro_find_controller_description:
  14293. * @info : Pointer to controller info handle.
  14294. * @id : Identifier of controller to search
  14295. * for.
  14296. *
  14297. * Search for a controller of type @id in @info.
  14298. *
  14299. * Returns: controller description of found controller on success,
  14300. * otherwise NULL.
  14301. **/
  14302. const struct retro_controller_description *
  14303. libretro_find_controller_description(
  14304. const struct retro_controller_info *info, unsigned id)
  14305. {
  14306. unsigned i;
  14307. for (i = 0; i < info->num_types; i++)
  14308. {
  14309. if (info->types[i].id != id)
  14310. continue;
  14311. return &info->types[i];
  14312. }
  14313. return NULL;
  14314. }
  14315. /**
  14316. * libretro_free_system_info:
  14317. * @info : Pointer to system info information.
  14318. *
  14319. * Frees system information.
  14320. **/
  14321. void libretro_free_system_info(struct retro_system_info *info)
  14322. {
  14323. if (!info)
  14324. return;
  14325. free((void*)info->library_name);
  14326. free((void*)info->library_version);
  14327. free((void*)info->valid_extensions);
  14328. memset(info, 0, sizeof(*info));
  14329. }
  14330. static bool environ_cb_get_system_info(unsigned cmd, void *data)
  14331. {
  14332. struct rarch_state *p_rarch = &rarch_st;
  14333. rarch_system_info_t *system = &p_rarch->runloop_system;
  14334. switch (cmd)
  14335. {
  14336. case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME:
  14337. *p_rarch->load_no_content_hook = *(const bool*)data;
  14338. break;
  14339. case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO:
  14340. {
  14341. unsigned i, j, size;
  14342. const struct retro_subsystem_info *info =
  14343. (const struct retro_subsystem_info*)data;
  14344. settings_t *settings = p_rarch->configuration_settings;
  14345. unsigned log_level = settings->uints.libretro_log_level;
  14346. subsystem_current_count = 0;
  14347. RARCH_LOG("[Environ]: SET_SUBSYSTEM_INFO.\n");
  14348. for (i = 0; info[i].ident; i++)
  14349. {
  14350. if (log_level != RETRO_LOG_DEBUG)
  14351. continue;
  14352. RARCH_LOG("Subsystem ID: %d\nSpecial game type: %s\n Ident: %s\n ID: %u\n Content:\n",
  14353. i,
  14354. info[i].desc,
  14355. info[i].ident,
  14356. info[i].id
  14357. );
  14358. for (j = 0; j < info[i].num_roms; j++)
  14359. {
  14360. RARCH_LOG(" %s (%s)\n",
  14361. info[i].roms[j].desc, info[i].roms[j].required ?
  14362. "required" : "optional");
  14363. }
  14364. }
  14365. size = i;
  14366. if (log_level == RETRO_LOG_DEBUG)
  14367. {
  14368. RARCH_LOG("Subsystems: %d\n", i);
  14369. if (size > SUBSYSTEM_MAX_SUBSYSTEMS)
  14370. RARCH_WARN("Subsystems exceed subsystem max, clamping to %d\n", SUBSYSTEM_MAX_SUBSYSTEMS);
  14371. }
  14372. if (system)
  14373. {
  14374. for (i = 0; i < size && i < SUBSYSTEM_MAX_SUBSYSTEMS; i++)
  14375. {
  14376. /* Nasty, but have to do it like this since
  14377. * the pointers are const char *
  14378. * (if we don't free them, we get a memory leak) */
  14379. if (!string_is_empty(subsystem_data[i].desc))
  14380. free((char *)subsystem_data[i].desc);
  14381. if (!string_is_empty(subsystem_data[i].ident))
  14382. free((char *)subsystem_data[i].ident);
  14383. subsystem_data[i].desc = strdup(info[i].desc);
  14384. subsystem_data[i].ident = strdup(info[i].ident);
  14385. subsystem_data[i].id = info[i].id;
  14386. subsystem_data[i].num_roms = info[i].num_roms;
  14387. if (log_level == RETRO_LOG_DEBUG)
  14388. if (subsystem_data[i].num_roms > SUBSYSTEM_MAX_SUBSYSTEM_ROMS)
  14389. RARCH_WARN("Subsystems exceed subsystem max roms, clamping to %d\n", SUBSYSTEM_MAX_SUBSYSTEM_ROMS);
  14390. for (j = 0; j < subsystem_data[i].num_roms && j < SUBSYSTEM_MAX_SUBSYSTEM_ROMS; j++)
  14391. {
  14392. /* Nasty, but have to do it like this since
  14393. * the pointers are const char *
  14394. * (if we don't free them, we get a memory leak) */
  14395. if (!string_is_empty(p_rarch->subsystem_data_roms[i][j].desc))
  14396. free((char *)p_rarch->subsystem_data_roms[i][j].desc);
  14397. if (!string_is_empty(p_rarch->subsystem_data_roms[i][j].valid_extensions))
  14398. free((char *)p_rarch->subsystem_data_roms[i][j].valid_extensions);
  14399. p_rarch->subsystem_data_roms[i][j].desc = strdup(info[i].roms[j].desc);
  14400. p_rarch->subsystem_data_roms[i][j].valid_extensions = strdup(info[i].roms[j].valid_extensions);
  14401. p_rarch->subsystem_data_roms[i][j].required = info[i].roms[j].required;
  14402. p_rarch->subsystem_data_roms[i][j].block_extract = info[i].roms[j].block_extract;
  14403. p_rarch->subsystem_data_roms[i][j].need_fullpath = info[i].roms[j].need_fullpath;
  14404. }
  14405. subsystem_data[i].roms = p_rarch->subsystem_data_roms[i];
  14406. }
  14407. subsystem_current_count =
  14408. size <= SUBSYSTEM_MAX_SUBSYSTEMS
  14409. ? size
  14410. : SUBSYSTEM_MAX_SUBSYSTEMS;
  14411. }
  14412. break;
  14413. }
  14414. default:
  14415. return false;
  14416. }
  14417. return true;
  14418. }
  14419. static bool dynamic_request_hw_context(enum retro_hw_context_type type,
  14420. unsigned minor, unsigned major)
  14421. {
  14422. switch (type)
  14423. {
  14424. case RETRO_HW_CONTEXT_NONE:
  14425. RARCH_LOG("Requesting no HW context.\n");
  14426. break;
  14427. case RETRO_HW_CONTEXT_VULKAN:
  14428. #ifdef HAVE_VULKAN
  14429. RARCH_LOG("Requesting Vulkan context.\n");
  14430. break;
  14431. #else
  14432. RARCH_ERR("Requesting Vulkan context, but RetroArch is not compiled against Vulkan. Cannot use HW context.\n");
  14433. return false;
  14434. #endif
  14435. #if defined(HAVE_OPENGLES)
  14436. #if (defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3))
  14437. case RETRO_HW_CONTEXT_OPENGLES2:
  14438. case RETRO_HW_CONTEXT_OPENGLES3:
  14439. RARCH_LOG("Requesting OpenGLES%u context.\n",
  14440. type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3);
  14441. break;
  14442. #if defined(HAVE_OPENGLES3)
  14443. case RETRO_HW_CONTEXT_OPENGLES_VERSION:
  14444. #ifndef HAVE_OPENGLES3_2
  14445. if (major == 3 && minor == 2)
  14446. {
  14447. RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch is compiled against a lesser version. Cannot use HW context.\n",
  14448. major, minor);
  14449. return false;
  14450. }
  14451. #endif
  14452. #if !defined(HAVE_OPENGLES3_2) && !defined(HAVE_OPENGLES3_1)
  14453. if (major == 3 && minor == 1)
  14454. {
  14455. RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch is compiled against a lesser version. Cannot use HW context.\n",
  14456. major, minor);
  14457. return false;
  14458. }
  14459. #endif
  14460. RARCH_LOG("Requesting OpenGLES%u.%u context.\n",
  14461. major, minor);
  14462. break;
  14463. #endif
  14464. #endif
  14465. case RETRO_HW_CONTEXT_OPENGL:
  14466. case RETRO_HW_CONTEXT_OPENGL_CORE:
  14467. RARCH_ERR("Requesting OpenGL context, but RetroArch "
  14468. "is compiled against OpenGLES. Cannot use HW context.\n");
  14469. return false;
  14470. #elif defined(HAVE_OPENGL) || defined(HAVE_OPENGL_CORE)
  14471. case RETRO_HW_CONTEXT_OPENGLES2:
  14472. case RETRO_HW_CONTEXT_OPENGLES3:
  14473. RARCH_ERR("Requesting OpenGLES%u context, but RetroArch "
  14474. "is compiled against OpenGL. Cannot use HW context.\n",
  14475. type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3);
  14476. return false;
  14477. case RETRO_HW_CONTEXT_OPENGLES_VERSION:
  14478. RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch "
  14479. "is compiled against OpenGL. Cannot use HW context.\n",
  14480. major, minor);
  14481. return false;
  14482. case RETRO_HW_CONTEXT_OPENGL:
  14483. RARCH_LOG("Requesting OpenGL context.\n");
  14484. break;
  14485. case RETRO_HW_CONTEXT_OPENGL_CORE:
  14486. /* TODO/FIXME - we should do a check here to see if
  14487. * the requested core GL version is supported */
  14488. RARCH_LOG("Requesting core OpenGL context (%u.%u).\n",
  14489. major, minor);
  14490. break;
  14491. #endif
  14492. #if defined(HAVE_D3D9) || defined(HAVE_D3D11)
  14493. case RETRO_HW_CONTEXT_DIRECT3D:
  14494. switch (major)
  14495. {
  14496. #ifdef HAVE_D3D9
  14497. case 9:
  14498. RARCH_LOG("Requesting D3D9 context.\n");
  14499. break;
  14500. #endif
  14501. #ifdef HAVE_D3D11
  14502. case 11:
  14503. RARCH_LOG("Requesting D3D11 context.\n");
  14504. break;
  14505. #endif
  14506. default:
  14507. RARCH_LOG("Requesting unknown context.\n");
  14508. return false;
  14509. }
  14510. break;
  14511. #endif
  14512. default:
  14513. RARCH_LOG("Requesting unknown context.\n");
  14514. return false;
  14515. }
  14516. return true;
  14517. }
  14518. static bool dynamic_verify_hw_context(
  14519. settings_t *settings,
  14520. enum retro_hw_context_type type,
  14521. unsigned minor, unsigned major)
  14522. {
  14523. const char *video_ident = settings->arrays.video_driver;
  14524. bool driver_switch_enable = settings->bools.driver_switch_enable;
  14525. if (driver_switch_enable)
  14526. return true;
  14527. switch (type)
  14528. {
  14529. case RETRO_HW_CONTEXT_VULKAN:
  14530. if (!string_is_equal(video_ident, "vulkan"))
  14531. return false;
  14532. break;
  14533. #if defined(HAVE_OPENGL_CORE)
  14534. case RETRO_HW_CONTEXT_OPENGL_CORE:
  14535. if (!string_is_equal(video_ident, "glcore"))
  14536. return false;
  14537. break;
  14538. #else
  14539. case RETRO_HW_CONTEXT_OPENGL_CORE:
  14540. #endif
  14541. case RETRO_HW_CONTEXT_OPENGLES2:
  14542. case RETRO_HW_CONTEXT_OPENGLES3:
  14543. case RETRO_HW_CONTEXT_OPENGLES_VERSION:
  14544. case RETRO_HW_CONTEXT_OPENGL:
  14545. if (!string_is_equal(video_ident, "gl") &&
  14546. !string_is_equal(video_ident, "glcore"))
  14547. return false;
  14548. break;
  14549. case RETRO_HW_CONTEXT_DIRECT3D:
  14550. if (!(string_is_equal(video_ident, "d3d11") && major == 11))
  14551. return false;
  14552. break;
  14553. default:
  14554. break;
  14555. }
  14556. return true;
  14557. }
  14558. static void rarch_log_libretro(
  14559. enum retro_log_level level,
  14560. const char *fmt, ...)
  14561. {
  14562. va_list vp;
  14563. struct rarch_state *p_rarch = &rarch_st;
  14564. settings_t *settings = p_rarch->configuration_settings;
  14565. unsigned libretro_log_level = settings->uints.libretro_log_level;
  14566. if ((unsigned)level < libretro_log_level)
  14567. return;
  14568. if (!verbosity_is_enabled())
  14569. return;
  14570. va_start(vp, fmt);
  14571. switch (level)
  14572. {
  14573. case RETRO_LOG_DEBUG:
  14574. RARCH_LOG_V("[libretro DEBUG]", fmt, vp);
  14575. break;
  14576. case RETRO_LOG_INFO:
  14577. RARCH_LOG_OUTPUT_V("[libretro INFO]", fmt, vp);
  14578. break;
  14579. case RETRO_LOG_WARN:
  14580. RARCH_WARN_V("[libretro WARN]", fmt, vp);
  14581. break;
  14582. case RETRO_LOG_ERROR:
  14583. RARCH_ERR_V("[libretro ERROR]", fmt, vp);
  14584. break;
  14585. default:
  14586. break;
  14587. }
  14588. va_end(vp);
  14589. }
  14590. static void core_performance_counter_start(
  14591. struct retro_perf_counter *perf)
  14592. {
  14593. struct rarch_state *p_rarch = &rarch_st;
  14594. bool runloop_perfcnt_enable = p_rarch->runloop_perfcnt_enable;
  14595. if (runloop_perfcnt_enable)
  14596. {
  14597. perf->call_cnt++;
  14598. perf->start = cpu_features_get_perf_counter();
  14599. }
  14600. }
  14601. static void core_performance_counter_stop(struct retro_perf_counter *perf)
  14602. {
  14603. struct rarch_state *p_rarch = &rarch_st;
  14604. bool runloop_perfcnt_enable = p_rarch->runloop_perfcnt_enable;
  14605. if (runloop_perfcnt_enable)
  14606. perf->total += cpu_features_get_perf_counter() - perf->start;
  14607. }
  14608. static size_t mmap_add_bits_down(size_t n)
  14609. {
  14610. n |= n >> 1;
  14611. n |= n >> 2;
  14612. n |= n >> 4;
  14613. n |= n >> 8;
  14614. n |= n >> 16;
  14615. /* double shift to avoid warnings on 32bit (it's dead code,
  14616. * but compilers suck) */
  14617. if (sizeof(size_t) > 4)
  14618. n |= n >> 16 >> 16;
  14619. return n;
  14620. }
  14621. static size_t mmap_inflate(size_t addr, size_t mask)
  14622. {
  14623. while (mask)
  14624. {
  14625. size_t tmp = (mask - 1) & ~mask;
  14626. /* to put in an 1 bit instead, OR in tmp+1 */
  14627. addr = ((addr & ~tmp) << 1) | (addr & tmp);
  14628. mask = mask & (mask - 1);
  14629. }
  14630. return addr;
  14631. }
  14632. static size_t mmap_reduce(size_t addr, size_t mask)
  14633. {
  14634. while (mask)
  14635. {
  14636. size_t tmp = (mask - 1) & ~mask;
  14637. addr = (addr & tmp) | ((addr >> 1) & ~tmp);
  14638. mask = (mask & (mask - 1)) >> 1;
  14639. }
  14640. return addr;
  14641. }
  14642. static size_t mmap_highest_bit(size_t n)
  14643. {
  14644. n = mmap_add_bits_down(n);
  14645. return n ^ (n >> 1);
  14646. }
  14647. static bool mmap_preprocess_descriptors(
  14648. rarch_memory_descriptor_t *first, unsigned count)
  14649. {
  14650. size_t top_addr = 1;
  14651. rarch_memory_descriptor_t *desc = NULL;
  14652. const rarch_memory_descriptor_t *end = first + count;
  14653. for (desc = first; desc < end; desc++)
  14654. {
  14655. if (desc->core.select != 0)
  14656. top_addr |= desc->core.select;
  14657. else
  14658. top_addr |= desc->core.start + desc->core.len - 1;
  14659. }
  14660. top_addr = mmap_add_bits_down(top_addr);
  14661. for (desc = first; desc < end; desc++)
  14662. {
  14663. if (desc->core.select == 0)
  14664. {
  14665. if (desc->core.len == 0)
  14666. return false;
  14667. if ((desc->core.len & (desc->core.len - 1)) != 0)
  14668. return false;
  14669. desc->core.select = top_addr & ~mmap_inflate(mmap_add_bits_down(desc->core.len - 1),
  14670. desc->core.disconnect);
  14671. }
  14672. if (desc->core.len == 0)
  14673. desc->core.len = mmap_add_bits_down(mmap_reduce(top_addr & ~desc->core.select,
  14674. desc->core.disconnect)) + 1;
  14675. if (desc->core.start & ~desc->core.select)
  14676. return false;
  14677. while (mmap_reduce(top_addr & ~desc->core.select, desc->core.disconnect) >> 1 > desc->core.len - 1)
  14678. desc->core.disconnect |= mmap_highest_bit(top_addr & ~desc->core.select & ~desc->core.disconnect);
  14679. desc->disconnect_mask = mmap_add_bits_down(desc->core.len - 1);
  14680. desc->core.disconnect &= desc->disconnect_mask;
  14681. while ((~desc->disconnect_mask) >> 1 & desc->core.disconnect)
  14682. {
  14683. desc->disconnect_mask >>= 1;
  14684. desc->core.disconnect &= desc->disconnect_mask;
  14685. }
  14686. }
  14687. return true;
  14688. }
  14689. static bool rarch_clear_all_thread_waits(
  14690. unsigned clear_threads, void *data)
  14691. {
  14692. struct rarch_state *p_rarch = &rarch_st;
  14693. if ( clear_threads > 0)
  14694. audio_driver_start(p_rarch,
  14695. false);
  14696. else
  14697. audio_driver_stop(p_rarch);
  14698. return true;
  14699. }
  14700. static void runloop_core_msg_queue_push(
  14701. struct retro_system_av_info *av_info,
  14702. const struct retro_message_ext *msg)
  14703. {
  14704. double fps;
  14705. unsigned duration_frames;
  14706. enum message_queue_category category;
  14707. /* Assign category */
  14708. switch (msg->level)
  14709. {
  14710. case RETRO_LOG_WARN:
  14711. category = MESSAGE_QUEUE_CATEGORY_WARNING;
  14712. break;
  14713. case RETRO_LOG_ERROR:
  14714. category = MESSAGE_QUEUE_CATEGORY_ERROR;
  14715. break;
  14716. case RETRO_LOG_INFO:
  14717. case RETRO_LOG_DEBUG:
  14718. default:
  14719. category = MESSAGE_QUEUE_CATEGORY_INFO;
  14720. break;
  14721. }
  14722. /* Get duration in frames */
  14723. fps = (av_info && (av_info->timing.fps > 0)) ? av_info->timing.fps : 60.0;
  14724. duration_frames = (unsigned)((fps * (float)msg->duration / 1000.0f) + 0.5f);
  14725. /* Note: Do not flush the message queue here - a core
  14726. * may need to send multiple notifications simultaneously */
  14727. runloop_msg_queue_push(msg->msg,
  14728. msg->priority, duration_frames,
  14729. false, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
  14730. category);
  14731. }
  14732. #ifdef HAVE_VULKAN
  14733. static bool hw_render_context_is_vulkan(enum retro_hw_context_type type)
  14734. {
  14735. return type == RETRO_HW_CONTEXT_VULKAN;
  14736. }
  14737. #endif
  14738. #ifdef HAVE_D3D9
  14739. static bool hw_render_context_is_d3d9(enum retro_hw_context_type type, int major, int minor)
  14740. {
  14741. return type == RETRO_HW_CONTEXT_DIRECT3D && major == 9;
  14742. }
  14743. #endif
  14744. #ifdef HAVE_D3D11
  14745. static bool hw_render_context_is_d3d11(enum retro_hw_context_type type, int major, int minor)
  14746. {
  14747. return type == RETRO_HW_CONTEXT_DIRECT3D && major == 11;
  14748. }
  14749. #endif
  14750. #ifdef HAVE_OPENGL
  14751. static bool hw_render_context_is_gl(enum retro_hw_context_type type)
  14752. {
  14753. switch (type)
  14754. {
  14755. case RETRO_HW_CONTEXT_OPENGLES2:
  14756. case RETRO_HW_CONTEXT_OPENGLES3:
  14757. case RETRO_HW_CONTEXT_OPENGLES_VERSION:
  14758. case RETRO_HW_CONTEXT_OPENGL:
  14759. #ifndef HAVE_OPENGL_CORE
  14760. case RETRO_HW_CONTEXT_OPENGL_CORE:
  14761. #endif
  14762. return true;
  14763. default:
  14764. break;
  14765. }
  14766. return false;
  14767. }
  14768. #endif
  14769. #ifdef HAVE_OPENGL_CORE
  14770. static bool hw_render_context_is_glcore(enum retro_hw_context_type type)
  14771. {
  14772. return type == RETRO_HW_CONTEXT_OPENGL_CORE;
  14773. }
  14774. #endif
  14775. #if defined(HAVE_VULKAN) || defined(HAVE_D3D11) || defined(HAVE_D3D9) || defined(HAVE_OPENGL_CORE)
  14776. static video_driver_t *hw_render_context_driver(enum retro_hw_context_type type, int major, int minor)
  14777. {
  14778. switch (type)
  14779. {
  14780. case RETRO_HW_CONTEXT_OPENGL_CORE:
  14781. #ifdef HAVE_OPENGL_CORE
  14782. return &video_gl_core;
  14783. #else
  14784. break;
  14785. #endif
  14786. case RETRO_HW_CONTEXT_OPENGL:
  14787. #ifdef HAVE_OPENGL
  14788. return &video_gl2;
  14789. #else
  14790. break;
  14791. #endif
  14792. case RETRO_HW_CONTEXT_DIRECT3D:
  14793. #if defined(HAVE_D3D9)
  14794. if (major == 9)
  14795. return &video_d3d9;
  14796. #endif
  14797. #if defined(HAVE_D3D11)
  14798. if (major == 11)
  14799. return &video_d3d11;
  14800. #endif
  14801. break;
  14802. case RETRO_HW_CONTEXT_VULKAN:
  14803. #if defined(HAVE_VULKAN)
  14804. return &video_vulkan;
  14805. #else
  14806. break;
  14807. #endif
  14808. default:
  14809. case RETRO_HW_CONTEXT_NONE:
  14810. break;
  14811. }
  14812. return NULL;
  14813. }
  14814. #endif
  14815. static enum retro_hw_context_type hw_render_context_type(const char *s)
  14816. {
  14817. #ifdef HAVE_OPENGL_CORE
  14818. if (string_is_equal(s, "glcore"))
  14819. return RETRO_HW_CONTEXT_OPENGL_CORE;
  14820. #endif
  14821. #ifdef HAVE_OPENGL
  14822. if (string_is_equal(s, "gl"))
  14823. return RETRO_HW_CONTEXT_OPENGL;
  14824. #endif
  14825. #ifdef HAVE_VULKAN
  14826. if (string_is_equal(s, "vulkan"))
  14827. return RETRO_HW_CONTEXT_VULKAN;
  14828. #endif
  14829. #ifdef HAVE_D3D11
  14830. if (string_is_equal(s, "d3d11"))
  14831. return RETRO_HW_CONTEXT_DIRECT3D;
  14832. #endif
  14833. #ifdef HAVE_D3D11
  14834. if (string_is_equal(s, "d3d9"))
  14835. return RETRO_HW_CONTEXT_DIRECT3D;
  14836. #endif
  14837. return RETRO_HW_CONTEXT_NONE;
  14838. }
  14839. static const char *hw_render_context_name(enum retro_hw_context_type type, int major, int minor)
  14840. {
  14841. #ifdef HAVE_OPENGL_CORE
  14842. if (hw_render_context_is_glcore(type))
  14843. return "glcore";
  14844. #endif
  14845. #ifdef HAVE_OPENGL
  14846. if (hw_render_context_is_gl(type))
  14847. return "gl";
  14848. #endif
  14849. #ifdef HAVE_VULKAN
  14850. if (hw_render_context_is_vulkan(type))
  14851. return "vulkan";
  14852. #endif
  14853. #ifdef HAVE_D3D11
  14854. if (hw_render_context_is_d3d11(type, major, minor))
  14855. return "d3d11";
  14856. #endif
  14857. #ifdef HAVE_D3D9
  14858. if (hw_render_context_is_d3d9(type, major, minor))
  14859. return "d3d9";
  14860. #endif
  14861. return "N/A";
  14862. }
  14863. /**
  14864. * rarch_environment_cb:
  14865. * @cmd : Identifier of command.
  14866. * @data : Pointer to data.
  14867. *
  14868. * Environment callback function implementation.
  14869. *
  14870. * Returns: true (1) if environment callback command could
  14871. * be performed, otherwise false (0).
  14872. **/
  14873. static bool rarch_environment_cb(unsigned cmd, void *data)
  14874. {
  14875. unsigned p;
  14876. struct rarch_state *p_rarch = &rarch_st;
  14877. settings_t *settings = p_rarch->configuration_settings;
  14878. rarch_system_info_t *system = &p_rarch->runloop_system;
  14879. bool ignore_environment_cb = p_rarch->ignore_environment_cb;
  14880. if (ignore_environment_cb)
  14881. return false;
  14882. switch (cmd)
  14883. {
  14884. case RETRO_ENVIRONMENT_GET_OVERSCAN:
  14885. {
  14886. bool video_crop_overscan = settings->bools.video_crop_overscan;
  14887. *(bool*)data = !video_crop_overscan;
  14888. RARCH_LOG("[Environ]: GET_OVERSCAN: %u\n",
  14889. (unsigned)!video_crop_overscan);
  14890. }
  14891. break;
  14892. case RETRO_ENVIRONMENT_GET_CAN_DUPE:
  14893. *(bool*)data = true;
  14894. RARCH_LOG("[Environ]: GET_CAN_DUPE: true\n");
  14895. break;
  14896. case RETRO_ENVIRONMENT_GET_VARIABLE:
  14897. {
  14898. unsigned log_level = settings->uints.libretro_log_level;
  14899. struct retro_variable *var = (struct retro_variable*)data;
  14900. if (!var)
  14901. return true;
  14902. var->value = NULL;
  14903. if (!p_rarch->runloop_core_options)
  14904. {
  14905. RARCH_LOG("[Environ]: GET_VARIABLE %s: not implemented.\n",
  14906. var->key);
  14907. return true;
  14908. }
  14909. {
  14910. size_t i;
  14911. #ifdef HAVE_RUNAHEAD
  14912. if (p_rarch->runloop_core_options->updated)
  14913. p_rarch->has_variable_update = true;
  14914. #endif
  14915. p_rarch->runloop_core_options->updated = false;
  14916. for (i = 0; i < p_rarch->runloop_core_options->size; i++)
  14917. {
  14918. if (!string_is_empty(p_rarch->runloop_core_options->opts[i].key))
  14919. if (string_is_equal(
  14920. p_rarch->runloop_core_options->opts[i].key, var->key))
  14921. {
  14922. var->value = p_rarch->runloop_core_options->opts[i].vals->elems[
  14923. p_rarch->runloop_core_options->opts[i].index].data;
  14924. break;
  14925. }
  14926. }
  14927. }
  14928. if (log_level == RETRO_LOG_DEBUG)
  14929. {
  14930. char s[128];
  14931. s[0] = '\0';
  14932. snprintf(s, sizeof(s), "[Environ]: GET_VARIABLE %s:\n\t%s\n", var->key, var->value ? var->value :
  14933. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
  14934. RARCH_LOG(s);
  14935. }
  14936. }
  14937. break;
  14938. case RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE:
  14939. if (p_rarch->runloop_core_options)
  14940. *(bool*)data = p_rarch->runloop_core_options->updated;
  14941. else
  14942. *(bool*)data = false;
  14943. break;
  14944. /* SET_VARIABLES: Legacy path */
  14945. case RETRO_ENVIRONMENT_SET_VARIABLES:
  14946. RARCH_LOG("[Environ]: SET_VARIABLES.\n");
  14947. if (p_rarch->runloop_core_options)
  14948. retroarch_deinit_core_options(p_rarch);
  14949. retroarch_init_core_variables(
  14950. p_rarch,
  14951. (const struct retro_variable *)data);
  14952. break;
  14953. case RETRO_ENVIRONMENT_SET_CORE_OPTIONS:
  14954. RARCH_LOG("[Environ]: SET_CORE_OPTIONS.\n");
  14955. if (p_rarch->runloop_core_options)
  14956. retroarch_deinit_core_options(p_rarch);
  14957. rarch_init_core_options(p_rarch,
  14958. (const struct retro_core_option_definition*)data);
  14959. break;
  14960. case RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL:
  14961. RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL.\n");
  14962. {
  14963. struct retro_core_option_definition *option_defs =
  14964. core_option_manager_get_definitions((const struct retro_core_options_intl*)data);
  14965. if (p_rarch->runloop_core_options)
  14966. retroarch_deinit_core_options(p_rarch);
  14967. /* Parse core_options_intl to create option definitions array */
  14968. if (option_defs)
  14969. {
  14970. /* Initialise core options */
  14971. rarch_init_core_options(p_rarch, option_defs);
  14972. /* Clean up */
  14973. free(option_defs);
  14974. }
  14975. }
  14976. break;
  14977. case RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY:
  14978. RARCH_DBG("[Environ]: RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY.\n");
  14979. {
  14980. const struct retro_core_option_display *core_options_display = (const struct retro_core_option_display *)data;
  14981. if (p_rarch->runloop_core_options && core_options_display)
  14982. core_option_manager_set_display(
  14983. p_rarch->runloop_core_options,
  14984. core_options_display->key,
  14985. core_options_display->visible);
  14986. }
  14987. break;
  14988. case RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION:
  14989. RARCH_LOG("[Environ]: GET_MESSAGE_INTERFACE_VERSION.\n");
  14990. /* Current API version is 1 */
  14991. *(unsigned *)data = 1;
  14992. break;
  14993. case RETRO_ENVIRONMENT_SET_MESSAGE:
  14994. {
  14995. const struct retro_message *msg = (const struct retro_message*)data;
  14996. RARCH_LOG("[Environ]: SET_MESSAGE: %s\n", msg->msg);
  14997. #if defined(HAVE_GFX_WIDGETS)
  14998. if (p_rarch->widgets_active)
  14999. gfx_widget_set_libretro_message(&p_rarch->dispwidget_st,
  15000. msg->msg,
  15001. roundf((float)msg->frames / 60.0f * 1000.0f));
  15002. else
  15003. #endif
  15004. runloop_msg_queue_push(msg->msg, 3, msg->frames,
  15005. true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
  15006. MESSAGE_QUEUE_CATEGORY_INFO);
  15007. break;
  15008. }
  15009. case RETRO_ENVIRONMENT_SET_MESSAGE_EXT:
  15010. {
  15011. const struct retro_message_ext *msg =
  15012. (const struct retro_message_ext*)data;
  15013. /* Log message, if required */
  15014. if (msg->target != RETRO_MESSAGE_TARGET_OSD)
  15015. {
  15016. settings_t *settings = p_rarch->configuration_settings;
  15017. unsigned log_level = settings->uints.frontend_log_level;
  15018. switch (msg->level)
  15019. {
  15020. case RETRO_LOG_DEBUG:
  15021. if (log_level == RETRO_LOG_DEBUG)
  15022. RARCH_LOG("[Environ]: SET_MESSAGE_EXT: %s\n", msg->msg);
  15023. break;
  15024. case RETRO_LOG_WARN:
  15025. RARCH_WARN("[Environ]: SET_MESSAGE_EXT: %s\n", msg->msg);
  15026. break;
  15027. case RETRO_LOG_ERROR:
  15028. RARCH_ERR("[Environ]: SET_MESSAGE_EXT: %s\n", msg->msg);
  15029. break;
  15030. case RETRO_LOG_INFO:
  15031. default:
  15032. RARCH_LOG("[Environ]: SET_MESSAGE_EXT: %s\n", msg->msg);
  15033. break;
  15034. }
  15035. }
  15036. /* Display message via OSD, if required */
  15037. if (msg->target != RETRO_MESSAGE_TARGET_LOG)
  15038. {
  15039. switch (msg->type)
  15040. {
  15041. /* Handle 'status' messages */
  15042. case RETRO_MESSAGE_TYPE_STATUS:
  15043. /* Note: We need to lock a mutex here. Strictly
  15044. * speaking, runloop_core_status_msg is not part
  15045. * of the message queue, but:
  15046. * - It may be implemented as a queue in the future
  15047. * - It seems unnecessary to create a new slock_t
  15048. * object for this type of message when
  15049. * _runloop_msg_queue_lock is already available
  15050. * We therefore just call runloop_msg_queue_lock()/
  15051. * runloop_msg_queue_unlock() in this case */
  15052. RUNLOOP_MSG_QUEUE_LOCK(p_rarch);
  15053. /* If a message is already set, only overwrite
  15054. * it if the new message has the same or higher
  15055. * priority */
  15056. if (!runloop_core_status_msg.set ||
  15057. (runloop_core_status_msg.priority <= msg->priority))
  15058. {
  15059. if (!string_is_empty(msg->msg))
  15060. {
  15061. strlcpy(runloop_core_status_msg.str, msg->msg,
  15062. sizeof(runloop_core_status_msg.str));
  15063. runloop_core_status_msg.duration = (float)msg->duration;
  15064. runloop_core_status_msg.set = true;
  15065. }
  15066. else
  15067. {
  15068. /* Ensure sane behaviour if core sends an
  15069. * empty message */
  15070. runloop_core_status_msg.str[0] = '\0';
  15071. runloop_core_status_msg.priority = 0;
  15072. runloop_core_status_msg.duration = 0.0f;
  15073. runloop_core_status_msg.set = false;
  15074. }
  15075. }
  15076. RUNLOOP_MSG_QUEUE_UNLOCK(p_rarch);
  15077. break;
  15078. #if defined(HAVE_GFX_WIDGETS)
  15079. /* Handle 'alternate' non-queued notifications */
  15080. case RETRO_MESSAGE_TYPE_NOTIFICATION_ALT:
  15081. if (p_rarch->widgets_active)
  15082. gfx_widget_set_libretro_message(&p_rarch->dispwidget_st,
  15083. msg->msg, msg->duration);
  15084. else
  15085. runloop_core_msg_queue_push(
  15086. &p_rarch->video_driver_av_info, msg);
  15087. break;
  15088. /* Handle 'progress' messages */
  15089. case RETRO_MESSAGE_TYPE_PROGRESS:
  15090. if (p_rarch->widgets_active)
  15091. gfx_widget_set_progress_message(&p_rarch->dispwidget_st,
  15092. msg->msg, msg->duration,
  15093. msg->priority, msg->progress);
  15094. else
  15095. runloop_core_msg_queue_push(
  15096. &p_rarch->video_driver_av_info, msg);
  15097. break;
  15098. #endif
  15099. /* Handle standard (queued) notifications */
  15100. case RETRO_MESSAGE_TYPE_NOTIFICATION:
  15101. default:
  15102. runloop_core_msg_queue_push(
  15103. &p_rarch->video_driver_av_info, msg);
  15104. break;
  15105. }
  15106. }
  15107. break;
  15108. }
  15109. case RETRO_ENVIRONMENT_SET_ROTATION:
  15110. {
  15111. unsigned rotation = *(const unsigned*)data;
  15112. bool video_allow_rotate = settings->bools.video_allow_rotate;
  15113. RARCH_LOG("[Environ]: SET_ROTATION: %u\n", rotation);
  15114. if (!video_allow_rotate)
  15115. break;
  15116. if (system)
  15117. system->rotation = rotation;
  15118. if (!video_driver_set_rotation(rotation))
  15119. return false;
  15120. break;
  15121. }
  15122. case RETRO_ENVIRONMENT_SHUTDOWN:
  15123. RARCH_LOG("[Environ]: SHUTDOWN.\n");
  15124. /* This case occurs when a core (internally) requests
  15125. * a shutdown event. Must save runtime log file here,
  15126. * since normal command.c CMD_EVENT_CORE_DEINIT event
  15127. * will not occur until after the current content has
  15128. * been cleared (causing log to be skipped) */
  15129. command_event_runtime_log_deinit(p_rarch);
  15130. p_rarch->runloop_shutdown_initiated = true;
  15131. p_rarch->runloop_core_shutdown_initiated = true;
  15132. break;
  15133. case RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL:
  15134. if (system)
  15135. {
  15136. system->performance_level = *(const unsigned*)data;
  15137. RARCH_LOG("[Environ]: PERFORMANCE_LEVEL: %u.\n",
  15138. system->performance_level);
  15139. }
  15140. break;
  15141. case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY:
  15142. {
  15143. const char *dir_system = settings->paths.directory_system;
  15144. bool systemfiles_in_content_dir = settings->bools.systemfiles_in_content_dir;
  15145. if (string_is_empty(dir_system) || systemfiles_in_content_dir)
  15146. {
  15147. const char *fullpath = path_get(RARCH_PATH_CONTENT);
  15148. if (!string_is_empty(fullpath))
  15149. {
  15150. char temp_path[PATH_MAX_LENGTH];
  15151. temp_path[0] = '\0';
  15152. if (string_is_empty(dir_system))
  15153. RARCH_WARN("[Environ]: SYSTEM DIR is empty, assume CONTENT DIR %s\n",
  15154. fullpath);
  15155. fill_pathname_basedir(temp_path, fullpath, sizeof(temp_path));
  15156. dir_set(RARCH_DIR_SYSTEM, temp_path);
  15157. }
  15158. *(const char**)data = dir_get_ptr(RARCH_DIR_SYSTEM);
  15159. RARCH_LOG("[Environ]: SYSTEM_DIRECTORY: \"%s\".\n",
  15160. dir_system);
  15161. }
  15162. else
  15163. {
  15164. *(const char**)data = dir_system;
  15165. RARCH_LOG("[Environ]: SYSTEM_DIRECTORY: \"%s\".\n",
  15166. dir_system);
  15167. }
  15168. }
  15169. break;
  15170. case RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY:
  15171. RARCH_LOG("[Environ]: GET_SAVE_DIRECTORY.\n");
  15172. *(const char**)data = p_rarch->current_savefile_dir;
  15173. break;
  15174. case RETRO_ENVIRONMENT_GET_USERNAME:
  15175. *(const char**)data = *settings->paths.username ?
  15176. settings->paths.username : NULL;
  15177. RARCH_LOG("[Environ]: GET_USERNAME: \"%s\".\n",
  15178. settings->paths.username);
  15179. break;
  15180. case RETRO_ENVIRONMENT_GET_LANGUAGE:
  15181. #ifdef HAVE_LANGEXTRA
  15182. {
  15183. unsigned user_lang = *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE);
  15184. *(unsigned *)data = user_lang;
  15185. RARCH_LOG("[Environ]: GET_LANGUAGE: \"%u\".\n", user_lang);
  15186. }
  15187. #endif
  15188. break;
  15189. case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT:
  15190. {
  15191. enum retro_pixel_format pix_fmt =
  15192. *(const enum retro_pixel_format*)data;
  15193. switch (pix_fmt)
  15194. {
  15195. case RETRO_PIXEL_FORMAT_0RGB1555:
  15196. RARCH_LOG("[Environ]: SET_PIXEL_FORMAT: 0RGB1555.\n");
  15197. break;
  15198. case RETRO_PIXEL_FORMAT_RGB565:
  15199. RARCH_LOG("[Environ]: SET_PIXEL_FORMAT: RGB565.\n");
  15200. break;
  15201. case RETRO_PIXEL_FORMAT_XRGB8888:
  15202. RARCH_LOG("[Environ]: SET_PIXEL_FORMAT: XRGB8888.\n");
  15203. break;
  15204. default:
  15205. return false;
  15206. }
  15207. p_rarch->video_driver_pix_fmt = pix_fmt;
  15208. break;
  15209. }
  15210. case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS:
  15211. {
  15212. static const char *libretro_btn_desc[] = {
  15213. "B (bottom)", "Y (left)", "Select", "Start",
  15214. "D-Pad Up", "D-Pad Down", "D-Pad Left", "D-Pad Right",
  15215. "A (right)", "X (up)",
  15216. "L", "R", "L2", "R2", "L3", "R3",
  15217. };
  15218. if (system)
  15219. {
  15220. unsigned retro_id;
  15221. const struct retro_input_descriptor *desc = NULL;
  15222. memset((void*)&system->input_desc_btn, 0,
  15223. sizeof(system->input_desc_btn));
  15224. desc = (const struct retro_input_descriptor*)data;
  15225. for (; desc->description; desc++)
  15226. {
  15227. unsigned retro_port = desc->port;
  15228. retro_id = desc->id;
  15229. if (desc->port >= MAX_USERS)
  15230. continue;
  15231. if (desc->id >= RARCH_FIRST_CUSTOM_BIND)
  15232. continue;
  15233. switch (desc->device)
  15234. {
  15235. case RETRO_DEVICE_JOYPAD:
  15236. system->input_desc_btn[retro_port]
  15237. [retro_id] = desc->description;
  15238. break;
  15239. case RETRO_DEVICE_ANALOG:
  15240. switch (retro_id)
  15241. {
  15242. case RETRO_DEVICE_ID_ANALOG_X:
  15243. switch (desc->index)
  15244. {
  15245. case RETRO_DEVICE_INDEX_ANALOG_LEFT:
  15246. system->input_desc_btn[retro_port]
  15247. [RARCH_ANALOG_LEFT_X_PLUS] = desc->description;
  15248. system->input_desc_btn[retro_port]
  15249. [RARCH_ANALOG_LEFT_X_MINUS] = desc->description;
  15250. break;
  15251. case RETRO_DEVICE_INDEX_ANALOG_RIGHT:
  15252. system->input_desc_btn[retro_port]
  15253. [RARCH_ANALOG_RIGHT_X_PLUS] = desc->description;
  15254. system->input_desc_btn[retro_port]
  15255. [RARCH_ANALOG_RIGHT_X_MINUS] = desc->description;
  15256. break;
  15257. }
  15258. break;
  15259. case RETRO_DEVICE_ID_ANALOG_Y:
  15260. switch (desc->index)
  15261. {
  15262. case RETRO_DEVICE_INDEX_ANALOG_LEFT:
  15263. system->input_desc_btn[retro_port]
  15264. [RARCH_ANALOG_LEFT_Y_PLUS] = desc->description;
  15265. system->input_desc_btn[retro_port]
  15266. [RARCH_ANALOG_LEFT_Y_MINUS] = desc->description;
  15267. break;
  15268. case RETRO_DEVICE_INDEX_ANALOG_RIGHT:
  15269. system->input_desc_btn[retro_port]
  15270. [RARCH_ANALOG_RIGHT_Y_PLUS] = desc->description;
  15271. system->input_desc_btn[retro_port]
  15272. [RARCH_ANALOG_RIGHT_Y_MINUS] = desc->description;
  15273. break;
  15274. }
  15275. break;
  15276. }
  15277. break;
  15278. }
  15279. }
  15280. RARCH_LOG("[Environ]: SET_INPUT_DESCRIPTORS:\n");
  15281. {
  15282. unsigned log_level = settings->uints.libretro_log_level;
  15283. if (log_level == RETRO_LOG_DEBUG)
  15284. {
  15285. unsigned input_driver_max_users =
  15286. p_rarch->input_driver_max_users;
  15287. for (p = 0; p < input_driver_max_users; p++)
  15288. {
  15289. for (retro_id = 0; retro_id < RARCH_FIRST_CUSTOM_BIND; retro_id++)
  15290. {
  15291. const char *description = system->input_desc_btn[p][retro_id];
  15292. if (!description)
  15293. continue;
  15294. RARCH_LOG("\tRetroPad, Port %u, Button \"%s\" => \"%s\"\n",
  15295. p + 1, libretro_btn_desc[retro_id], description);
  15296. }
  15297. }
  15298. }
  15299. }
  15300. p_rarch->current_core.has_set_input_descriptors = true;
  15301. }
  15302. break;
  15303. }
  15304. case RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK:
  15305. {
  15306. const struct retro_keyboard_callback *info =
  15307. (const struct retro_keyboard_callback*)data;
  15308. retro_keyboard_event_t *frontend_key_event = &p_rarch->runloop_frontend_key_event;
  15309. retro_keyboard_event_t *key_event = &p_rarch->runloop_key_event;
  15310. RARCH_LOG("[Environ]: SET_KEYBOARD_CALLBACK.\n");
  15311. if (key_event)
  15312. *key_event = info->callback;
  15313. if (frontend_key_event && key_event)
  15314. *frontend_key_event = *key_event;
  15315. /* If a core calls RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK,
  15316. * then it is assumed that game focus mode is desired */
  15317. p_rarch->game_focus_state.core_requested = true;
  15318. break;
  15319. }
  15320. case RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION:
  15321. RARCH_LOG("[Environ]: GET_DISK_CONTROL_INTERFACE_VERSION.\n");
  15322. /* Current API version is 1 */
  15323. *(unsigned *)data = 1;
  15324. break;
  15325. case RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE:
  15326. {
  15327. const struct retro_disk_control_callback *control_cb =
  15328. (const struct retro_disk_control_callback*)data;
  15329. if (system)
  15330. {
  15331. RARCH_LOG("[Environ]: SET_DISK_CONTROL_INTERFACE.\n");
  15332. disk_control_set_callback(&system->disk_control, control_cb);
  15333. }
  15334. }
  15335. break;
  15336. case RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE:
  15337. {
  15338. const struct retro_disk_control_ext_callback *control_cb =
  15339. (const struct retro_disk_control_ext_callback*)data;
  15340. if (system)
  15341. {
  15342. RARCH_LOG("[Environ]: SET_DISK_CONTROL_EXT_INTERFACE.\n");
  15343. disk_control_set_ext_callback(&system->disk_control, control_cb);
  15344. }
  15345. }
  15346. break;
  15347. case RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER:
  15348. {
  15349. unsigned *cb = (unsigned*)data;
  15350. settings_t *settings = p_rarch->configuration_settings;
  15351. const char *video_driver_name = settings->arrays.video_driver;
  15352. bool driver_switch_enable = settings->bools.driver_switch_enable;
  15353. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER, video driver name: %s.\n", video_driver_name);
  15354. if (string_is_equal(video_driver_name, "glcore"))
  15355. {
  15356. *cb = RETRO_HW_CONTEXT_OPENGL_CORE;
  15357. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_OPENGL_CORE.\n");
  15358. }
  15359. else if (string_is_equal(video_driver_name, "gl"))
  15360. {
  15361. *cb = RETRO_HW_CONTEXT_OPENGL;
  15362. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_OPENGL.\n");
  15363. }
  15364. else if (string_is_equal(video_driver_name, "vulkan"))
  15365. {
  15366. *cb = RETRO_HW_CONTEXT_VULKAN;
  15367. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_VULKAN.\n");
  15368. }
  15369. else if (!strncmp(video_driver_name, "d3d", 3))
  15370. {
  15371. *cb = RETRO_HW_CONTEXT_DIRECT3D;
  15372. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_DIRECT3D.\n");
  15373. }
  15374. else
  15375. {
  15376. *cb = RETRO_HW_CONTEXT_NONE;
  15377. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_NONE.\n");
  15378. }
  15379. if (!driver_switch_enable)
  15380. {
  15381. RARCH_LOG("[Environ]: Driver switching disabled, GET_PREFERRED_HW_RENDER will be ignored.\n");
  15382. return false;
  15383. }
  15384. break;
  15385. }
  15386. case RETRO_ENVIRONMENT_SET_HW_RENDER:
  15387. case RETRO_ENVIRONMENT_SET_HW_RENDER | RETRO_ENVIRONMENT_EXPERIMENTAL:
  15388. {
  15389. struct retro_hw_render_callback *cb =
  15390. (struct retro_hw_render_callback*)data;
  15391. struct retro_hw_render_callback *hwr =
  15392. VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
  15393. if (!cb)
  15394. {
  15395. RARCH_ERR("[Environ]: SET_HW_RENDER - No valid callback passed, returning...\n");
  15396. return false;
  15397. }
  15398. RARCH_LOG("[Environ]: SET_HW_RENDER, context type: %s.\n", hw_render_context_name(cb->context_type, cb->version_major, cb->version_minor));
  15399. if (!dynamic_request_hw_context(
  15400. cb->context_type, cb->version_minor, cb->version_major))
  15401. {
  15402. RARCH_ERR("[Environ]: SET_HW_RENDER - Dynamic request HW context failed.\n");
  15403. return false;
  15404. }
  15405. if (!dynamic_verify_hw_context(p_rarch->configuration_settings,
  15406. cb->context_type, cb->version_minor, cb->version_major))
  15407. {
  15408. RARCH_ERR("[Environ]: SET_HW_RENDER: Dynamic verify HW context failed.\n");
  15409. return false;
  15410. }
  15411. #if defined(HAVE_OPENGL) || defined(HAVE_OPENGL_CORE)
  15412. if (!gl_set_core_context(cb->context_type)) { }
  15413. #endif
  15414. cb->get_current_framebuffer = video_driver_get_current_framebuffer;
  15415. cb->get_proc_address = video_driver_get_proc_address;
  15416. /* Old ABI. Don't copy garbage. */
  15417. if (cmd & RETRO_ENVIRONMENT_EXPERIMENTAL)
  15418. {
  15419. memcpy(hwr,
  15420. cb, offsetof(struct retro_hw_render_callback, stencil));
  15421. memset((uint8_t*)hwr + offsetof(struct retro_hw_render_callback, stencil),
  15422. 0, sizeof(*cb) - offsetof(struct retro_hw_render_callback, stencil));
  15423. }
  15424. else
  15425. memcpy(hwr, cb, sizeof(*cb));
  15426. RARCH_LOG("Reached end of SET_HW_RENDER.\n");
  15427. break;
  15428. }
  15429. case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME:
  15430. {
  15431. bool state = *(const bool*)data;
  15432. RARCH_LOG("[Environ]: SET_SUPPORT_NO_GAME: %s.\n", state ? "yes" : "no");
  15433. if (state)
  15434. content_set_does_not_need_content();
  15435. else
  15436. content_unset_does_not_need_content();
  15437. break;
  15438. }
  15439. case RETRO_ENVIRONMENT_GET_LIBRETRO_PATH:
  15440. {
  15441. const char **path = (const char**)data;
  15442. RARCH_LOG("[Environ]: GET_LIBRETRO_PATH.\n");
  15443. #ifdef HAVE_DYNAMIC
  15444. *path = path_get(RARCH_PATH_CORE);
  15445. #else
  15446. *path = NULL;
  15447. #endif
  15448. break;
  15449. }
  15450. case RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK:
  15451. #ifdef HAVE_THREADS
  15452. {
  15453. const struct retro_audio_callback *cb = (const struct retro_audio_callback*)data;
  15454. RARCH_LOG("[Environ]: SET_AUDIO_CALLBACK.\n");
  15455. #ifdef HAVE_NETWORKING
  15456. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
  15457. return false;
  15458. #endif
  15459. if (p_rarch->recording_data) /* A/V sync is a must. */
  15460. return false;
  15461. if (cb)
  15462. p_rarch->audio_callback = *cb;
  15463. }
  15464. break;
  15465. #else
  15466. return false;
  15467. #endif
  15468. case RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK:
  15469. {
  15470. const struct retro_frame_time_callback *info =
  15471. (const struct retro_frame_time_callback*)data;
  15472. RARCH_LOG("[Environ]: SET_FRAME_TIME_CALLBACK.\n");
  15473. #ifdef HAVE_NETWORKING
  15474. /* retro_run() will be called in very strange and
  15475. * mysterious ways, have to disable it. */
  15476. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
  15477. return false;
  15478. #endif
  15479. p_rarch->runloop_frame_time = *info;
  15480. break;
  15481. }
  15482. case RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK:
  15483. {
  15484. const struct retro_audio_buffer_status_callback *info =
  15485. (const struct retro_audio_buffer_status_callback*)data;
  15486. RARCH_LOG("[Environ]: SET_AUDIO_BUFFER_STATUS_CALLBACK.\n");
  15487. if (info)
  15488. p_rarch->runloop_audio_buffer_status.callback = info->callback;
  15489. else
  15490. p_rarch->runloop_audio_buffer_status.callback = NULL;
  15491. break;
  15492. }
  15493. case RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY:
  15494. {
  15495. unsigned audio_latency_default = settings->uints.audio_latency;
  15496. unsigned audio_latency_current =
  15497. (p_rarch->runloop_audio_latency > audio_latency_default) ?
  15498. p_rarch->runloop_audio_latency : audio_latency_default;
  15499. unsigned audio_latency_new;
  15500. RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY.\n");
  15501. /* Sanitise input latency value */
  15502. p_rarch->runloop_audio_latency = 0;
  15503. if (data)
  15504. p_rarch->runloop_audio_latency = *(const unsigned*)data;
  15505. if (p_rarch->runloop_audio_latency > 512)
  15506. {
  15507. RARCH_WARN("[Environ]: Requested audio latency of %u ms - limiting to maximum of 512 ms.\n",
  15508. p_rarch->runloop_audio_latency);
  15509. p_rarch->runloop_audio_latency = 512;
  15510. }
  15511. /* Determine new set-point latency value */
  15512. if (p_rarch->runloop_audio_latency >= audio_latency_default)
  15513. audio_latency_new = p_rarch->runloop_audio_latency;
  15514. else
  15515. {
  15516. if (p_rarch->runloop_audio_latency != 0)
  15517. RARCH_WARN("[Environ]: Requested audio latency of %u ms is less than frontend default of %u ms."
  15518. " Using frontend default...\n",
  15519. p_rarch->runloop_audio_latency, audio_latency_default);
  15520. audio_latency_new = audio_latency_default;
  15521. }
  15522. /* Check whether audio driver requires reinitialisation
  15523. * (Identical to RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO,
  15524. * without video driver initialisation) */
  15525. if (audio_latency_new != audio_latency_current)
  15526. {
  15527. bool video_fullscreen = settings->bools.video_fullscreen;
  15528. int reinit_flags = DRIVERS_CMD_ALL &
  15529. ~(DRIVER_VIDEO_MASK | DRIVER_INPUT_MASK | DRIVER_MENU_MASK);
  15530. RARCH_LOG("[Environ]: Setting audio latency to %u ms.\n", audio_latency_new);
  15531. command_event(CMD_EVENT_REINIT, &reinit_flags);
  15532. video_driver_set_aspect_ratio();
  15533. /* Cannot continue recording with different parameters.
  15534. * Take the easiest route out and just restart the recording. */
  15535. if (p_rarch->recording_data)
  15536. {
  15537. runloop_msg_queue_push(
  15538. msg_hash_to_str(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT),
  15539. 2, 180, false,
  15540. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  15541. command_event(CMD_EVENT_RECORD_DEINIT, NULL);
  15542. command_event(CMD_EVENT_RECORD_INIT, NULL);
  15543. }
  15544. /* Hide mouse cursor in fullscreen mode */
  15545. if (video_fullscreen)
  15546. video_driver_hide_mouse();
  15547. }
  15548. break;
  15549. }
  15550. case RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE:
  15551. {
  15552. struct retro_rumble_interface *iface =
  15553. (struct retro_rumble_interface*)data;
  15554. RARCH_LOG("[Environ]: GET_RUMBLE_INTERFACE.\n");
  15555. iface->set_rumble_state = input_driver_set_rumble_state;
  15556. break;
  15557. }
  15558. case RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES:
  15559. {
  15560. uint64_t *mask = (uint64_t*)data;
  15561. RARCH_LOG("[Environ]: GET_INPUT_DEVICE_CAPABILITIES.\n");
  15562. if (!p_rarch->current_input->get_capabilities || !p_rarch->current_input_data)
  15563. return false;
  15564. *mask = input_driver_get_capabilities();
  15565. break;
  15566. }
  15567. case RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE:
  15568. {
  15569. settings_t *settings = p_rarch->configuration_settings;
  15570. bool input_sensors_enable = settings->bools.input_sensors_enable;
  15571. struct retro_sensor_interface *iface = (struct retro_sensor_interface*)data;
  15572. RARCH_LOG("[Environ]: GET_SENSOR_INTERFACE.\n");
  15573. if (!input_sensors_enable)
  15574. return false;
  15575. iface->set_sensor_state = input_sensor_set_state;
  15576. iface->get_sensor_input = input_sensor_get_input;
  15577. break;
  15578. }
  15579. case RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE:
  15580. {
  15581. struct retro_camera_callback *cb =
  15582. (struct retro_camera_callback*)data;
  15583. RARCH_LOG("[Environ]: GET_CAMERA_INTERFACE.\n");
  15584. cb->start = driver_camera_start;
  15585. cb->stop = driver_camera_stop;
  15586. p_rarch->camera_cb = *cb;
  15587. if (cb->caps != 0)
  15588. p_rarch->camera_driver_active = true;
  15589. else
  15590. p_rarch->camera_driver_active = false;
  15591. break;
  15592. }
  15593. case RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE:
  15594. {
  15595. struct retro_location_callback *cb =
  15596. (struct retro_location_callback*)data;
  15597. RARCH_LOG("[Environ]: GET_LOCATION_INTERFACE.\n");
  15598. cb->start = driver_location_start;
  15599. cb->stop = driver_location_stop;
  15600. cb->get_position = driver_location_get_position;
  15601. cb->set_interval = driver_location_set_interval;
  15602. if (system)
  15603. system->location_cb = *cb;
  15604. p_rarch->location_driver_active = false;
  15605. break;
  15606. }
  15607. case RETRO_ENVIRONMENT_GET_LOG_INTERFACE:
  15608. {
  15609. struct retro_log_callback *cb = (struct retro_log_callback*)data;
  15610. RARCH_LOG("[Environ]: GET_LOG_INTERFACE.\n");
  15611. cb->log = rarch_log_libretro;
  15612. break;
  15613. }
  15614. case RETRO_ENVIRONMENT_GET_PERF_INTERFACE:
  15615. {
  15616. struct retro_perf_callback *cb = (struct retro_perf_callback*)data;
  15617. RARCH_LOG("[Environ]: GET_PERF_INTERFACE.\n");
  15618. cb->get_time_usec = cpu_features_get_time_usec;
  15619. cb->get_cpu_features = cpu_features_get;
  15620. cb->get_perf_counter = cpu_features_get_perf_counter;
  15621. cb->perf_register = performance_counter_register;
  15622. cb->perf_start = core_performance_counter_start;
  15623. cb->perf_stop = core_performance_counter_stop;
  15624. cb->perf_log = retro_perf_log;
  15625. break;
  15626. }
  15627. case RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY:
  15628. {
  15629. const char **dir = (const char**)data;
  15630. const char *dir_core_assets = settings->paths.directory_core_assets;
  15631. *dir = *dir_core_assets ?
  15632. dir_core_assets : NULL;
  15633. RARCH_LOG("[Environ]: CORE_ASSETS_DIRECTORY: \"%s\".\n",
  15634. dir_core_assets);
  15635. break;
  15636. }
  15637. case RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO:
  15638. /**
  15639. * Update the system Audio/Video information.
  15640. * Will reinitialize audio/video drivers if needed.
  15641. * Used by RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO.
  15642. **/
  15643. {
  15644. const struct retro_system_av_info **info = (const struct retro_system_av_info**)&data;
  15645. struct retro_system_av_info *av_info = &p_rarch->video_driver_av_info;
  15646. if (data)
  15647. {
  15648. settings_t *settings = p_rarch->configuration_settings;
  15649. unsigned crt_switch_resolution = settings->uints.crt_switch_resolution;
  15650. bool video_fullscreen = settings->bools.video_fullscreen;
  15651. const bool no_video_reinit = (
  15652. crt_switch_resolution == 0
  15653. && data
  15654. && ((*info)->geometry.max_width == av_info->geometry.max_width)
  15655. && ((*info)->geometry.max_height == av_info->geometry.max_height));
  15656. /* When not doing video reinit, we also must not do input and menu
  15657. * reinit, otherwise the input driver crashes and the menu gets
  15658. * corrupted. */
  15659. int reinit_flags = no_video_reinit ?
  15660. DRIVERS_CMD_ALL & ~(DRIVER_VIDEO_MASK | DRIVER_INPUT_MASK | DRIVER_MENU_MASK)
  15661. : DRIVERS_CMD_ALL;
  15662. RARCH_LOG("[Environ]: SET_SYSTEM_AV_INFO.\n");
  15663. memcpy(av_info, *info, sizeof(*av_info));
  15664. command_event(CMD_EVENT_REINIT, &reinit_flags);
  15665. if (no_video_reinit)
  15666. video_driver_set_aspect_ratio();
  15667. /* Cannot continue recording with different parameters.
  15668. * Take the easiest route out and just restart the recording. */
  15669. if (p_rarch->recording_data)
  15670. {
  15671. runloop_msg_queue_push(
  15672. msg_hash_to_str(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT),
  15673. 2, 180, false,
  15674. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  15675. command_event(CMD_EVENT_RECORD_DEINIT, NULL);
  15676. command_event(CMD_EVENT_RECORD_INIT, NULL);
  15677. }
  15678. /* Hide mouse cursor in fullscreen after
  15679. * a RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO call. */
  15680. if (video_fullscreen)
  15681. video_driver_hide_mouse();
  15682. return true;
  15683. }
  15684. return false;
  15685. }
  15686. case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO:
  15687. {
  15688. unsigned i;
  15689. const struct retro_subsystem_info *info =
  15690. (const struct retro_subsystem_info*)data;
  15691. unsigned log_level = settings->uints.libretro_log_level;
  15692. if (log_level == RETRO_LOG_DEBUG)
  15693. RARCH_LOG("[Environ]: SET_SUBSYSTEM_INFO.\n");
  15694. for (i = 0; info[i].ident; i++)
  15695. {
  15696. unsigned j;
  15697. if (log_level != RETRO_LOG_DEBUG)
  15698. continue;
  15699. RARCH_LOG("Special game type: %s\n Ident: %s\n ID: %u\n Content:\n",
  15700. info[i].desc,
  15701. info[i].ident,
  15702. info[i].id
  15703. );
  15704. for (j = 0; j < info[i].num_roms; j++)
  15705. {
  15706. RARCH_LOG(" %s (%s)\n",
  15707. info[i].roms[j].desc, info[i].roms[j].required ?
  15708. "required" : "optional");
  15709. }
  15710. }
  15711. if (system)
  15712. {
  15713. struct retro_subsystem_info *info_ptr = NULL;
  15714. free(system->subsystem.data);
  15715. system->subsystem.data = NULL;
  15716. system->subsystem.size = 0;
  15717. info_ptr = (struct retro_subsystem_info*)
  15718. malloc(i * sizeof(*info_ptr));
  15719. if (!info_ptr)
  15720. return false;
  15721. system->subsystem.data = info_ptr;
  15722. memcpy(system->subsystem.data, info,
  15723. i * sizeof(*system->subsystem.data));
  15724. system->subsystem.size = i;
  15725. p_rarch->current_core.has_set_subsystems = true;
  15726. }
  15727. break;
  15728. }
  15729. case RETRO_ENVIRONMENT_SET_CONTROLLER_INFO:
  15730. {
  15731. unsigned i, j;
  15732. const struct retro_controller_info *info =
  15733. (const struct retro_controller_info*)data;
  15734. unsigned log_level = settings->uints.libretro_log_level;
  15735. RARCH_LOG("[Environ]: SET_CONTROLLER_INFO.\n");
  15736. for (i = 0; info[i].types; i++)
  15737. {
  15738. if (log_level != RETRO_LOG_DEBUG)
  15739. continue;
  15740. RARCH_LOG("Controller port: %u\n", i + 1);
  15741. for (j = 0; j < info[i].num_types; j++)
  15742. RARCH_LOG(" %s (ID: %u)\n", info[i].types[j].desc,
  15743. info[i].types[j].id);
  15744. }
  15745. if (system)
  15746. {
  15747. struct retro_controller_info *info_ptr = NULL;
  15748. free(system->ports.data);
  15749. system->ports.data = NULL;
  15750. system->ports.size = 0;
  15751. info_ptr = (struct retro_controller_info*)calloc(i, sizeof(*info_ptr));
  15752. if (!info_ptr)
  15753. return false;
  15754. system->ports.data = info_ptr;
  15755. memcpy(system->ports.data, info,
  15756. i * sizeof(*system->ports.data));
  15757. system->ports.size = i;
  15758. }
  15759. break;
  15760. }
  15761. case RETRO_ENVIRONMENT_SET_MEMORY_MAPS:
  15762. {
  15763. if (system)
  15764. {
  15765. unsigned i;
  15766. const struct retro_memory_map *mmaps =
  15767. (const struct retro_memory_map*)data;
  15768. rarch_memory_descriptor_t *descriptors = NULL;
  15769. RARCH_LOG("[Environ]: SET_MEMORY_MAPS.\n");
  15770. free((void*)system->mmaps.descriptors);
  15771. system->mmaps.descriptors = 0;
  15772. system->mmaps.num_descriptors = 0;
  15773. descriptors = (rarch_memory_descriptor_t*)
  15774. calloc(mmaps->num_descriptors,
  15775. sizeof(*descriptors));
  15776. if (!descriptors)
  15777. return false;
  15778. system->mmaps.descriptors = descriptors;
  15779. system->mmaps.num_descriptors = mmaps->num_descriptors;
  15780. for (i = 0; i < mmaps->num_descriptors; i++)
  15781. system->mmaps.descriptors[i].core = mmaps->descriptors[i];
  15782. mmap_preprocess_descriptors(descriptors, mmaps->num_descriptors);
  15783. if (sizeof(void *) == 8)
  15784. RARCH_LOG(" ndx flags ptr offset start select disconn len addrspace\n");
  15785. else
  15786. RARCH_LOG(" ndx flags ptr offset start select disconn len addrspace\n");
  15787. for (i = 0; i < system->mmaps.num_descriptors; i++)
  15788. {
  15789. const rarch_memory_descriptor_t *desc =
  15790. &system->mmaps.descriptors[i];
  15791. char flags[7];
  15792. flags[0] = 'M';
  15793. if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_8) == RETRO_MEMDESC_MINSIZE_8)
  15794. flags[1] = '8';
  15795. else if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_4) == RETRO_MEMDESC_MINSIZE_4)
  15796. flags[1] = '4';
  15797. else if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_2) == RETRO_MEMDESC_MINSIZE_2)
  15798. flags[1] = '2';
  15799. else
  15800. flags[1] = '1';
  15801. flags[2] = 'A';
  15802. if ((desc->core.flags & RETRO_MEMDESC_ALIGN_8) == RETRO_MEMDESC_ALIGN_8)
  15803. flags[3] = '8';
  15804. else if ((desc->core.flags & RETRO_MEMDESC_ALIGN_4) == RETRO_MEMDESC_ALIGN_4)
  15805. flags[3] = '4';
  15806. else if ((desc->core.flags & RETRO_MEMDESC_ALIGN_2) == RETRO_MEMDESC_ALIGN_2)
  15807. flags[3] = '2';
  15808. else
  15809. flags[3] = '1';
  15810. flags[4] = (desc->core.flags & RETRO_MEMDESC_BIGENDIAN) ? 'B' : 'b';
  15811. flags[5] = (desc->core.flags & RETRO_MEMDESC_CONST) ? 'C' : 'c';
  15812. flags[6] = 0;
  15813. RARCH_LOG(" %03u %s %p %08X %08X %08X %08X %08X %s\n",
  15814. i + 1, flags, desc->core.ptr, desc->core.offset, desc->core.start,
  15815. desc->core.select, desc->core.disconnect, desc->core.len,
  15816. desc->core.addrspace ? desc->core.addrspace : "");
  15817. }
  15818. }
  15819. else
  15820. {
  15821. RARCH_WARN("[Environ]: SET_MEMORY_MAPS, but system pointer not initialized..\n");
  15822. }
  15823. break;
  15824. }
  15825. case RETRO_ENVIRONMENT_SET_GEOMETRY:
  15826. {
  15827. struct retro_system_av_info *av_info = &p_rarch->video_driver_av_info;
  15828. struct retro_game_geometry *geom = (struct retro_game_geometry*)&av_info->geometry;
  15829. const struct retro_game_geometry *in_geom = (const struct retro_game_geometry*)data;
  15830. if (!geom)
  15831. return false;
  15832. /* Can potentially be called every frame,
  15833. * don't do anything unless required. */
  15834. if ( (geom->base_width != in_geom->base_width) ||
  15835. (geom->base_height != in_geom->base_height) ||
  15836. (geom->aspect_ratio != in_geom->aspect_ratio))
  15837. {
  15838. geom->base_width = in_geom->base_width;
  15839. geom->base_height = in_geom->base_height;
  15840. geom->aspect_ratio = in_geom->aspect_ratio;
  15841. RARCH_LOG("[Environ]: SET_GEOMETRY: %ux%u, aspect: %.3f.\n",
  15842. geom->base_width, geom->base_height, geom->aspect_ratio);
  15843. /* Forces recomputation of aspect ratios if
  15844. * using core-dependent aspect ratios. */
  15845. video_driver_set_aspect_ratio();
  15846. /* TODO: Figure out what to do, if anything, with recording. */
  15847. }
  15848. else
  15849. {
  15850. RARCH_LOG("[Environ]: SET_GEOMETRY.\n");
  15851. }
  15852. break;
  15853. }
  15854. case RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER:
  15855. {
  15856. struct retro_framebuffer *fb = (struct retro_framebuffer*)data;
  15857. if (
  15858. p_rarch->video_driver_poke
  15859. && p_rarch->video_driver_poke->get_current_software_framebuffer
  15860. && p_rarch->video_driver_poke->get_current_software_framebuffer(
  15861. p_rarch->video_driver_data, fb))
  15862. return true;
  15863. return false;
  15864. }
  15865. case RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE:
  15866. {
  15867. const struct retro_hw_render_interface **iface = (const struct retro_hw_render_interface **)data;
  15868. if (
  15869. p_rarch->video_driver_poke
  15870. && p_rarch->video_driver_poke->get_hw_render_interface
  15871. && p_rarch->video_driver_poke->get_hw_render_interface(
  15872. p_rarch->video_driver_data, iface))
  15873. return true;
  15874. return false;
  15875. }
  15876. case RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS:
  15877. #ifdef HAVE_CHEEVOS
  15878. {
  15879. bool state = *(const bool*)data;
  15880. RARCH_LOG("[Environ]: SET_SUPPORT_ACHIEVEMENTS: %s.\n", state ? "yes" : "no");
  15881. rcheevos_set_support_cheevos(state);
  15882. }
  15883. #endif
  15884. break;
  15885. case RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE:
  15886. {
  15887. const struct retro_hw_render_context_negotiation_interface *iface =
  15888. (const struct retro_hw_render_context_negotiation_interface*)data;
  15889. RARCH_LOG("[Environ]: SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE.\n");
  15890. p_rarch->hw_render_context_negotiation = iface;
  15891. break;
  15892. }
  15893. case RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS:
  15894. {
  15895. uint64_t *quirks = (uint64_t *) data;
  15896. RARCH_LOG("[Environ]: SET_SERIALIZATION_QUIRKS.\n");
  15897. p_rarch->current_core.serialization_quirks_v = *quirks;
  15898. break;
  15899. }
  15900. case RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT:
  15901. #ifdef HAVE_LIBNX
  15902. RARCH_LOG("[Environ]: SET_HW_SHARED_CONTEXT - ignored for now.\n");
  15903. /* TODO/FIXME - Force this off for now for Switch
  15904. * until shared HW context can work there */
  15905. return false;
  15906. #else
  15907. RARCH_LOG("[Environ]: SET_HW_SHARED_CONTEXT.\n");
  15908. p_rarch->core_set_shared_context = true;
  15909. #endif
  15910. break;
  15911. case RETRO_ENVIRONMENT_GET_VFS_INTERFACE:
  15912. {
  15913. const uint32_t supported_vfs_version = 3;
  15914. static struct retro_vfs_interface vfs_iface =
  15915. {
  15916. /* VFS API v1 */
  15917. retro_vfs_file_get_path_impl,
  15918. retro_vfs_file_open_impl,
  15919. retro_vfs_file_close_impl,
  15920. retro_vfs_file_size_impl,
  15921. retro_vfs_file_tell_impl,
  15922. retro_vfs_file_seek_impl,
  15923. retro_vfs_file_read_impl,
  15924. retro_vfs_file_write_impl,
  15925. retro_vfs_file_flush_impl,
  15926. retro_vfs_file_remove_impl,
  15927. retro_vfs_file_rename_impl,
  15928. /* VFS API v2 */
  15929. retro_vfs_file_truncate_impl,
  15930. /* VFS API v3 */
  15931. retro_vfs_stat_impl,
  15932. retro_vfs_mkdir_impl,
  15933. retro_vfs_opendir_impl,
  15934. retro_vfs_readdir_impl,
  15935. retro_vfs_dirent_get_name_impl,
  15936. retro_vfs_dirent_is_dir_impl,
  15937. retro_vfs_closedir_impl
  15938. };
  15939. struct retro_vfs_interface_info *vfs_iface_info = (struct retro_vfs_interface_info *) data;
  15940. if (vfs_iface_info->required_interface_version <= supported_vfs_version)
  15941. {
  15942. RARCH_LOG("Core requested VFS version >= v%d, providing v%d\n", vfs_iface_info->required_interface_version, supported_vfs_version);
  15943. vfs_iface_info->required_interface_version = supported_vfs_version;
  15944. vfs_iface_info->iface = &vfs_iface;
  15945. system->supports_vfs = true;
  15946. }
  15947. else
  15948. {
  15949. RARCH_WARN("Core requested VFS version v%d which is higher than what we support (v%d)\n", vfs_iface_info->required_interface_version, supported_vfs_version);
  15950. return false;
  15951. }
  15952. break;
  15953. }
  15954. case RETRO_ENVIRONMENT_GET_LED_INTERFACE:
  15955. {
  15956. struct retro_led_interface *ledintf =
  15957. (struct retro_led_interface *)data;
  15958. if (ledintf)
  15959. ledintf->set_led_state = led_driver_set_led;
  15960. }
  15961. break;
  15962. case RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE:
  15963. {
  15964. int result = 0;
  15965. if ( !p_rarch->audio_suspended &&
  15966. p_rarch->audio_driver_active)
  15967. result |= 2;
  15968. if (p_rarch->video_driver_active
  15969. && !(p_rarch->current_video->frame == video_null.frame))
  15970. result |= 1;
  15971. #ifdef HAVE_RUNAHEAD
  15972. if (p_rarch->request_fast_savestate)
  15973. result |= 4;
  15974. if (p_rarch->hard_disable_audio)
  15975. result |= 8;
  15976. #endif
  15977. #ifdef HAVE_NETWORKING
  15978. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_REPLAYING, NULL))
  15979. result &= ~(1|2);
  15980. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
  15981. result |= 4;
  15982. #endif
  15983. if (data)
  15984. {
  15985. int* result_p = (int*)data;
  15986. *result_p = result;
  15987. }
  15988. break;
  15989. }
  15990. case RETRO_ENVIRONMENT_GET_MIDI_INTERFACE:
  15991. {
  15992. struct retro_midi_interface *midi_interface =
  15993. (struct retro_midi_interface *)data;
  15994. if (midi_interface)
  15995. {
  15996. midi_interface->input_enabled = midi_driver_input_enabled;
  15997. midi_interface->output_enabled = midi_driver_output_enabled;
  15998. midi_interface->read = midi_driver_read;
  15999. midi_interface->write = midi_driver_write;
  16000. midi_interface->flush = midi_driver_flush;
  16001. }
  16002. break;
  16003. }
  16004. case RETRO_ENVIRONMENT_GET_FASTFORWARDING:
  16005. *(bool *)data = p_rarch->runloop_fastmotion;
  16006. break;
  16007. case RETRO_ENVIRONMENT_GET_INPUT_BITMASKS:
  16008. /* Just falldown, the function will return true */
  16009. break;
  16010. case RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION:
  16011. RARCH_LOG("[Environ]: GET_CORE_OPTIONS_VERSION.\n");
  16012. /* Current API version is 1 */
  16013. *(unsigned *)data = 1;
  16014. break;
  16015. case RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE:
  16016. {
  16017. /* Try to use the polled refresh rate first. */
  16018. float target_refresh_rate = video_driver_get_refresh_rate();
  16019. float video_refresh_rate = settings ? settings->floats.video_refresh_rate : 0.0;
  16020. /* If the above function failed [possibly because it is not
  16021. * implemented], use the refresh rate set in the config instead. */
  16022. if (target_refresh_rate == 0.0f && video_refresh_rate != 0.0f)
  16023. target_refresh_rate = video_refresh_rate;
  16024. *(float *)data = target_refresh_rate;
  16025. break;
  16026. }
  16027. case RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS:
  16028. *(unsigned *)data = p_rarch->input_driver_max_users;
  16029. break;
  16030. /* Private environment callbacks.
  16031. *
  16032. * Should all be properly addressed in version 2.
  16033. * */
  16034. case RETRO_ENVIRONMENT_POLL_TYPE_OVERRIDE:
  16035. {
  16036. const unsigned *poll_type_data = (const unsigned*)data;
  16037. if (poll_type_data)
  16038. p_rarch->core_poll_type_override = (enum poll_type_override_t)*poll_type_data;
  16039. }
  16040. break;
  16041. case RETRO_ENVIRONMENT_GET_CLEAR_ALL_THREAD_WAITS_CB:
  16042. *(retro_environment_t *)data = rarch_clear_all_thread_waits;
  16043. break;
  16044. case RETRO_ENVIRONMENT_SET_SAVE_STATE_IN_BACKGROUND:
  16045. {
  16046. bool state = *(const bool*)data;
  16047. RARCH_LOG("[Environ]: SET_SAVE_STATE_IN_BACKGROUND: %s.\n", state ? "yes" : "no");
  16048. set_save_state_in_background(state);
  16049. }
  16050. break;
  16051. default:
  16052. RARCH_LOG("[Environ]: UNSUPPORTED (#%u).\n", cmd);
  16053. return false;
  16054. }
  16055. return true;
  16056. }
  16057. #ifdef HAVE_DYNAMIC
  16058. /**
  16059. * libretro_get_environment_info:
  16060. * @func : Function pointer for get_environment_info.
  16061. * @load_no_content : If true, core should be able to auto-start
  16062. * without any content loaded.
  16063. *
  16064. * Sets environment callback in order to get statically known
  16065. * information from it.
  16066. *
  16067. * Fetched via environment callbacks instead of
  16068. * retro_get_system_info(), as this info is part of extensions.
  16069. *
  16070. * Should only be called once right after core load to
  16071. * avoid overwriting the "real" environ callback.
  16072. *
  16073. * For statically linked cores, pass retro_set_environment as argument.
  16074. */
  16075. static void libretro_get_environment_info(
  16076. void (*func)(retro_environment_t),
  16077. bool *load_no_content)
  16078. {
  16079. struct rarch_state *p_rarch = &rarch_st;
  16080. p_rarch->load_no_content_hook = load_no_content;
  16081. /* load_no_content gets set in this callback. */
  16082. func(environ_cb_get_system_info);
  16083. /* It's possible that we just set get_system_info callback
  16084. * to the currently running core.
  16085. *
  16086. * Make sure we reset it to the actual environment callback.
  16087. * Ignore any environment callbacks here in case we're running
  16088. * on the non-current core. */
  16089. p_rarch->ignore_environment_cb = true;
  16090. func(rarch_environment_cb);
  16091. p_rarch->ignore_environment_cb = false;
  16092. }
  16093. static dylib_t load_dynamic_core(
  16094. const char *path, char *buf, size_t size)
  16095. {
  16096. #if defined(ANDROID)
  16097. /* Can't resolve symlinks when dealing with cores
  16098. * installed via play feature delivery, because the
  16099. * source files have non-standard file names (which
  16100. * will not be recognised by regular core handling
  16101. * routines) */
  16102. bool resolve_symlinks = !play_feature_delivery_enabled();
  16103. #else
  16104. bool resolve_symlinks = true;
  16105. #endif
  16106. /* Can't lookup symbols in itself on UWP */
  16107. #if !(defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
  16108. if (dylib_proc(NULL, "retro_init"))
  16109. {
  16110. /* Try to verify that -lretro was not linked in from other modules
  16111. * since loading it dynamically and with -l will fail hard. */
  16112. RARCH_ERR("Serious problem. RetroArch wants to load libretro cores"
  16113. " dynamically, but it is already linked.\n");
  16114. RARCH_ERR("This could happen if other modules RetroArch depends on "
  16115. "link against libretro directly.\n");
  16116. RARCH_ERR("Proceeding could cause a crash. Aborting ...\n");
  16117. retroarch_fail(1, "init_libretro_symbols()");
  16118. }
  16119. #endif
  16120. /* Need to use absolute path for this setting. It can be
  16121. * saved to content history, and a relative path would
  16122. * break in that scenario. */
  16123. path_resolve_realpath(buf, size, resolve_symlinks);
  16124. return dylib_load(path);
  16125. }
  16126. static dylib_t libretro_get_system_info_lib(const char *path,
  16127. struct retro_system_info *info, bool *load_no_content)
  16128. {
  16129. dylib_t lib = dylib_load(path);
  16130. void (*proc)(struct retro_system_info*);
  16131. if (!lib)
  16132. return NULL;
  16133. proc = (void (*)(struct retro_system_info*))
  16134. dylib_proc(lib, "retro_get_system_info");
  16135. if (!proc)
  16136. {
  16137. dylib_close(lib);
  16138. return NULL;
  16139. }
  16140. proc(info);
  16141. if (load_no_content)
  16142. {
  16143. void (*set_environ)(retro_environment_t);
  16144. *load_no_content = false;
  16145. set_environ = (void (*)(retro_environment_t))
  16146. dylib_proc(lib, "retro_set_environment");
  16147. if (set_environ)
  16148. libretro_get_environment_info(set_environ, load_no_content);
  16149. }
  16150. return lib;
  16151. }
  16152. #endif
  16153. /**
  16154. * libretro_get_system_info:
  16155. * @path : Path to libretro library.
  16156. * @info : Pointer to system info information.
  16157. * @load_no_content : If true, core should be able to auto-start
  16158. * without any content loaded.
  16159. *
  16160. * Gets system info from an arbitrary lib.
  16161. * The struct returned must be freed as strings are allocated dynamically.
  16162. *
  16163. * Returns: true (1) if successful, otherwise false (0).
  16164. **/
  16165. static bool libretro_get_system_info(
  16166. struct rarch_state *p_rarch,
  16167. const char *path,
  16168. struct retro_system_info *info,
  16169. bool *load_no_content)
  16170. {
  16171. struct retro_system_info dummy_info;
  16172. #ifdef HAVE_DYNAMIC
  16173. dylib_t lib;
  16174. #endif
  16175. if (string_ends_with_size(path,
  16176. "builtin", strlen(path), STRLEN_CONST("builtin")))
  16177. return false;
  16178. dummy_info.library_name = NULL;
  16179. dummy_info.library_version = NULL;
  16180. dummy_info.valid_extensions = NULL;
  16181. dummy_info.need_fullpath = false;
  16182. dummy_info.block_extract = false;
  16183. #ifdef HAVE_DYNAMIC
  16184. lib = libretro_get_system_info_lib(
  16185. path, &dummy_info, load_no_content);
  16186. if (!lib)
  16187. {
  16188. RARCH_ERR("%s: \"%s\"\n",
  16189. msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE),
  16190. path);
  16191. RARCH_ERR("Error(s): %s\n", dylib_error());
  16192. return false;
  16193. }
  16194. #else
  16195. if (load_no_content)
  16196. {
  16197. p_rarch->load_no_content_hook = load_no_content;
  16198. /* load_no_content gets set in this callback. */
  16199. retro_set_environment(environ_cb_get_system_info);
  16200. /* It's possible that we just set get_system_info callback
  16201. * to the currently running core.
  16202. *
  16203. * Make sure we reset it to the actual environment callback.
  16204. * Ignore any environment callbacks here in case we're running
  16205. * on the non-current core. */
  16206. p_rarch->ignore_environment_cb = true;
  16207. retro_set_environment(rarch_environment_cb);
  16208. p_rarch->ignore_environment_cb = false;
  16209. }
  16210. retro_get_system_info(&dummy_info);
  16211. #endif
  16212. memcpy(info, &dummy_info, sizeof(*info));
  16213. p_rarch->current_library_name[0] = '\0';
  16214. p_rarch->current_library_version[0] = '\0';
  16215. p_rarch->current_valid_extensions[0] = '\0';
  16216. if (!string_is_empty(dummy_info.library_name))
  16217. strlcpy(p_rarch->current_library_name,
  16218. dummy_info.library_name, sizeof(p_rarch->current_library_name));
  16219. if (!string_is_empty(dummy_info.library_version))
  16220. strlcpy(p_rarch->current_library_version,
  16221. dummy_info.library_version, sizeof(p_rarch->current_library_version));
  16222. if (dummy_info.valid_extensions)
  16223. strlcpy(p_rarch->current_valid_extensions,
  16224. dummy_info.valid_extensions, sizeof(p_rarch->current_valid_extensions));
  16225. info->library_name = p_rarch->current_library_name;
  16226. info->library_version = p_rarch->current_library_version;
  16227. info->valid_extensions = p_rarch->current_valid_extensions;
  16228. #ifdef HAVE_DYNAMIC
  16229. dylib_close(lib);
  16230. #endif
  16231. return true;
  16232. }
  16233. /**
  16234. * load_symbols:
  16235. * @type : Type of core to be loaded.
  16236. * If CORE_TYPE_DUMMY, will
  16237. * load dummy symbols.
  16238. *
  16239. * Setup libretro callback symbols. Returns true on success,
  16240. * or false if symbols could not be loaded.
  16241. **/
  16242. static bool init_libretro_symbols_custom(
  16243. struct rarch_state *p_rarch,
  16244. enum rarch_core_type type,
  16245. struct retro_core_t *current_core,
  16246. const char *lib_path,
  16247. void *_lib_handle_p)
  16248. {
  16249. #ifdef HAVE_DYNAMIC
  16250. /* the library handle for use with the SYMBOL macro */
  16251. dylib_t lib_handle_local;
  16252. #endif
  16253. switch (type)
  16254. {
  16255. case CORE_TYPE_PLAIN:
  16256. {
  16257. #ifdef HAVE_DYNAMIC
  16258. #ifdef HAVE_RUNAHEAD
  16259. dylib_t *lib_handle_p = (dylib_t*)_lib_handle_p;
  16260. if (!lib_path || !lib_handle_p)
  16261. #endif
  16262. {
  16263. const char *path = path_get(RARCH_PATH_CORE);
  16264. if (string_is_empty(path))
  16265. {
  16266. RARCH_ERR("[Core]: Frontend is built for dynamic libretro cores, but "
  16267. "path is not set. Cannot continue.\n");
  16268. retroarch_fail(1, "init_libretro_symbols()");
  16269. }
  16270. RARCH_LOG("[Core]: Loading dynamic libretro core from: \"%s\"\n",
  16271. path);
  16272. if (!(p_rarch->lib_handle = load_dynamic_core(
  16273. path,
  16274. path_get_ptr(RARCH_PATH_CORE),
  16275. path_get_realsize(RARCH_PATH_CORE)
  16276. )))
  16277. {
  16278. RARCH_ERR("%s: \"%s\"\nError(s): %s\n",
  16279. msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE),
  16280. path, dylib_error());
  16281. runloop_msg_queue_push(msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE),
  16282. 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  16283. return false;
  16284. }
  16285. lib_handle_local = p_rarch->lib_handle;
  16286. }
  16287. #ifdef HAVE_RUNAHEAD
  16288. else
  16289. {
  16290. /* for a secondary core, we already have a
  16291. * primary library loaded, so we can skip
  16292. * some checks and just load the library */
  16293. retro_assert(lib_path != NULL && lib_handle_p != NULL);
  16294. lib_handle_local = dylib_load(lib_path);
  16295. if (!lib_handle_local)
  16296. return false;
  16297. *lib_handle_p = lib_handle_local;
  16298. }
  16299. #endif
  16300. #endif
  16301. CORE_SYMBOLS(SYMBOL);
  16302. }
  16303. break;
  16304. case CORE_TYPE_DUMMY:
  16305. CORE_SYMBOLS(SYMBOL_DUMMY);
  16306. break;
  16307. case CORE_TYPE_FFMPEG:
  16308. #ifdef HAVE_FFMPEG
  16309. CORE_SYMBOLS(SYMBOL_FFMPEG);
  16310. #endif
  16311. break;
  16312. case CORE_TYPE_MPV:
  16313. #ifdef HAVE_MPV
  16314. CORE_SYMBOLS(SYMBOL_MPV);
  16315. #endif
  16316. break;
  16317. case CORE_TYPE_IMAGEVIEWER:
  16318. #ifdef HAVE_IMAGEVIEWER
  16319. CORE_SYMBOLS(SYMBOL_IMAGEVIEWER);
  16320. #endif
  16321. break;
  16322. case CORE_TYPE_NETRETROPAD:
  16323. #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD)
  16324. CORE_SYMBOLS(SYMBOL_NETRETROPAD);
  16325. #endif
  16326. break;
  16327. case CORE_TYPE_VIDEO_PROCESSOR:
  16328. #if defined(HAVE_VIDEOPROCESSOR)
  16329. CORE_SYMBOLS(SYMBOL_VIDEOPROCESSOR);
  16330. #endif
  16331. break;
  16332. case CORE_TYPE_GONG:
  16333. #ifdef HAVE_GONG
  16334. CORE_SYMBOLS(SYMBOL_GONG);
  16335. #endif
  16336. break;
  16337. }
  16338. return true;
  16339. }
  16340. /**
  16341. * init_libretro_symbols:
  16342. * @type : Type of core to be loaded.
  16343. * If CORE_TYPE_DUMMY, will
  16344. * load dummy symbols.
  16345. *
  16346. * Initializes libretro symbols and
  16347. * setups environment callback functions. Returns true on success,
  16348. * or false if symbols could not be loaded.
  16349. **/
  16350. static bool init_libretro_symbols(
  16351. struct rarch_state *p_rarch,
  16352. enum rarch_core_type type,
  16353. struct retro_core_t *current_core)
  16354. {
  16355. /* Load symbols */
  16356. if (!init_libretro_symbols_custom(p_rarch,
  16357. type, current_core, NULL, NULL))
  16358. return false;
  16359. #ifdef HAVE_RUNAHEAD
  16360. /* remember last core type created, so creating a
  16361. * secondary core will know what core type to use. */
  16362. p_rarch->last_core_type = type;
  16363. #endif
  16364. return true;
  16365. }
  16366. bool libretro_get_shared_context(void)
  16367. {
  16368. struct rarch_state *p_rarch = &rarch_st;
  16369. bool core_set_shared_context = p_rarch->core_set_shared_context;
  16370. return core_set_shared_context;
  16371. }
  16372. /**
  16373. * uninit_libretro_sym:
  16374. *
  16375. * Frees libretro core.
  16376. *
  16377. * Frees all core options,
  16378. * associated state, and
  16379. * unbind all libretro callback symbols.
  16380. **/
  16381. static void uninit_libretro_symbols(
  16382. struct rarch_state *p_rarch,
  16383. struct retro_core_t *current_core)
  16384. {
  16385. #ifdef HAVE_DYNAMIC
  16386. if (p_rarch->lib_handle)
  16387. dylib_close(p_rarch->lib_handle);
  16388. p_rarch->lib_handle = NULL;
  16389. #endif
  16390. memset(current_core, 0, sizeof(struct retro_core_t));
  16391. p_rarch->core_set_shared_context = false;
  16392. if (p_rarch->runloop_core_options)
  16393. retroarch_deinit_core_options(p_rarch);
  16394. retroarch_system_info_free(p_rarch);
  16395. retroarch_frame_time_free(p_rarch);
  16396. retroarch_audio_buffer_status_free(p_rarch);
  16397. retroarch_game_focus_free(p_rarch);
  16398. p_rarch->camera_driver_active = false;
  16399. p_rarch->location_driver_active = false;
  16400. /* Performance counters no longer valid. */
  16401. p_rarch->perf_ptr_libretro = 0;
  16402. memset(p_rarch->perf_counters_libretro, 0,
  16403. sizeof(p_rarch->perf_counters_libretro));
  16404. }
  16405. #if defined(HAVE_RUNAHEAD)
  16406. static void free_retro_ctx_load_content_info(struct
  16407. retro_ctx_load_content_info *dest)
  16408. {
  16409. if (!dest)
  16410. return;
  16411. core_free_retro_game_info(dest->info);
  16412. string_list_free((struct string_list*)dest->content);
  16413. if (dest->info)
  16414. free(dest->info);
  16415. dest->info = NULL;
  16416. dest->content = NULL;
  16417. }
  16418. static struct retro_game_info* clone_retro_game_info(const
  16419. struct retro_game_info *src)
  16420. {
  16421. struct retro_game_info *dest = (struct retro_game_info*)malloc(
  16422. sizeof(struct retro_game_info));
  16423. if (!dest)
  16424. return NULL;
  16425. dest->path = NULL;
  16426. dest->data = NULL;
  16427. dest->size = 0;
  16428. dest->meta = NULL;
  16429. if (src->size && src->data)
  16430. {
  16431. void *data = malloc(src->size);
  16432. if (data)
  16433. {
  16434. memcpy(data, src->data, src->size);
  16435. dest->data = data;
  16436. }
  16437. }
  16438. if (!string_is_empty(src->path))
  16439. dest->path = strdup(src->path);
  16440. if (!string_is_empty(src->meta))
  16441. dest->meta = strdup(src->meta);
  16442. dest->size = src->size;
  16443. return dest;
  16444. }
  16445. static struct retro_ctx_load_content_info
  16446. *clone_retro_ctx_load_content_info(
  16447. const struct retro_ctx_load_content_info *src)
  16448. {
  16449. struct retro_ctx_load_content_info *dest = NULL;
  16450. if (!src || src->special)
  16451. return NULL; /* refuse to deal with the Special field */
  16452. dest = (struct retro_ctx_load_content_info*)
  16453. malloc(sizeof(*dest));
  16454. if (!dest)
  16455. return NULL;
  16456. dest->info = NULL;
  16457. dest->content = NULL;
  16458. dest->special = NULL;
  16459. if (src->info)
  16460. dest->info = clone_retro_game_info(src->info);
  16461. if (src->content)
  16462. dest->content = string_list_clone(src->content);
  16463. return dest;
  16464. }
  16465. static void set_load_content_info(
  16466. struct rarch_state *p_rarch,
  16467. const retro_ctx_load_content_info_t *ctx)
  16468. {
  16469. free_retro_ctx_load_content_info(p_rarch->load_content_info);
  16470. free(p_rarch->load_content_info);
  16471. p_rarch->load_content_info = clone_retro_ctx_load_content_info(ctx);
  16472. }
  16473. /* RUNAHEAD - SECONDARY CORE */
  16474. #if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
  16475. static void strcat_alloc(char **dst, const char *s)
  16476. {
  16477. size_t len1;
  16478. char *src = *dst;
  16479. if (!src)
  16480. {
  16481. src = (s) ? strcpy_alloc(s) : (char*)calloc(1,1);
  16482. *dst = src;
  16483. return;
  16484. }
  16485. if (!s)
  16486. return;
  16487. len1 = strlen(src);
  16488. src = (char*)realloc(src, len1 + strlen(s) + 1);
  16489. if (!src)
  16490. return;
  16491. *dst = src;
  16492. strcpy(src + len1, s);
  16493. }
  16494. static void secondary_core_destroy(struct rarch_state *p_rarch)
  16495. {
  16496. if (!p_rarch || !p_rarch->secondary_lib_handle)
  16497. return;
  16498. /* unload game from core */
  16499. if (p_rarch->secondary_core.retro_unload_game)
  16500. p_rarch->secondary_core.retro_unload_game();
  16501. p_rarch->core_poll_type_override = POLL_TYPE_OVERRIDE_DONTCARE;
  16502. /* deinit */
  16503. if (p_rarch->secondary_core.retro_deinit)
  16504. p_rarch->secondary_core.retro_deinit();
  16505. memset(&p_rarch->secondary_core, 0, sizeof(struct retro_core_t));
  16506. dylib_close(p_rarch->secondary_lib_handle);
  16507. p_rarch->secondary_lib_handle = NULL;
  16508. filestream_delete(p_rarch->secondary_library_path);
  16509. if (p_rarch->secondary_library_path)
  16510. free(p_rarch->secondary_library_path);
  16511. p_rarch->secondary_library_path = NULL;
  16512. }
  16513. static bool secondary_core_ensure_exists(struct rarch_state *p_rarch)
  16514. {
  16515. if (!p_rarch->secondary_lib_handle)
  16516. if (!secondary_core_create(p_rarch))
  16517. return false;
  16518. return true;
  16519. }
  16520. #if defined(HAVE_RUNAHEAD) && defined(HAVE_DYNAMIC)
  16521. static bool secondary_core_deserialize(
  16522. struct rarch_state *p_rarch,
  16523. const void *buffer, int size)
  16524. {
  16525. if (secondary_core_ensure_exists(p_rarch))
  16526. return p_rarch->secondary_core.retro_unserialize(buffer, size);
  16527. secondary_core_destroy(p_rarch);
  16528. return false;
  16529. }
  16530. #endif
  16531. static void remember_controller_port_device(
  16532. struct rarch_state *p_rarch,
  16533. long port, long device)
  16534. {
  16535. if (port >= 0 && port < MAX_USERS)
  16536. p_rarch->port_map[port] = (int)device;
  16537. if ( p_rarch->secondary_lib_handle
  16538. && p_rarch->secondary_core.retro_set_controller_port_device)
  16539. p_rarch->secondary_core.retro_set_controller_port_device((unsigned)port, (unsigned)device);
  16540. }
  16541. static void clear_controller_port_map(struct rarch_state *p_rarch)
  16542. {
  16543. unsigned port;
  16544. for (port = 0; port < MAX_USERS; port++)
  16545. p_rarch->port_map[port] = -1;
  16546. }
  16547. static char *get_temp_directory_alloc(const char *override_dir)
  16548. {
  16549. const char *src = NULL;
  16550. char *path = NULL;
  16551. #ifdef _WIN32
  16552. #ifdef LEGACY_WIN32
  16553. DWORD plen = GetTempPath(0, NULL) + 1;
  16554. if (!(path = (char*)malloc(plen * sizeof(char))))
  16555. return NULL;
  16556. path[plen - 1] = 0;
  16557. GetTempPath(plen, path);
  16558. #else
  16559. DWORD plen = GetTempPathW(0, NULL) + 1;
  16560. wchar_t *wide_str = (wchar_t*)malloc(plen * sizeof(wchar_t));
  16561. if (!wide_str)
  16562. return NULL;
  16563. wide_str[plen - 1] = 0;
  16564. GetTempPathW(plen, wide_str);
  16565. path = utf16_to_utf8_string_alloc(wide_str);
  16566. free(wide_str);
  16567. #endif
  16568. #else
  16569. #if defined ANDROID
  16570. src = override_dir;
  16571. #else
  16572. {
  16573. char *tmpdir = getenv("TMPDIR");
  16574. if (tmpdir)
  16575. src = tmpdir;
  16576. else
  16577. src = "/tmp";
  16578. }
  16579. #endif
  16580. path = (src) ? strcpy_alloc(src) : (char*)calloc(1,1);
  16581. #endif
  16582. return path;
  16583. }
  16584. static bool write_file_with_random_name(char **temp_dll_path,
  16585. const char *retroarch_temp_path, const void* data, ssize_t dataSize)
  16586. {
  16587. unsigned i;
  16588. char number_buf[32];
  16589. bool okay = false;
  16590. const char *prefix = "tmp";
  16591. time_t time_value = time(NULL);
  16592. unsigned number_value = (unsigned)time_value;
  16593. const char *src = path_get_extension(*temp_dll_path);
  16594. char *ext = (src) ? strcpy_alloc(src) : (char*)calloc(1,1);
  16595. int ext_len = (int)strlen(ext);
  16596. if (ext_len > 0)
  16597. {
  16598. strcat_alloc(&ext, ".");
  16599. memmove(ext + 1, ext, ext_len);
  16600. ext[0] = '.';
  16601. ext_len++;
  16602. }
  16603. /* Try up to 30 'random' filenames before giving up */
  16604. for (i = 0; i < 30; i++)
  16605. {
  16606. int number;
  16607. number_value = number_value * 214013 + 2531011;
  16608. number = (number_value >> 14) % 100000;
  16609. snprintf(number_buf, sizeof(number_buf), "%05d", number);
  16610. if (*temp_dll_path)
  16611. free(*temp_dll_path);
  16612. *temp_dll_path = NULL;
  16613. strcat_alloc(temp_dll_path, retroarch_temp_path);
  16614. strcat_alloc(temp_dll_path, prefix);
  16615. strcat_alloc(temp_dll_path, number_buf);
  16616. strcat_alloc(temp_dll_path, ext);
  16617. if (filestream_write_file(*temp_dll_path, data, dataSize))
  16618. {
  16619. okay = true;
  16620. break;
  16621. }
  16622. }
  16623. if (ext)
  16624. free(ext);
  16625. ext = NULL;
  16626. return okay;
  16627. }
  16628. static char *copy_core_to_temp_file(struct rarch_state *p_rarch)
  16629. {
  16630. bool failed = false;
  16631. char *temp_directory = NULL;
  16632. char *retroarch_temp_path = NULL;
  16633. char *temp_dll_path = NULL;
  16634. void *dll_file_data = NULL;
  16635. int64_t dll_file_size = 0;
  16636. const char *core_path = path_get(RARCH_PATH_CORE);
  16637. const char *core_base_name = path_basename(core_path);
  16638. settings_t *settings = p_rarch->configuration_settings;
  16639. const char *dir_libretro = settings->paths.directory_libretro;
  16640. if (strlen(core_base_name) == 0)
  16641. return NULL;
  16642. temp_directory = get_temp_directory_alloc(dir_libretro);
  16643. if (!temp_directory)
  16644. return NULL;
  16645. strcat_alloc(&retroarch_temp_path, temp_directory);
  16646. strcat_alloc(&retroarch_temp_path, PATH_DEFAULT_SLASH());
  16647. strcat_alloc(&retroarch_temp_path, "retroarch_temp");
  16648. strcat_alloc(&retroarch_temp_path, PATH_DEFAULT_SLASH());
  16649. if (!path_mkdir(retroarch_temp_path))
  16650. {
  16651. failed = true;
  16652. goto end;
  16653. }
  16654. if (!filestream_read_file(core_path, &dll_file_data, &dll_file_size))
  16655. {
  16656. failed = true;
  16657. goto end;
  16658. }
  16659. strcat_alloc(&temp_dll_path, retroarch_temp_path);
  16660. strcat_alloc(&temp_dll_path, core_base_name);
  16661. if (!filestream_write_file(temp_dll_path, dll_file_data, dll_file_size))
  16662. {
  16663. /* try other file names */
  16664. if (!write_file_with_random_name(&temp_dll_path,
  16665. retroarch_temp_path, dll_file_data, dll_file_size))
  16666. failed = true;
  16667. }
  16668. end:
  16669. if (temp_directory)
  16670. free(temp_directory);
  16671. if (retroarch_temp_path)
  16672. free(retroarch_temp_path);
  16673. if (dll_file_data)
  16674. free(dll_file_data);
  16675. temp_directory = NULL;
  16676. retroarch_temp_path = NULL;
  16677. dll_file_data = NULL;
  16678. if (!failed)
  16679. return temp_dll_path;
  16680. if (temp_dll_path)
  16681. free(temp_dll_path);
  16682. temp_dll_path = NULL;
  16683. return NULL;
  16684. }
  16685. static bool rarch_environment_secondary_core_hook(
  16686. unsigned cmd, void *data)
  16687. {
  16688. struct rarch_state *p_rarch = &rarch_st;
  16689. bool result = rarch_environment_cb(cmd, data);
  16690. if (p_rarch->has_variable_update)
  16691. {
  16692. if (cmd == RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE)
  16693. {
  16694. bool *bool_p = (bool*)data;
  16695. *bool_p = true;
  16696. p_rarch->has_variable_update = false;
  16697. return true;
  16698. }
  16699. else if (cmd == RETRO_ENVIRONMENT_GET_VARIABLE)
  16700. p_rarch->has_variable_update = false;
  16701. }
  16702. return result;
  16703. }
  16704. static bool secondary_core_create(struct rarch_state *p_rarch)
  16705. {
  16706. unsigned port;
  16707. bool contentless = false;
  16708. bool is_inited = false;
  16709. const enum rarch_core_type
  16710. last_core_type = p_rarch->last_core_type;
  16711. rarch_system_info_t *info = &p_rarch->runloop_system;
  16712. unsigned num_active_users = p_rarch->input_driver_max_users;
  16713. if ( last_core_type != CORE_TYPE_PLAIN ||
  16714. !p_rarch->load_content_info ||
  16715. p_rarch->load_content_info->special)
  16716. return false;
  16717. if (p_rarch->secondary_library_path)
  16718. free(p_rarch->secondary_library_path);
  16719. p_rarch->secondary_library_path = NULL;
  16720. p_rarch->secondary_library_path = copy_core_to_temp_file(p_rarch);
  16721. if (!p_rarch->secondary_library_path)
  16722. return false;
  16723. /* Load Core */
  16724. if (!init_libretro_symbols_custom(p_rarch,
  16725. CORE_TYPE_PLAIN, &p_rarch->secondary_core,
  16726. p_rarch->secondary_library_path,
  16727. &p_rarch->secondary_lib_handle))
  16728. return false;
  16729. p_rarch->secondary_core.symbols_inited = true;
  16730. p_rarch->secondary_core.retro_set_environment(
  16731. rarch_environment_secondary_core_hook);
  16732. #ifdef HAVE_RUNAHEAD
  16733. p_rarch->has_variable_update = true;
  16734. #endif
  16735. p_rarch->secondary_core.retro_init();
  16736. content_get_status(&contentless, &is_inited);
  16737. p_rarch->secondary_core.inited = is_inited;
  16738. /* Load Content */
  16739. /* disabled due to crashes */
  16740. if ( !p_rarch->load_content_info ||
  16741. p_rarch->load_content_info->special)
  16742. return false;
  16743. if ( (p_rarch->load_content_info->content->size > 0) &&
  16744. p_rarch->load_content_info->content->elems[0].data)
  16745. {
  16746. p_rarch->secondary_core.game_loaded = p_rarch->secondary_core.retro_load_game(
  16747. p_rarch->load_content_info->info);
  16748. if (!p_rarch->secondary_core.game_loaded)
  16749. goto error;
  16750. }
  16751. else if (contentless)
  16752. {
  16753. p_rarch->secondary_core.game_loaded = p_rarch->secondary_core.retro_load_game(NULL);
  16754. if (!p_rarch->secondary_core.game_loaded)
  16755. goto error;
  16756. }
  16757. else
  16758. p_rarch->secondary_core.game_loaded = false;
  16759. if (!p_rarch->secondary_core.inited)
  16760. goto error;
  16761. core_set_default_callbacks(&p_rarch->secondary_callbacks);
  16762. p_rarch->secondary_core.retro_set_video_refresh(p_rarch->secondary_callbacks.frame_cb);
  16763. p_rarch->secondary_core.retro_set_audio_sample(p_rarch->secondary_callbacks.sample_cb);
  16764. p_rarch->secondary_core.retro_set_audio_sample_batch(p_rarch->secondary_callbacks.sample_batch_cb);
  16765. p_rarch->secondary_core.retro_set_input_state(p_rarch->secondary_callbacks.state_cb);
  16766. p_rarch->secondary_core.retro_set_input_poll(p_rarch->secondary_callbacks.poll_cb);
  16767. if (info)
  16768. for (port = 0; port < MAX_USERS; port++)
  16769. {
  16770. if (port < info->ports.size)
  16771. {
  16772. unsigned device = (port < num_active_users) ?
  16773. p_rarch->port_map[port] : RETRO_DEVICE_NONE;
  16774. p_rarch->secondary_core.retro_set_controller_port_device(
  16775. port, device);
  16776. }
  16777. }
  16778. clear_controller_port_map(p_rarch);
  16779. return true;
  16780. error:
  16781. secondary_core_destroy(p_rarch);
  16782. return false;
  16783. }
  16784. static void secondary_core_input_poll_null(void) { }
  16785. static bool secondary_core_run_use_last_input(struct rarch_state *p_rarch)
  16786. {
  16787. retro_input_poll_t old_poll_function;
  16788. retro_input_state_t old_input_function;
  16789. if (!secondary_core_ensure_exists(p_rarch))
  16790. {
  16791. secondary_core_destroy(p_rarch);
  16792. return false;
  16793. }
  16794. old_poll_function = p_rarch->secondary_callbacks.poll_cb;
  16795. old_input_function = p_rarch->secondary_callbacks.state_cb;
  16796. p_rarch->secondary_callbacks.poll_cb = secondary_core_input_poll_null;
  16797. p_rarch->secondary_callbacks.state_cb = input_state_get_last;
  16798. p_rarch->secondary_core.retro_set_input_poll(p_rarch->secondary_callbacks.poll_cb);
  16799. p_rarch->secondary_core.retro_set_input_state(p_rarch->secondary_callbacks.state_cb);
  16800. p_rarch->secondary_core.retro_run();
  16801. p_rarch->secondary_callbacks.poll_cb = old_poll_function;
  16802. p_rarch->secondary_callbacks.state_cb = old_input_function;
  16803. p_rarch->secondary_core.retro_set_input_poll(p_rarch->secondary_callbacks.poll_cb);
  16804. p_rarch->secondary_core.retro_set_input_state(p_rarch->secondary_callbacks.state_cb);
  16805. return true;
  16806. }
  16807. #else
  16808. static void secondary_core_destroy(struct rarch_state *p_rarch) { }
  16809. static void remember_controller_port_device(
  16810. struct rarch_state *p_rarch,
  16811. long port, long device) { }
  16812. static void clear_controller_port_map(struct rarch_state *p_rarch) { }
  16813. #endif
  16814. #endif
  16815. /* BLUETOOTH DRIVER */
  16816. /**
  16817. * config_get_bluetooth_driver_options:
  16818. *
  16819. * Get an enumerated list of all bluetooth driver names,
  16820. * separated by '|'.
  16821. *
  16822. * Returns: string listing of all bluetooth driver names,
  16823. * separated by '|'.
  16824. **/
  16825. const char* config_get_bluetooth_driver_options(void)
  16826. {
  16827. return char_list_new_special(STRING_LIST_BLUETOOTH_DRIVERS, NULL);
  16828. }
  16829. void driver_bluetooth_scan(void)
  16830. {
  16831. struct rarch_state *p_rarch = &rarch_st;
  16832. if ( (p_rarch->bluetooth_driver_active) &&
  16833. (p_rarch->bluetooth_driver->scan) )
  16834. p_rarch->bluetooth_driver->scan(p_rarch->bluetooth_data);
  16835. }
  16836. void driver_bluetooth_get_devices(struct string_list* devices)
  16837. {
  16838. struct rarch_state *p_rarch = &rarch_st;
  16839. if ( (p_rarch->bluetooth_driver_active) &&
  16840. (p_rarch->bluetooth_driver->get_devices) )
  16841. p_rarch->bluetooth_driver->get_devices(p_rarch->bluetooth_data, devices);
  16842. }
  16843. bool driver_bluetooth_device_is_connected(unsigned i)
  16844. {
  16845. struct rarch_state *p_rarch = &rarch_st;
  16846. if ( (p_rarch->bluetooth_driver_active) &&
  16847. (p_rarch->bluetooth_driver->device_is_connected) )
  16848. return p_rarch->bluetooth_driver->device_is_connected(p_rarch->bluetooth_data, i);
  16849. return false;
  16850. }
  16851. void driver_bluetooth_device_get_sublabel(char *s, unsigned i, size_t len)
  16852. {
  16853. struct rarch_state *p_rarch = &rarch_st;
  16854. if ( (p_rarch->bluetooth_driver_active) &&
  16855. (p_rarch->bluetooth_driver->device_get_sublabel) )
  16856. p_rarch->bluetooth_driver->device_get_sublabel(p_rarch->bluetooth_data, s, i, len);
  16857. }
  16858. bool driver_bluetooth_connect_device(unsigned i)
  16859. {
  16860. struct rarch_state *p_rarch = &rarch_st;
  16861. if (p_rarch->bluetooth_driver_active)
  16862. return p_rarch->bluetooth_driver->connect_device(p_rarch->bluetooth_data, i);
  16863. return false;
  16864. }
  16865. bool bluetooth_driver_ctl(enum rarch_bluetooth_ctl_state state, void *data)
  16866. {
  16867. struct rarch_state *p_rarch = &rarch_st;
  16868. settings_t *settings = p_rarch->configuration_settings;
  16869. switch (state)
  16870. {
  16871. case RARCH_BLUETOOTH_CTL_DESTROY:
  16872. p_rarch->bluetooth_driver = NULL;
  16873. p_rarch->bluetooth_data = NULL;
  16874. p_rarch->bluetooth_driver_active = false;
  16875. break;
  16876. case RARCH_BLUETOOTH_CTL_FIND_DRIVER:
  16877. {
  16878. int i = (int)driver_find_index(
  16879. "bluetooth_driver",
  16880. settings->arrays.bluetooth_driver);
  16881. if (i >= 0)
  16882. p_rarch->bluetooth_driver = (const bluetooth_driver_t*)bluetooth_drivers[i];
  16883. else
  16884. {
  16885. if (verbosity_is_enabled())
  16886. {
  16887. unsigned d;
  16888. RARCH_ERR("Couldn't find any bluetooth driver named \"%s\"\n",
  16889. settings->arrays.bluetooth_driver);
  16890. RARCH_LOG_OUTPUT("Available bluetooth drivers are:\n");
  16891. for (d = 0; bluetooth_drivers[d]; d++)
  16892. RARCH_LOG_OUTPUT("\t%s\n", bluetooth_drivers[d]->ident);
  16893. RARCH_WARN("Going to default to first bluetooth driver...\n");
  16894. }
  16895. p_rarch->bluetooth_driver = (const bluetooth_driver_t*)bluetooth_drivers[0];
  16896. if (!p_rarch->bluetooth_driver)
  16897. retroarch_fail(1, "find_bluetooth_driver()");
  16898. }
  16899. }
  16900. break;
  16901. case RARCH_BLUETOOTH_CTL_DEINIT:
  16902. if (p_rarch->bluetooth_data && p_rarch->bluetooth_driver)
  16903. {
  16904. if (p_rarch->bluetooth_driver->free)
  16905. p_rarch->bluetooth_driver->free(p_rarch->bluetooth_data);
  16906. }
  16907. p_rarch->bluetooth_data = NULL;
  16908. p_rarch->bluetooth_driver_active = false;
  16909. break;
  16910. case RARCH_BLUETOOTH_CTL_INIT:
  16911. /* Resource leaks will follow if bluetooth is initialized twice. */
  16912. if (p_rarch->bluetooth_data)
  16913. return false;
  16914. bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_FIND_DRIVER, NULL);
  16915. if (p_rarch->bluetooth_driver && p_rarch->bluetooth_driver->init)
  16916. {
  16917. p_rarch->bluetooth_driver_active = true;
  16918. p_rarch->bluetooth_data = p_rarch->bluetooth_driver->init();
  16919. if (!p_rarch->bluetooth_data)
  16920. {
  16921. RARCH_ERR("Failed to initialize bluetooth driver. Will continue without bluetooth.\n");
  16922. p_rarch->bluetooth_driver_active = false;
  16923. }
  16924. } else {
  16925. p_rarch->bluetooth_driver_active = false;
  16926. }
  16927. break;
  16928. default:
  16929. break;
  16930. }
  16931. return false;
  16932. }
  16933. /* WIFI DRIVER */
  16934. /**
  16935. * config_get_wifi_driver_options:
  16936. *
  16937. * Get an enumerated list of all wifi driver names,
  16938. * separated by '|'.
  16939. *
  16940. * Returns: string listing of all wifi driver names,
  16941. * separated by '|'.
  16942. **/
  16943. const char* config_get_wifi_driver_options(void)
  16944. {
  16945. return char_list_new_special(STRING_LIST_WIFI_DRIVERS, NULL);
  16946. }
  16947. void driver_wifi_scan(void)
  16948. {
  16949. struct rarch_state *p_rarch = &rarch_st;
  16950. p_rarch->wifi_driver->scan(p_rarch->wifi_data);
  16951. }
  16952. bool driver_wifi_enable(bool enabled)
  16953. {
  16954. struct rarch_state *p_rarch = &rarch_st;
  16955. return p_rarch->wifi_driver->enable(p_rarch->wifi_data, enabled);
  16956. }
  16957. bool driver_wifi_connection_info(wifi_network_info_t *netinfo)
  16958. {
  16959. struct rarch_state *p_rarch = &rarch_st;
  16960. return p_rarch->wifi_driver->connection_info(p_rarch->wifi_data, netinfo);
  16961. }
  16962. wifi_network_scan_t* driver_wifi_get_ssids()
  16963. {
  16964. struct rarch_state *p_rarch = &rarch_st;
  16965. return p_rarch->wifi_driver->get_ssids(p_rarch->wifi_data);
  16966. }
  16967. bool driver_wifi_ssid_is_online(unsigned i)
  16968. {
  16969. struct rarch_state *p_rarch = &rarch_st;
  16970. return p_rarch->wifi_driver->ssid_is_online(p_rarch->wifi_data, i);
  16971. }
  16972. bool driver_wifi_connect_ssid(const wifi_network_info_t* net)
  16973. {
  16974. struct rarch_state *p_rarch = &rarch_st;
  16975. return p_rarch->wifi_driver->connect_ssid(p_rarch->wifi_data, net);
  16976. }
  16977. bool driver_wifi_disconnect_ssid(const wifi_network_info_t* net)
  16978. {
  16979. struct rarch_state *p_rarch = &rarch_st;
  16980. return p_rarch->wifi_driver->disconnect_ssid(p_rarch->wifi_data, net);
  16981. }
  16982. void driver_wifi_tether_start_stop(bool start, char* configfile)
  16983. {
  16984. struct rarch_state *p_rarch = &rarch_st;
  16985. p_rarch->wifi_driver->tether_start_stop(p_rarch->wifi_data, start, configfile);
  16986. }
  16987. bool wifi_driver_ctl(enum rarch_wifi_ctl_state state, void *data)
  16988. {
  16989. struct rarch_state *p_rarch = &rarch_st;
  16990. settings_t *settings = p_rarch->configuration_settings;
  16991. switch (state)
  16992. {
  16993. case RARCH_WIFI_CTL_DESTROY:
  16994. p_rarch->wifi_driver_active = false;
  16995. p_rarch->wifi_driver = NULL;
  16996. p_rarch->wifi_data = NULL;
  16997. break;
  16998. case RARCH_WIFI_CTL_SET_ACTIVE:
  16999. p_rarch->wifi_driver_active = true;
  17000. break;
  17001. case RARCH_WIFI_CTL_FIND_DRIVER:
  17002. {
  17003. int i = (int)driver_find_index(
  17004. "wifi_driver",
  17005. settings->arrays.wifi_driver);
  17006. if (i >= 0)
  17007. p_rarch->wifi_driver = (const wifi_driver_t*)wifi_drivers[i];
  17008. else
  17009. {
  17010. if (verbosity_is_enabled())
  17011. {
  17012. unsigned d;
  17013. RARCH_ERR("Couldn't find any wifi driver named \"%s\"\n",
  17014. settings->arrays.wifi_driver);
  17015. RARCH_LOG_OUTPUT("Available wifi drivers are:\n");
  17016. for (d = 0; wifi_drivers[d]; d++)
  17017. RARCH_LOG_OUTPUT("\t%s\n", wifi_drivers[d]->ident);
  17018. RARCH_WARN("Going to default to first wifi driver...\n");
  17019. }
  17020. p_rarch->wifi_driver = (const wifi_driver_t*)wifi_drivers[0];
  17021. if (!p_rarch->wifi_driver)
  17022. retroarch_fail(1, "find_wifi_driver()");
  17023. }
  17024. }
  17025. break;
  17026. case RARCH_WIFI_CTL_UNSET_ACTIVE:
  17027. p_rarch->wifi_driver_active = false;
  17028. break;
  17029. case RARCH_WIFI_CTL_IS_ACTIVE:
  17030. return p_rarch->wifi_driver_active;
  17031. case RARCH_WIFI_CTL_DEINIT:
  17032. if (p_rarch->wifi_data && p_rarch->wifi_driver)
  17033. {
  17034. if (p_rarch->wifi_driver->free)
  17035. p_rarch->wifi_driver->free(p_rarch->wifi_data);
  17036. }
  17037. p_rarch->wifi_data = NULL;
  17038. break;
  17039. case RARCH_WIFI_CTL_STOP:
  17040. if ( p_rarch->wifi_driver
  17041. && p_rarch->wifi_driver->stop
  17042. && p_rarch->wifi_data)
  17043. p_rarch->wifi_driver->stop(p_rarch->wifi_data);
  17044. break;
  17045. case RARCH_WIFI_CTL_START:
  17046. if ( p_rarch->wifi_driver
  17047. && p_rarch->wifi_data
  17048. && p_rarch->wifi_driver->start)
  17049. {
  17050. bool wifi_allow = settings->bools.wifi_allow;
  17051. if (wifi_allow)
  17052. return p_rarch->wifi_driver->start(p_rarch->wifi_data);
  17053. }
  17054. return false;
  17055. case RARCH_WIFI_CTL_INIT:
  17056. /* Resource leaks will follow if wifi is initialized twice. */
  17057. if (p_rarch->wifi_data)
  17058. return false;
  17059. wifi_driver_ctl(RARCH_WIFI_CTL_FIND_DRIVER, NULL);
  17060. if (p_rarch->wifi_driver && p_rarch->wifi_driver->init)
  17061. {
  17062. p_rarch->wifi_data = p_rarch->wifi_driver->init();
  17063. if (p_rarch->wifi_data)
  17064. {
  17065. p_rarch->wifi_driver->enable(p_rarch->wifi_data,
  17066. settings->bools.wifi_enabled);
  17067. }
  17068. else
  17069. {
  17070. RARCH_ERR("Failed to initialize wifi driver. Will continue without wifi.\n");
  17071. wifi_driver_ctl(RARCH_WIFI_CTL_UNSET_ACTIVE, NULL);
  17072. }
  17073. }
  17074. break;
  17075. default:
  17076. break;
  17077. }
  17078. return false;
  17079. }
  17080. /* UI COMPANION */
  17081. void ui_companion_set_foreground(unsigned enable)
  17082. {
  17083. struct rarch_state *p_rarch = &rarch_st;
  17084. p_rarch->main_ui_companion_is_on_foreground = enable;
  17085. }
  17086. bool ui_companion_is_on_foreground(void)
  17087. {
  17088. struct rarch_state *p_rarch = &rarch_st;
  17089. return p_rarch->main_ui_companion_is_on_foreground;
  17090. }
  17091. void ui_companion_event_command(enum event_command action)
  17092. {
  17093. struct rarch_state *p_rarch = &rarch_st;
  17094. #ifdef HAVE_QT
  17095. bool qt_is_inited = p_rarch->qt_is_inited;
  17096. #endif
  17097. const ui_companion_driver_t *ui = p_rarch->ui_companion;
  17098. if (ui && ui->event_command)
  17099. ui->event_command(p_rarch->ui_companion_data, action);
  17100. #ifdef HAVE_QT
  17101. if (ui_companion_qt.toggle && qt_is_inited)
  17102. ui_companion_qt.event_command(
  17103. p_rarch->ui_companion_qt_data, action);
  17104. #endif
  17105. }
  17106. static void ui_companion_driver_deinit(struct rarch_state *p_rarch)
  17107. {
  17108. #ifdef HAVE_QT
  17109. bool qt_is_inited = p_rarch->qt_is_inited;
  17110. #endif
  17111. const ui_companion_driver_t *ui = p_rarch->ui_companion;
  17112. if (!ui)
  17113. return;
  17114. if (ui->deinit)
  17115. ui->deinit(p_rarch->ui_companion_data);
  17116. #ifdef HAVE_QT
  17117. if (qt_is_inited)
  17118. {
  17119. ui_companion_qt.deinit(p_rarch->ui_companion_qt_data);
  17120. p_rarch->ui_companion_qt_data = NULL;
  17121. }
  17122. #endif
  17123. p_rarch->ui_companion_data = NULL;
  17124. }
  17125. static void ui_companion_driver_init_first(
  17126. settings_t *settings,
  17127. struct rarch_state *p_rarch)
  17128. {
  17129. #ifdef HAVE_QT
  17130. bool desktop_menu_enable = settings->bools.desktop_menu_enable;
  17131. bool ui_companion_toggle = settings->bools.ui_companion_toggle;
  17132. if (desktop_menu_enable && ui_companion_toggle)
  17133. {
  17134. p_rarch->ui_companion_qt_data = ui_companion_qt.init();
  17135. p_rarch->qt_is_inited = true;
  17136. }
  17137. #endif
  17138. p_rarch->ui_companion = (ui_companion_driver_t*)ui_companion_drivers[0];
  17139. if (p_rarch->ui_companion)
  17140. {
  17141. unsigned ui_companion_start_on_boot =
  17142. settings->bools.ui_companion_start_on_boot;
  17143. if (ui_companion_start_on_boot)
  17144. {
  17145. if (p_rarch->ui_companion->init)
  17146. p_rarch->ui_companion_data = p_rarch->ui_companion->init();
  17147. ui_companion_driver_toggle(settings, p_rarch, false);
  17148. }
  17149. }
  17150. }
  17151. static void ui_companion_driver_toggle(
  17152. settings_t *settings,
  17153. struct rarch_state *p_rarch,
  17154. bool force)
  17155. {
  17156. #ifdef HAVE_QT
  17157. bool desktop_menu_enable = settings->bools.desktop_menu_enable;
  17158. bool ui_companion_toggle = settings->bools.ui_companion_toggle;
  17159. #endif
  17160. if (p_rarch->ui_companion && p_rarch->ui_companion->toggle)
  17161. p_rarch->ui_companion->toggle(p_rarch->ui_companion_data, false);
  17162. #ifdef HAVE_QT
  17163. if (desktop_menu_enable)
  17164. {
  17165. if ((ui_companion_toggle || force) && !p_rarch->qt_is_inited)
  17166. {
  17167. p_rarch->ui_companion_qt_data = ui_companion_qt.init();
  17168. p_rarch->qt_is_inited = true;
  17169. }
  17170. if (ui_companion_qt.toggle && p_rarch->qt_is_inited)
  17171. ui_companion_qt.toggle(p_rarch->ui_companion_qt_data, force);
  17172. }
  17173. #endif
  17174. }
  17175. void ui_companion_driver_notify_refresh(void)
  17176. {
  17177. struct rarch_state *p_rarch = &rarch_st;
  17178. const ui_companion_driver_t *ui = p_rarch->ui_companion;
  17179. #ifdef HAVE_QT
  17180. settings_t *settings = p_rarch->configuration_settings;
  17181. bool desktop_menu_enable = settings->bools.desktop_menu_enable;
  17182. bool qt_is_inited = p_rarch->qt_is_inited;
  17183. #endif
  17184. if (!ui)
  17185. return;
  17186. if (ui->notify_refresh)
  17187. ui->notify_refresh(p_rarch->ui_companion_data);
  17188. #ifdef HAVE_QT
  17189. if (desktop_menu_enable)
  17190. if (ui_companion_qt.notify_refresh && qt_is_inited)
  17191. ui_companion_qt.notify_refresh(p_rarch->ui_companion_qt_data);
  17192. #endif
  17193. }
  17194. void ui_companion_driver_notify_list_loaded(
  17195. file_list_t *list, file_list_t *menu_list)
  17196. {
  17197. struct rarch_state *p_rarch = &rarch_st;
  17198. const ui_companion_driver_t *ui = p_rarch->ui_companion;
  17199. if (ui && ui->notify_list_loaded)
  17200. ui->notify_list_loaded(p_rarch->ui_companion_data, list, menu_list);
  17201. }
  17202. void ui_companion_driver_notify_content_loaded(void)
  17203. {
  17204. struct rarch_state *p_rarch = &rarch_st;
  17205. const ui_companion_driver_t *ui = p_rarch->ui_companion;
  17206. if (ui && ui->notify_content_loaded)
  17207. ui->notify_content_loaded(p_rarch->ui_companion_data);
  17208. }
  17209. void ui_companion_driver_free(void)
  17210. {
  17211. struct rarch_state *p_rarch = &rarch_st;
  17212. p_rarch->ui_companion = NULL;
  17213. }
  17214. const ui_msg_window_t *ui_companion_driver_get_msg_window_ptr(void)
  17215. {
  17216. struct rarch_state *p_rarch = &rarch_st;
  17217. const ui_companion_driver_t *ui = p_rarch->ui_companion;
  17218. if (!ui)
  17219. return NULL;
  17220. return ui->msg_window;
  17221. }
  17222. const ui_window_t *ui_companion_driver_get_window_ptr(void)
  17223. {
  17224. struct rarch_state *p_rarch = &rarch_st;
  17225. const ui_companion_driver_t *ui = p_rarch->ui_companion;
  17226. if (!ui)
  17227. return NULL;
  17228. return ui->window;
  17229. }
  17230. const ui_browser_window_t *ui_companion_driver_get_browser_window_ptr(void)
  17231. {
  17232. struct rarch_state *p_rarch = &rarch_st;
  17233. const ui_companion_driver_t *ui = p_rarch->ui_companion;
  17234. if (!ui)
  17235. return NULL;
  17236. return ui->browser_window;
  17237. }
  17238. static void ui_companion_driver_msg_queue_push(
  17239. struct rarch_state *p_rarch,
  17240. const char *msg, unsigned priority, unsigned duration, bool flush)
  17241. {
  17242. const ui_companion_driver_t *ui = p_rarch->ui_companion;
  17243. if (ui && ui->msg_queue_push)
  17244. ui->msg_queue_push(p_rarch->ui_companion_data, msg, priority, duration, flush);
  17245. #ifdef HAVE_QT
  17246. {
  17247. settings_t *settings = p_rarch->configuration_settings;
  17248. bool qt_is_inited = p_rarch->qt_is_inited;
  17249. bool desktop_menu_enable = settings->bools.desktop_menu_enable;
  17250. if (desktop_menu_enable)
  17251. if (ui_companion_qt.msg_queue_push && qt_is_inited)
  17252. ui_companion_qt.msg_queue_push(
  17253. p_rarch->ui_companion_qt_data,
  17254. msg, priority, duration, flush);
  17255. }
  17256. #endif
  17257. }
  17258. void *ui_companion_driver_get_main_window(void)
  17259. {
  17260. struct rarch_state
  17261. *p_rarch = &rarch_st;
  17262. const ui_companion_driver_t *ui = p_rarch->ui_companion;
  17263. if (!ui || !ui->get_main_window)
  17264. return NULL;
  17265. return ui->get_main_window(p_rarch->ui_companion_data);
  17266. }
  17267. const char *ui_companion_driver_get_ident(void)
  17268. {
  17269. struct rarch_state
  17270. *p_rarch = &rarch_st;
  17271. const ui_companion_driver_t *ui = p_rarch->ui_companion;
  17272. if (!ui)
  17273. return "null";
  17274. return ui->ident;
  17275. }
  17276. void ui_companion_driver_log_msg(const char *msg)
  17277. {
  17278. #ifdef HAVE_QT
  17279. struct rarch_state *p_rarch = &rarch_st;
  17280. settings_t *settings = p_rarch->configuration_settings;
  17281. bool qt_is_inited = p_rarch->qt_is_inited;
  17282. bool desktop_menu_enable = settings->bools.desktop_menu_enable;
  17283. bool window_is_active = p_rarch->ui_companion_qt_data && qt_is_inited
  17284. && ui_companion_qt.is_active(p_rarch->ui_companion_qt_data);
  17285. if (desktop_menu_enable)
  17286. if (window_is_active)
  17287. ui_companion_qt.log_msg(p_rarch->ui_companion_qt_data, msg);
  17288. #endif
  17289. }
  17290. /* RECORDING */
  17291. /**
  17292. * config_get_record_driver_options:
  17293. *
  17294. * Get an enumerated list of all record driver names, separated by '|'.
  17295. *
  17296. * Returns: string listing of all record driver names, separated by '|'.
  17297. **/
  17298. const char* config_get_record_driver_options(void)
  17299. {
  17300. return char_list_new_special(STRING_LIST_RECORD_DRIVERS, NULL);
  17301. }
  17302. #if 0
  17303. /* TODO/FIXME - not used apparently */
  17304. static void find_record_driver(void)
  17305. {
  17306. settings_t *settings = p_rarch->configuration_settings;
  17307. int i = (int)driver_find_index(
  17308. "record_driver",
  17309. settings->arrays.record_driver);
  17310. if (i >= 0)
  17311. p_rarch->recording_driver = (const record_driver_t*)record_drivers[i];
  17312. else
  17313. {
  17314. if (verbosity_is_enabled())
  17315. {
  17316. unsigned d;
  17317. RARCH_ERR("[recording] Couldn't find any record driver named \"%s\"\n",
  17318. settings->arrays.record_driver);
  17319. RARCH_LOG_OUTPUT("Available record drivers are:\n");
  17320. for (d = 0; record_drivers[d]; d++)
  17321. RARCH_LOG_OUTPUT("\t%s\n", record_drivers[d].ident);
  17322. RARCH_WARN("[recording] Going to default to first record driver...\n");
  17323. }
  17324. p_rarch->recording_driver = (const record_driver_t*)record_drivers[0];
  17325. if (!p_rarch->recording_driver)
  17326. retroarch_fail(1, "find_record_driver()");
  17327. }
  17328. }
  17329. /**
  17330. * ffemu_find_backend:
  17331. * @ident : Identifier of driver to find.
  17332. *
  17333. * Finds a recording driver with the name @ident.
  17334. *
  17335. * Returns: recording driver handle if successful, otherwise
  17336. * NULL.
  17337. **/
  17338. static const record_driver_t *ffemu_find_backend(const char *ident)
  17339. {
  17340. unsigned i;
  17341. for (i = 0; record_drivers[i]; i++)
  17342. {
  17343. if (string_is_equal(record_drivers[i]->ident, ident))
  17344. return record_drivers[i];
  17345. }
  17346. return NULL;
  17347. }
  17348. static void recording_driver_free_state(void)
  17349. {
  17350. /* TODO/FIXME - this is not being called anywhere */
  17351. p_rarch->recording_gpu_width = 0;
  17352. p_rarch->recording_gpu_height = 0;
  17353. p_rarch->recording_width = 0;
  17354. p_rarch->recording_height = 0;
  17355. }
  17356. #endif
  17357. /**
  17358. * gfx_ctx_init_first:
  17359. * @backend : Recording backend handle.
  17360. * @data : Recording data handle.
  17361. * @params : Recording info parameters.
  17362. *
  17363. * Finds first suitable recording context driver and initializes.
  17364. *
  17365. * Returns: true (1) if successful, otherwise false (0).
  17366. **/
  17367. static bool record_driver_init_first(
  17368. const record_driver_t **backend, void **data,
  17369. const struct record_params *params)
  17370. {
  17371. unsigned i;
  17372. for (i = 0; record_drivers[i]; i++)
  17373. {
  17374. void *handle = record_drivers[i]->init(params);
  17375. if (!handle)
  17376. continue;
  17377. *backend = record_drivers[i];
  17378. *data = handle;
  17379. return true;
  17380. }
  17381. return false;
  17382. }
  17383. static void recording_dump_frame(
  17384. struct rarch_state *p_rarch,
  17385. const void *data, unsigned width,
  17386. unsigned height, size_t pitch, bool is_idle)
  17387. {
  17388. struct record_video_data ffemu_data;
  17389. ffemu_data.data = data;
  17390. ffemu_data.width = width;
  17391. ffemu_data.height = height;
  17392. ffemu_data.pitch = (int)pitch;
  17393. ffemu_data.is_dupe = false;
  17394. if (p_rarch->video_driver_record_gpu_buffer)
  17395. {
  17396. struct video_viewport vp;
  17397. vp.x = 0;
  17398. vp.y = 0;
  17399. vp.width = 0;
  17400. vp.height = 0;
  17401. vp.full_width = 0;
  17402. vp.full_height = 0;
  17403. video_driver_get_viewport_info(&vp);
  17404. if (!vp.width || !vp.height)
  17405. {
  17406. RARCH_WARN("[recording] %s \n",
  17407. msg_hash_to_str(MSG_VIEWPORT_SIZE_CALCULATION_FAILED));
  17408. video_driver_gpu_record_deinit(p_rarch);
  17409. recording_dump_frame(p_rarch,
  17410. data, width, height, pitch, is_idle);
  17411. return;
  17412. }
  17413. /* User has resized. We kinda have a problem now. */
  17414. if ( vp.width != p_rarch->recording_gpu_width ||
  17415. vp.height != p_rarch->recording_gpu_height)
  17416. {
  17417. RARCH_WARN("[recording] %s\n",
  17418. msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE));
  17419. runloop_msg_queue_push(
  17420. msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE),
  17421. 1, 180, true,
  17422. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  17423. command_event(CMD_EVENT_RECORD_DEINIT, NULL);
  17424. return;
  17425. }
  17426. /* Big bottleneck.
  17427. * Since we might need to do read-backs asynchronously,
  17428. * it might take 3-4 times before this returns true. */
  17429. if (!video_driver_read_viewport(p_rarch->video_driver_record_gpu_buffer, is_idle))
  17430. return;
  17431. ffemu_data.pitch = (int)(p_rarch->recording_gpu_width * 3);
  17432. ffemu_data.width = (unsigned)p_rarch->recording_gpu_width;
  17433. ffemu_data.height = (unsigned)p_rarch->recording_gpu_height;
  17434. ffemu_data.data = p_rarch->video_driver_record_gpu_buffer + (ffemu_data.height - 1) * ffemu_data.pitch;
  17435. ffemu_data.pitch = -ffemu_data.pitch;
  17436. }
  17437. else
  17438. ffemu_data.is_dupe = !data;
  17439. p_rarch->recording_driver->push_video(p_rarch->recording_data, &ffemu_data);
  17440. }
  17441. static bool recording_deinit(struct rarch_state *p_rarch)
  17442. {
  17443. if (!p_rarch->recording_data || !p_rarch->recording_driver)
  17444. return false;
  17445. if (p_rarch->recording_driver->finalize)
  17446. p_rarch->recording_driver->finalize(p_rarch->recording_data);
  17447. if (p_rarch->recording_driver->free)
  17448. p_rarch->recording_driver->free(p_rarch->recording_data);
  17449. p_rarch->recording_data = NULL;
  17450. p_rarch->recording_driver = NULL;
  17451. video_driver_gpu_record_deinit(p_rarch);
  17452. return true;
  17453. }
  17454. bool recording_is_enabled(void)
  17455. {
  17456. struct rarch_state *p_rarch = &rarch_st;
  17457. return p_rarch->recording_enable;
  17458. }
  17459. bool streaming_is_enabled(void)
  17460. {
  17461. struct rarch_state *p_rarch = &rarch_st;
  17462. return p_rarch->streaming_enable;
  17463. }
  17464. void streaming_set_state(bool state)
  17465. {
  17466. struct rarch_state *p_rarch = &rarch_st;
  17467. p_rarch->streaming_enable = state;
  17468. }
  17469. static void video_driver_gpu_record_deinit(struct rarch_state *p_rarch)
  17470. {
  17471. if (p_rarch->video_driver_record_gpu_buffer)
  17472. free(p_rarch->video_driver_record_gpu_buffer);
  17473. p_rarch->video_driver_record_gpu_buffer = NULL;
  17474. }
  17475. /**
  17476. * recording_init:
  17477. *
  17478. * Initializes recording.
  17479. *
  17480. * Returns: true (1) if successful, otherwise false (0).
  17481. **/
  17482. static bool recording_init(
  17483. settings_t *settings,
  17484. struct rarch_state *p_rarch)
  17485. {
  17486. char output[PATH_MAX_LENGTH];
  17487. char buf[PATH_MAX_LENGTH];
  17488. struct record_params params = {0};
  17489. struct retro_system_av_info *av_info = &p_rarch->video_driver_av_info;
  17490. global_t *global = &p_rarch->g_extern;
  17491. bool video_gpu_record = settings->bools.video_gpu_record;
  17492. bool video_force_aspect = settings->bools.video_force_aspect;
  17493. const enum rarch_core_type
  17494. current_core_type = p_rarch->current_core_type;
  17495. const enum retro_pixel_format
  17496. video_driver_pix_fmt = p_rarch->video_driver_pix_fmt;
  17497. bool recording_enable = p_rarch->recording_enable;
  17498. if (!recording_enable)
  17499. return false;
  17500. output[0] = '\0';
  17501. if (current_core_type == CORE_TYPE_DUMMY)
  17502. {
  17503. RARCH_WARN("[recording] %s\n",
  17504. msg_hash_to_str(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED));
  17505. return false;
  17506. }
  17507. if (!video_gpu_record && video_driver_is_hw_context())
  17508. {
  17509. RARCH_WARN("[recording] %s.\n",
  17510. msg_hash_to_str(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING));
  17511. return false;
  17512. }
  17513. RARCH_LOG("[recording] %s: FPS: %.4f, Sample rate: %.4f\n",
  17514. msg_hash_to_str(MSG_CUSTOM_TIMING_GIVEN),
  17515. (float)av_info->timing.fps,
  17516. (float)av_info->timing.sample_rate);
  17517. if (!string_is_empty(global->record.path))
  17518. strlcpy(output, global->record.path, sizeof(output));
  17519. else
  17520. {
  17521. const char *stream_url = settings->paths.path_stream_url;
  17522. unsigned video_record_quality = settings->uints.video_record_quality;
  17523. unsigned video_stream_port = settings->uints.video_stream_port;
  17524. if (p_rarch->streaming_enable)
  17525. if (!string_is_empty(stream_url))
  17526. strlcpy(output, stream_url, sizeof(output));
  17527. else
  17528. /* Fallback, stream locally to 127.0.0.1 */
  17529. snprintf(output, sizeof(output), "udp://127.0.0.1:%u",
  17530. video_stream_port);
  17531. else
  17532. {
  17533. const char *game_name = path_basename(path_get(RARCH_PATH_BASENAME));
  17534. /* Fallback to core name if started without content */
  17535. if (string_is_empty(game_name))
  17536. game_name = p_rarch->runloop_system.info.library_name;
  17537. if (video_record_quality < RECORD_CONFIG_TYPE_RECORDING_WEBM_FAST)
  17538. {
  17539. fill_str_dated_filename(buf, game_name,
  17540. "mkv", sizeof(buf));
  17541. fill_pathname_join(output, global->record.output_dir, buf, sizeof(output));
  17542. }
  17543. else if (video_record_quality >= RECORD_CONFIG_TYPE_RECORDING_WEBM_FAST
  17544. && video_record_quality < RECORD_CONFIG_TYPE_RECORDING_GIF)
  17545. {
  17546. fill_str_dated_filename(buf, game_name,
  17547. "webm", sizeof(buf));
  17548. fill_pathname_join(output, global->record.output_dir, buf, sizeof(output));
  17549. }
  17550. else if (video_record_quality >= RECORD_CONFIG_TYPE_RECORDING_GIF
  17551. && video_record_quality < RECORD_CONFIG_TYPE_RECORDING_APNG)
  17552. {
  17553. fill_str_dated_filename(buf, game_name,
  17554. "gif", sizeof(buf));
  17555. fill_pathname_join(output, global->record.output_dir, buf, sizeof(output));
  17556. }
  17557. else
  17558. {
  17559. fill_str_dated_filename(buf, game_name,
  17560. "png", sizeof(buf));
  17561. fill_pathname_join(output, global->record.output_dir, buf, sizeof(output));
  17562. }
  17563. }
  17564. }
  17565. params.audio_resampler = settings->arrays.audio_resampler;
  17566. params.video_gpu_record = settings->bools.video_gpu_record;
  17567. params.video_record_scale_factor = settings->uints.video_record_scale_factor;
  17568. params.video_stream_scale_factor = settings->uints.video_stream_scale_factor;
  17569. params.video_record_threads = settings->uints.video_record_threads;
  17570. params.streaming_mode = settings->uints.streaming_mode;
  17571. params.out_width = av_info->geometry.base_width;
  17572. params.out_height = av_info->geometry.base_height;
  17573. params.fb_width = av_info->geometry.max_width;
  17574. params.fb_height = av_info->geometry.max_height;
  17575. params.channels = 2;
  17576. params.filename = output;
  17577. params.fps = av_info->timing.fps;
  17578. params.samplerate = av_info->timing.sample_rate;
  17579. params.pix_fmt =
  17580. (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888)
  17581. ? FFEMU_PIX_ARGB8888
  17582. : FFEMU_PIX_RGB565;
  17583. params.config = NULL;
  17584. if (!string_is_empty(global->record.config))
  17585. params.config = global->record.config;
  17586. else
  17587. {
  17588. if (p_rarch->streaming_enable)
  17589. {
  17590. params.config = settings->paths.path_stream_config;
  17591. params.preset = (enum record_config_type)
  17592. settings->uints.video_stream_quality;
  17593. }
  17594. else
  17595. {
  17596. params.config = settings->paths.path_record_config;
  17597. params.preset = (enum record_config_type)
  17598. settings->uints.video_record_quality;
  17599. }
  17600. }
  17601. if (settings->bools.video_gpu_record
  17602. && p_rarch->current_video->read_viewport)
  17603. {
  17604. unsigned gpu_size;
  17605. struct video_viewport vp;
  17606. vp.x = 0;
  17607. vp.y = 0;
  17608. vp.width = 0;
  17609. vp.height = 0;
  17610. vp.full_width = 0;
  17611. vp.full_height = 0;
  17612. video_driver_get_viewport_info(&vp);
  17613. if (!vp.width || !vp.height)
  17614. {
  17615. RARCH_ERR("[recording] Failed to get viewport information from video driver. "
  17616. "Cannot start recording ...\n");
  17617. return false;
  17618. }
  17619. params.out_width = vp.width;
  17620. params.out_height = vp.height;
  17621. params.fb_width = next_pow2(vp.width);
  17622. params.fb_height = next_pow2(vp.height);
  17623. if (video_force_aspect &&
  17624. (p_rarch->video_driver_aspect_ratio > 0.0f))
  17625. params.aspect_ratio = p_rarch->video_driver_aspect_ratio;
  17626. else
  17627. params.aspect_ratio = (float)vp.width / vp.height;
  17628. params.pix_fmt = FFEMU_PIX_BGR24;
  17629. p_rarch->recording_gpu_width = vp.width;
  17630. p_rarch->recording_gpu_height = vp.height;
  17631. RARCH_LOG("[recording] %s %u x %u\n", msg_hash_to_str(MSG_DETECTED_VIEWPORT_OF),
  17632. vp.width, vp.height);
  17633. gpu_size = vp.width * vp.height * 3;
  17634. if (!(p_rarch->video_driver_record_gpu_buffer = (uint8_t*)malloc(gpu_size)))
  17635. return false;
  17636. }
  17637. else
  17638. {
  17639. if (p_rarch->recording_width || p_rarch->recording_height)
  17640. {
  17641. params.out_width = p_rarch->recording_width;
  17642. params.out_height = p_rarch->recording_height;
  17643. }
  17644. if (video_force_aspect &&
  17645. (p_rarch->video_driver_aspect_ratio > 0.0f))
  17646. params.aspect_ratio = p_rarch->video_driver_aspect_ratio;
  17647. else
  17648. params.aspect_ratio = (float)params.out_width / params.out_height;
  17649. #ifdef HAVE_VIDEO_FILTER
  17650. if (settings->bools.video_post_filter_record
  17651. && !!p_rarch->video_driver_state_filter)
  17652. {
  17653. unsigned max_width = 0;
  17654. unsigned max_height = 0;
  17655. params.pix_fmt = FFEMU_PIX_RGB565;
  17656. if (p_rarch->video_driver_state_out_rgb32)
  17657. params.pix_fmt = FFEMU_PIX_ARGB8888;
  17658. rarch_softfilter_get_max_output_size(
  17659. p_rarch->video_driver_state_filter,
  17660. &max_width, &max_height);
  17661. params.fb_width = next_pow2(max_width);
  17662. params.fb_height = next_pow2(max_height);
  17663. }
  17664. #endif
  17665. }
  17666. RARCH_LOG("[recording] %s %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n",
  17667. msg_hash_to_str(MSG_RECORDING_TO),
  17668. output,
  17669. params.out_width, params.out_height,
  17670. params.fb_width, params.fb_height,
  17671. (unsigned)params.pix_fmt);
  17672. if (!record_driver_init_first(
  17673. &p_rarch->recording_driver, &p_rarch->recording_data, &params))
  17674. {
  17675. RARCH_ERR("[recording] %s\n",
  17676. msg_hash_to_str(MSG_FAILED_TO_START_RECORDING));
  17677. video_driver_gpu_record_deinit(p_rarch);
  17678. return false;
  17679. }
  17680. return true;
  17681. }
  17682. void recording_driver_update_streaming_url(void)
  17683. {
  17684. struct rarch_state *p_rarch = &rarch_st;
  17685. settings_t *settings = p_rarch->configuration_settings;
  17686. const char *youtube_url = "rtmp://a.rtmp.youtube.com/live2/";
  17687. const char *twitch_url = "rtmp://live.twitch.tv/app/";
  17688. const char *facebook_url = "rtmps://live-api-s.facebook.com:443/rtmp/";
  17689. if (!settings)
  17690. return;
  17691. switch (settings->uints.streaming_mode)
  17692. {
  17693. case STREAMING_MODE_TWITCH:
  17694. if (!string_is_empty(settings->arrays.twitch_stream_key))
  17695. {
  17696. strlcpy(settings->paths.path_stream_url,
  17697. twitch_url,
  17698. sizeof(settings->paths.path_stream_url));
  17699. strlcat(settings->paths.path_stream_url,
  17700. settings->arrays.twitch_stream_key,
  17701. sizeof(settings->paths.path_stream_url));
  17702. }
  17703. break;
  17704. case STREAMING_MODE_YOUTUBE:
  17705. if (!string_is_empty(settings->arrays.youtube_stream_key))
  17706. {
  17707. strlcpy(settings->paths.path_stream_url,
  17708. youtube_url,
  17709. sizeof(settings->paths.path_stream_url));
  17710. strlcat(settings->paths.path_stream_url,
  17711. settings->arrays.youtube_stream_key,
  17712. sizeof(settings->paths.path_stream_url));
  17713. }
  17714. break;
  17715. case STREAMING_MODE_LOCAL:
  17716. /* TODO: figure out default interface and bind to that instead */
  17717. snprintf(settings->paths.path_stream_url, sizeof(settings->paths.path_stream_url),
  17718. "udp://%s:%u", "127.0.0.1", settings->uints.video_stream_port);
  17719. break;
  17720. case STREAMING_MODE_CUSTOM:
  17721. default:
  17722. /* Do nothing, let the user input the URL */
  17723. break;
  17724. case STREAMING_MODE_FACEBOOK:
  17725. if (!string_is_empty(settings->arrays.facebook_stream_key))
  17726. {
  17727. strlcpy(settings->paths.path_stream_url,
  17728. facebook_url,
  17729. sizeof(settings->paths.path_stream_url));
  17730. strlcat(settings->paths.path_stream_url,
  17731. settings->arrays.facebook_stream_key,
  17732. sizeof(settings->paths.path_stream_url));
  17733. }
  17734. break;
  17735. }
  17736. }
  17737. #ifdef HAVE_BSV_MOVIE
  17738. /* BSV MOVIE */
  17739. static bool bsv_movie_init_playback(
  17740. bsv_movie_t *handle, const char *path)
  17741. {
  17742. uint32_t state_size = 0;
  17743. uint32_t content_crc = 0;
  17744. uint32_t header[4] = {0};
  17745. intfstream_t *file = intfstream_open_file(path,
  17746. RETRO_VFS_FILE_ACCESS_READ,
  17747. RETRO_VFS_FILE_ACCESS_HINT_NONE);
  17748. if (!file)
  17749. {
  17750. RARCH_ERR("Could not open BSV file for playback, path : \"%s\".\n", path);
  17751. return false;
  17752. }
  17753. handle->file = file;
  17754. handle->playback = true;
  17755. intfstream_read(handle->file, header, sizeof(uint32_t) * 4);
  17756. /* Compatibility with old implementation that
  17757. * used incorrect documentation. */
  17758. if (swap_if_little32(header[MAGIC_INDEX]) != BSV_MAGIC
  17759. && swap_if_big32(header[MAGIC_INDEX]) != BSV_MAGIC)
  17760. {
  17761. RARCH_ERR("%s\n", msg_hash_to_str(MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE));
  17762. return false;
  17763. }
  17764. content_crc = content_get_crc();
  17765. if (content_crc != 0)
  17766. if (swap_if_big32(header[CRC_INDEX]) != content_crc)
  17767. RARCH_WARN("%s.\n", msg_hash_to_str(MSG_CRC32_CHECKSUM_MISMATCH));
  17768. state_size = swap_if_big32(header[STATE_SIZE_INDEX]);
  17769. #if 0
  17770. RARCH_ERR("----- debug %u -----\n", header[0]);
  17771. RARCH_ERR("----- debug %u -----\n", header[1]);
  17772. RARCH_ERR("----- debug %u -----\n", header[2]);
  17773. RARCH_ERR("----- debug %u -----\n", header[3]);
  17774. #endif
  17775. if (state_size)
  17776. {
  17777. retro_ctx_size_info_t info;
  17778. retro_ctx_serialize_info_t serial_info;
  17779. uint8_t *buf = (uint8_t*)malloc(state_size);
  17780. if (!buf)
  17781. return false;
  17782. handle->state = buf;
  17783. handle->state_size = state_size;
  17784. if (intfstream_read(handle->file,
  17785. handle->state, state_size) != state_size)
  17786. {
  17787. RARCH_ERR("%s\n", msg_hash_to_str(MSG_COULD_NOT_READ_STATE_FROM_MOVIE));
  17788. return false;
  17789. }
  17790. core_serialize_size( &info);
  17791. if (info.size == state_size)
  17792. {
  17793. serial_info.data_const = handle->state;
  17794. serial_info.size = state_size;
  17795. core_unserialize(&serial_info);
  17796. }
  17797. else
  17798. RARCH_WARN("%s\n",
  17799. msg_hash_to_str(MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION));
  17800. }
  17801. handle->min_file_pos = sizeof(header) + state_size;
  17802. return true;
  17803. }
  17804. static bool bsv_movie_init_record(
  17805. bsv_movie_t *handle, const char *path)
  17806. {
  17807. retro_ctx_size_info_t info;
  17808. uint32_t state_size = 0;
  17809. uint32_t content_crc = 0;
  17810. uint32_t header[4] = {0};
  17811. intfstream_t *file = intfstream_open_file(path,
  17812. RETRO_VFS_FILE_ACCESS_WRITE,
  17813. RETRO_VFS_FILE_ACCESS_HINT_NONE);
  17814. if (!file)
  17815. {
  17816. RARCH_ERR("Could not open BSV file for recording, path : \"%s\".\n", path);
  17817. return false;
  17818. }
  17819. handle->file = file;
  17820. content_crc = content_get_crc();
  17821. /* This value is supposed to show up as
  17822. * BSV1 in a HEX editor, big-endian. */
  17823. header[MAGIC_INDEX] = swap_if_little32(BSV_MAGIC);
  17824. header[CRC_INDEX] = swap_if_big32(content_crc);
  17825. core_serialize_size(&info);
  17826. state_size = (unsigned)info.size;
  17827. header[STATE_SIZE_INDEX] = swap_if_big32(state_size);
  17828. intfstream_write(handle->file, header, 4 * sizeof(uint32_t));
  17829. handle->min_file_pos = sizeof(header) + state_size;
  17830. handle->state_size = state_size;
  17831. if (state_size)
  17832. {
  17833. retro_ctx_serialize_info_t serial_info;
  17834. uint8_t *st = (uint8_t*)malloc(state_size);
  17835. if (!st)
  17836. return false;
  17837. handle->state = st;
  17838. serial_info.data = handle->state;
  17839. serial_info.size = state_size;
  17840. core_serialize(&serial_info);
  17841. intfstream_write(handle->file,
  17842. handle->state, state_size);
  17843. }
  17844. return true;
  17845. }
  17846. static void bsv_movie_free(bsv_movie_t *handle)
  17847. {
  17848. if (!handle)
  17849. return;
  17850. intfstream_close(handle->file);
  17851. free(handle->file);
  17852. free(handle->state);
  17853. free(handle->frame_pos);
  17854. free(handle);
  17855. }
  17856. static bsv_movie_t *bsv_movie_init_internal(const char *path,
  17857. enum rarch_movie_type type)
  17858. {
  17859. size_t *frame_pos = NULL;
  17860. bsv_movie_t *handle = (bsv_movie_t*)calloc(1, sizeof(*handle));
  17861. if (!handle)
  17862. return NULL;
  17863. if (type == RARCH_MOVIE_PLAYBACK)
  17864. {
  17865. if (!bsv_movie_init_playback(handle, path))
  17866. goto error;
  17867. }
  17868. else if (!bsv_movie_init_record(handle, path))
  17869. goto error;
  17870. /* Just pick something really large
  17871. * ~1 million frames rewind should do the trick. */
  17872. if (!(frame_pos = (size_t*)calloc((1 << 20), sizeof(size_t))))
  17873. goto error;
  17874. handle->frame_pos = frame_pos;
  17875. handle->frame_pos[0] = handle->min_file_pos;
  17876. handle->frame_mask = (1 << 20) - 1;
  17877. return handle;
  17878. error:
  17879. bsv_movie_free(handle);
  17880. return NULL;
  17881. }
  17882. void bsv_movie_frame_rewind(void)
  17883. {
  17884. struct rarch_state *p_rarch = &rarch_st;
  17885. bsv_movie_t *handle = p_rarch->bsv_movie_state_handle;
  17886. if (!handle)
  17887. return;
  17888. handle->did_rewind = true;
  17889. if ( (handle->frame_ptr <= 1)
  17890. && (handle->frame_pos[0] == handle->min_file_pos))
  17891. {
  17892. /* If we're at the beginning... */
  17893. handle->frame_ptr = 0;
  17894. intfstream_seek(handle->file, (int)handle->min_file_pos, SEEK_SET);
  17895. }
  17896. else
  17897. {
  17898. /* First time rewind is performed, the old frame is simply replayed.
  17899. * However, playing back that frame caused us to read data, and push
  17900. * data to the ring buffer.
  17901. *
  17902. * Sucessively rewinding frames, we need to rewind past the read data,
  17903. * plus another. */
  17904. handle->frame_ptr = (handle->frame_ptr -
  17905. (handle->first_rewind ? 1 : 2)) & handle->frame_mask;
  17906. intfstream_seek(handle->file,
  17907. (int)handle->frame_pos[handle->frame_ptr], SEEK_SET);
  17908. }
  17909. if (intfstream_tell(handle->file) <= (long)handle->min_file_pos)
  17910. {
  17911. /* We rewound past the beginning. */
  17912. if (!handle->playback)
  17913. {
  17914. retro_ctx_serialize_info_t serial_info;
  17915. /* If recording, we simply reset
  17916. * the starting point. Nice and easy. */
  17917. intfstream_seek(handle->file, 4 * sizeof(uint32_t), SEEK_SET);
  17918. serial_info.data = handle->state;
  17919. serial_info.size = handle->state_size;
  17920. core_serialize(&serial_info);
  17921. intfstream_write(handle->file, handle->state, handle->state_size);
  17922. }
  17923. else
  17924. intfstream_seek(handle->file, (int)handle->min_file_pos, SEEK_SET);
  17925. }
  17926. }
  17927. static bool bsv_movie_init_handle(
  17928. struct rarch_state *p_rarch,
  17929. const char *path,
  17930. enum rarch_movie_type type)
  17931. {
  17932. bsv_movie_t *state = bsv_movie_init_internal(path, type);
  17933. if (!state)
  17934. return false;
  17935. p_rarch->bsv_movie_state_handle = state;
  17936. return true;
  17937. }
  17938. static bool bsv_movie_init(struct rarch_state *p_rarch)
  17939. {
  17940. if (p_rarch->bsv_movie_state.movie_start_playback)
  17941. {
  17942. if (!bsv_movie_init_handle(p_rarch,
  17943. p_rarch->bsv_movie_state.movie_start_path,
  17944. RARCH_MOVIE_PLAYBACK))
  17945. {
  17946. RARCH_ERR("%s: \"%s\".\n",
  17947. msg_hash_to_str(MSG_FAILED_TO_LOAD_MOVIE_FILE),
  17948. p_rarch->bsv_movie_state.movie_start_path);
  17949. return false;
  17950. }
  17951. p_rarch->bsv_movie_state.movie_playback = true;
  17952. runloop_msg_queue_push(msg_hash_to_str(MSG_STARTING_MOVIE_PLAYBACK),
  17953. 2, 180, false,
  17954. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  17955. RARCH_LOG("%s.\n", msg_hash_to_str(MSG_STARTING_MOVIE_PLAYBACK));
  17956. return true;
  17957. }
  17958. else if (p_rarch->bsv_movie_state.movie_start_recording)
  17959. {
  17960. char msg[8192];
  17961. if (!bsv_movie_init_handle(
  17962. p_rarch,
  17963. p_rarch->bsv_movie_state.movie_start_path,
  17964. RARCH_MOVIE_RECORD))
  17965. {
  17966. runloop_msg_queue_push(
  17967. msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD),
  17968. 1, 180, true,
  17969. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  17970. RARCH_ERR("%s.\n",
  17971. msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD));
  17972. return false;
  17973. }
  17974. snprintf(msg, sizeof(msg),
  17975. "%s \"%s\".",
  17976. msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO),
  17977. p_rarch->bsv_movie_state.movie_start_path);
  17978. runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  17979. RARCH_LOG("%s \"%s\".\n",
  17980. msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO),
  17981. p_rarch->bsv_movie_state.movie_start_path);
  17982. return true;
  17983. }
  17984. return false;
  17985. }
  17986. static void bsv_movie_deinit(struct rarch_state *p_rarch)
  17987. {
  17988. if (p_rarch->bsv_movie_state_handle)
  17989. bsv_movie_free(p_rarch->bsv_movie_state_handle);
  17990. p_rarch->bsv_movie_state_handle = NULL;
  17991. }
  17992. static bool runloop_check_movie_init(struct rarch_state *p_rarch)
  17993. {
  17994. char msg[16384], path[8192];
  17995. settings_t *settings = p_rarch->configuration_settings;
  17996. int state_slot = settings->ints.state_slot;
  17997. msg[0] = path[0] = '\0';
  17998. configuration_set_uint(settings, settings->uints.rewind_granularity, 1);
  17999. if (state_slot > 0)
  18000. snprintf(path, sizeof(path), "%s%d.bsv",
  18001. p_rarch->bsv_movie_state.movie_path,
  18002. state_slot);
  18003. else
  18004. {
  18005. strlcpy(path, p_rarch->bsv_movie_state.movie_path, sizeof(path));
  18006. strlcat(path, ".bsv", sizeof(path));
  18007. }
  18008. snprintf(msg, sizeof(msg), "%s \"%s\".",
  18009. msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO),
  18010. path);
  18011. bsv_movie_init_handle(
  18012. p_rarch,
  18013. path, RARCH_MOVIE_RECORD);
  18014. if (!p_rarch->bsv_movie_state_handle)
  18015. {
  18016. runloop_msg_queue_push(
  18017. msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD),
  18018. 2, 180, true,
  18019. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  18020. RARCH_ERR("%s\n",
  18021. msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD));
  18022. return false;
  18023. }
  18024. runloop_msg_queue_push(msg, 2, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  18025. RARCH_LOG("%s \"%s\".\n",
  18026. msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO),
  18027. path);
  18028. return true;
  18029. }
  18030. static bool bsv_movie_check(struct rarch_state *p_rarch)
  18031. {
  18032. if (!p_rarch->bsv_movie_state_handle)
  18033. return runloop_check_movie_init(p_rarch);
  18034. if (p_rarch->bsv_movie_state.movie_playback)
  18035. {
  18036. /* Checks if movie is being played back. */
  18037. if (!p_rarch->bsv_movie_state.movie_end)
  18038. return false;
  18039. runloop_msg_queue_push(
  18040. msg_hash_to_str(MSG_MOVIE_PLAYBACK_ENDED), 2, 180, false,
  18041. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  18042. RARCH_LOG("%s\n", msg_hash_to_str(MSG_MOVIE_PLAYBACK_ENDED));
  18043. bsv_movie_deinit(p_rarch);
  18044. p_rarch->bsv_movie_state.movie_end = false;
  18045. p_rarch->bsv_movie_state.movie_playback = false;
  18046. return true;
  18047. }
  18048. /* Checks if movie is being recorded. */
  18049. if (!p_rarch->bsv_movie_state_handle)
  18050. return false;
  18051. runloop_msg_queue_push(
  18052. msg_hash_to_str(MSG_MOVIE_RECORD_STOPPED), 2, 180, true,
  18053. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  18054. RARCH_LOG("%s\n", msg_hash_to_str(MSG_MOVIE_RECORD_STOPPED));
  18055. bsv_movie_deinit(p_rarch);
  18056. return true;
  18057. }
  18058. #endif
  18059. /* INPUT OVERLAY */
  18060. #ifdef HAVE_OVERLAY
  18061. static bool video_driver_overlay_interface(
  18062. const video_overlay_interface_t **iface);
  18063. /**
  18064. * input_overlay_add_inputs:
  18065. * @ol : pointer to overlay
  18066. * @port : the user to show the inputs of
  18067. *
  18068. * Adds inputs from current_input to the overlay, so it's displayed
  18069. * returns true if an input that is pressed will change the overlay
  18070. */
  18071. static bool input_overlay_add_inputs_inner(overlay_desc_t *desc,
  18072. unsigned port, unsigned analog_dpad_mode)
  18073. {
  18074. switch(desc->type)
  18075. {
  18076. case OVERLAY_TYPE_BUTTONS:
  18077. {
  18078. unsigned i;
  18079. bool all_buttons_pressed = false;
  18080. /*Check each bank of the mask*/
  18081. for (i = 0; i < ARRAY_SIZE(desc->button_mask.data); ++i)
  18082. {
  18083. /*Get bank*/
  18084. uint32_t bank_mask = BITS_GET_ELEM(desc->button_mask,i);
  18085. unsigned id = i * 32;
  18086. /*Worth pursuing? Have we got any bits left in here?*/
  18087. while (bank_mask)
  18088. {
  18089. /*If this bit is set then we need to query the pad
  18090. *The button must be pressed.*/
  18091. if (bank_mask & 1)
  18092. {
  18093. /* Light up the button if pressed */
  18094. if (!input_state(port, RETRO_DEVICE_JOYPAD, 0, id))
  18095. {
  18096. /* We need ALL of the inputs to be active,
  18097. * abort. */
  18098. desc->updated = false;
  18099. return false;
  18100. }
  18101. all_buttons_pressed = true;
  18102. desc->updated = true;
  18103. }
  18104. bank_mask >>= 1;
  18105. ++id;
  18106. }
  18107. }
  18108. return all_buttons_pressed;
  18109. }
  18110. case OVERLAY_TYPE_ANALOG_LEFT:
  18111. case OVERLAY_TYPE_ANALOG_RIGHT:
  18112. {
  18113. unsigned int index = (desc->type == OVERLAY_TYPE_ANALOG_RIGHT) ?
  18114. RETRO_DEVICE_INDEX_ANALOG_RIGHT : RETRO_DEVICE_INDEX_ANALOG_LEFT;
  18115. float analog_x = input_state(port, RETRO_DEVICE_ANALOG,
  18116. index, RETRO_DEVICE_ID_ANALOG_X);
  18117. float analog_y = input_state(port, RETRO_DEVICE_ANALOG,
  18118. index, RETRO_DEVICE_ID_ANALOG_Y);
  18119. float dx = (analog_x/0x8000)*(desc->range_x/2);
  18120. float dy = (analog_y/0x8000)*(desc->range_y/2);
  18121. desc->delta_x = dx;
  18122. desc->delta_y = dy;
  18123. /*Maybe use some option here instead of 0, only display
  18124. changes greater than some magnitude.
  18125. */
  18126. if ((dx * dx) > 0 || (dy*dy) > 0)
  18127. return true;
  18128. }
  18129. break;
  18130. case OVERLAY_TYPE_KEYBOARD:
  18131. if (input_state(port, RETRO_DEVICE_KEYBOARD, 0, desc->retro_key_idx))
  18132. {
  18133. desc->updated = true;
  18134. return true;
  18135. }
  18136. break;
  18137. default:
  18138. break;
  18139. }
  18140. return false;
  18141. }
  18142. static bool input_overlay_add_inputs(input_overlay_t *ol,
  18143. unsigned port, unsigned analog_dpad_mode)
  18144. {
  18145. unsigned i;
  18146. bool button_pressed = false;
  18147. input_overlay_state_t *ol_state = &ol->overlay_state;
  18148. if (!ol_state)
  18149. return false;
  18150. for (i = 0; i < ol->active->size; i++)
  18151. {
  18152. overlay_desc_t *desc = &(ol->active->descs[i]);
  18153. button_pressed |= input_overlay_add_inputs_inner(desc,
  18154. port, analog_dpad_mode);
  18155. }
  18156. return button_pressed;
  18157. }
  18158. static void input_overlay_parse_layout(
  18159. const struct overlay *ol,
  18160. const overlay_layout_desc_t *layout_desc,
  18161. float display_aspect_ratio,
  18162. overlay_layout_t *overlay_layout)
  18163. {
  18164. /* Set default values */
  18165. overlay_layout->x_scale = 1.0f;
  18166. overlay_layout->y_scale = 1.0f;
  18167. overlay_layout->x_separation = 0.0f;
  18168. overlay_layout->y_separation = 0.0f;
  18169. overlay_layout->x_offset = 0.0f;
  18170. overlay_layout->y_offset = 0.0f;
  18171. /* Perform auto-scaling, if required */
  18172. if (layout_desc->auto_scale)
  18173. {
  18174. /* Sanity check - if scaling is blocked,
  18175. * or aspect ratios are invalid, then we
  18176. * can do nothing */
  18177. if (ol->block_scale ||
  18178. (ol->aspect_ratio <= 0.0f) ||
  18179. (display_aspect_ratio <= 0.0f))
  18180. return;
  18181. /* If display is wider than overlay,
  18182. * reduce width */
  18183. if (display_aspect_ratio >
  18184. ol->aspect_ratio)
  18185. {
  18186. overlay_layout->x_scale = ol->aspect_ratio /
  18187. display_aspect_ratio;
  18188. if (overlay_layout->x_scale <= 0.0f)
  18189. {
  18190. overlay_layout->x_scale = 1.0f;
  18191. return;
  18192. }
  18193. /* If X separation is permitted, move elements
  18194. * horizontally towards the edges of the screen */
  18195. if (!ol->block_x_separation)
  18196. overlay_layout->x_separation = ((1.0f / overlay_layout->x_scale) - 1.0f) * 0.5f;
  18197. }
  18198. /* If display is taller than overlay,
  18199. * reduce height */
  18200. else
  18201. {
  18202. overlay_layout->y_scale = display_aspect_ratio /
  18203. ol->aspect_ratio;
  18204. if (overlay_layout->y_scale <= 0.0f)
  18205. {
  18206. overlay_layout->y_scale = 1.0f;
  18207. return;
  18208. }
  18209. /* If Y separation is permitted and display has
  18210. * a *landscape* orientation, move elements
  18211. * vertically towards the edges of the screen
  18212. * > Portrait overlays typically have all elements
  18213. * below the centre line, so Y separation
  18214. * provides no real benefit */
  18215. if ((display_aspect_ratio > 1.0f) &&
  18216. !ol->block_y_separation)
  18217. overlay_layout->y_separation = ((1.0f / overlay_layout->y_scale) - 1.0f) * 0.5f;
  18218. }
  18219. return;
  18220. }
  18221. /* Regular 'manual' scaling/position adjustment
  18222. * > Landscape display orientations */
  18223. if (display_aspect_ratio > 1.0f)
  18224. {
  18225. float scale = layout_desc->scale_landscape;
  18226. float aspect_adjust = layout_desc->aspect_adjust_landscape;
  18227. /* Note: Y offsets have their sign inverted,
  18228. * since from a usability perspective positive
  18229. * values should move the overlay upwards */
  18230. overlay_layout->x_offset = layout_desc->x_offset_landscape;
  18231. overlay_layout->y_offset = layout_desc->y_offset_landscape * -1.0f;
  18232. if (!ol->block_x_separation)
  18233. overlay_layout->x_separation = layout_desc->x_separation_landscape;
  18234. if (!ol->block_y_separation)
  18235. overlay_layout->y_separation = layout_desc->y_separation_landscape;
  18236. if (!ol->block_scale)
  18237. {
  18238. /* In landscape orientations, aspect correction
  18239. * adjusts the overlay width */
  18240. overlay_layout->x_scale = (aspect_adjust >= 0.0f) ?
  18241. (scale * (aspect_adjust + 1.0f)) :
  18242. (scale / ((aspect_adjust * -1.0f) + 1.0f));
  18243. overlay_layout->y_scale = scale;
  18244. }
  18245. }
  18246. /* > Portrait display orientations */
  18247. else
  18248. {
  18249. float scale = layout_desc->scale_portrait;
  18250. float aspect_adjust = layout_desc->aspect_adjust_portrait;
  18251. overlay_layout->x_offset = layout_desc->x_offset_portrait;
  18252. overlay_layout->y_offset = layout_desc->y_offset_portrait * -1.0f;
  18253. if (!ol->block_x_separation)
  18254. overlay_layout->x_separation = layout_desc->x_separation_portrait;
  18255. if (!ol->block_y_separation)
  18256. overlay_layout->y_separation = layout_desc->y_separation_portrait;
  18257. if (!ol->block_scale)
  18258. {
  18259. /* In portrait orientations, aspect correction
  18260. * adjusts the overlay height */
  18261. overlay_layout->x_scale = scale;
  18262. overlay_layout->y_scale = (aspect_adjust >= 0.0f) ?
  18263. (scale * (aspect_adjust + 1.0f)) :
  18264. (scale / ((aspect_adjust * -1.0f) + 1.0f));
  18265. }
  18266. }
  18267. }
  18268. /**
  18269. * input_overlay_scale:
  18270. * @ol : Overlay handle.
  18271. * @layout : Scale + offset factors.
  18272. *
  18273. * Scales the overlay and all its associated descriptors
  18274. * and applies any aspect ratio/offset factors.
  18275. **/
  18276. static void input_overlay_scale(struct overlay *ol,
  18277. const overlay_layout_t *layout)
  18278. {
  18279. size_t i;
  18280. ol->mod_w = ol->w * layout->x_scale;
  18281. ol->mod_h = ol->h * layout->y_scale;
  18282. ol->mod_x = (ol->center_x + (ol->x - ol->center_x) *
  18283. layout->x_scale) + layout->x_offset;
  18284. ol->mod_y = (ol->center_y + (ol->y - ol->center_y) *
  18285. layout->y_scale) + layout->y_offset;
  18286. for (i = 0; i < ol->size; i++)
  18287. {
  18288. struct overlay_desc *desc = &ol->descs[i];
  18289. float x_shift_offset = 0.0f;
  18290. float y_shift_offset = 0.0f;
  18291. float scale_w;
  18292. float scale_h;
  18293. float adj_center_x;
  18294. float adj_center_y;
  18295. /* Apply 'x separation' factor */
  18296. if (desc->x < (0.5f - 0.0001f))
  18297. x_shift_offset = layout->x_separation * -1.0f;
  18298. else if (desc->x > (0.5f + 0.0001f))
  18299. x_shift_offset = layout->x_separation;
  18300. desc->x_shift = desc->x + x_shift_offset;
  18301. /* Apply 'y separation' factor */
  18302. if (desc->y < (0.5f - 0.0001f))
  18303. y_shift_offset = layout->y_separation * -1.0f;
  18304. else if (desc->y > (0.5f + 0.0001f))
  18305. y_shift_offset = layout->y_separation;
  18306. desc->y_shift = desc->y + y_shift_offset;
  18307. scale_w = ol->mod_w * desc->range_x;
  18308. scale_h = ol->mod_h * desc->range_y;
  18309. adj_center_x = ol->mod_x + desc->x_shift * ol->mod_w;
  18310. adj_center_y = ol->mod_y + desc->y_shift * ol->mod_h;
  18311. desc->mod_w = 2.0f * scale_w;
  18312. desc->mod_h = 2.0f * scale_h;
  18313. desc->mod_x = adj_center_x - scale_w;
  18314. desc->mod_y = adj_center_y - scale_h;
  18315. }
  18316. }
  18317. static void input_overlay_set_vertex_geom(input_overlay_t *ol)
  18318. {
  18319. size_t i;
  18320. if (ol->active->image.pixels)
  18321. ol->iface->vertex_geom(ol->iface_data, 0,
  18322. ol->active->mod_x, ol->active->mod_y,
  18323. ol->active->mod_w, ol->active->mod_h);
  18324. if (ol->iface->vertex_geom)
  18325. for (i = 0; i < ol->active->size; i++)
  18326. {
  18327. struct overlay_desc *desc = &ol->active->descs[i];
  18328. if (!desc->image.pixels)
  18329. continue;
  18330. ol->iface->vertex_geom(ol->iface_data, desc->image_index,
  18331. desc->mod_x, desc->mod_y, desc->mod_w, desc->mod_h);
  18332. }
  18333. }
  18334. /**
  18335. * input_overlay_set_scale_factor:
  18336. * @ol : Overlay handle.
  18337. * @layout_desc : Scale + offset factors.
  18338. *
  18339. * Scales the overlay and applies any aspect ratio/
  18340. * offset factors.
  18341. **/
  18342. static void input_overlay_set_scale_factor(struct rarch_state *p_rarch,
  18343. input_overlay_t *ol, const overlay_layout_desc_t *layout_desc)
  18344. {
  18345. float display_aspect_ratio = 0.0f;
  18346. size_t i;
  18347. if (!ol || !layout_desc)
  18348. return;
  18349. if (p_rarch->video_driver_height > 0)
  18350. display_aspect_ratio = (float)p_rarch->video_driver_width /
  18351. (float)p_rarch->video_driver_height;
  18352. for (i = 0; i < ol->size; i++)
  18353. {
  18354. struct overlay *current_overlay = &ol->overlays[i];
  18355. overlay_layout_t overlay_layout;
  18356. input_overlay_parse_layout(current_overlay,
  18357. layout_desc, display_aspect_ratio, &overlay_layout);
  18358. input_overlay_scale(current_overlay, &overlay_layout);
  18359. }
  18360. input_overlay_set_vertex_geom(ol);
  18361. }
  18362. void input_overlay_free_overlay(struct overlay *overlay)
  18363. {
  18364. size_t i;
  18365. if (!overlay)
  18366. return;
  18367. for (i = 0; i < overlay->size; i++)
  18368. image_texture_free(&overlay->descs[i].image);
  18369. if (overlay->load_images)
  18370. free(overlay->load_images);
  18371. overlay->load_images = NULL;
  18372. if (overlay->descs)
  18373. free(overlay->descs);
  18374. overlay->descs = NULL;
  18375. image_texture_free(&overlay->image);
  18376. }
  18377. static void input_overlay_free_overlays(input_overlay_t *ol)
  18378. {
  18379. size_t i;
  18380. if (!ol || !ol->overlays)
  18381. return;
  18382. for (i = 0; i < ol->size; i++)
  18383. input_overlay_free_overlay(&ol->overlays[i]);
  18384. free(ol->overlays);
  18385. ol->overlays = NULL;
  18386. }
  18387. static enum overlay_visibility input_overlay_get_visibility(
  18388. struct rarch_state *p_rarch,
  18389. int overlay_idx)
  18390. {
  18391. enum overlay_visibility *visibility = p_rarch->overlay_visibility;
  18392. if (!visibility)
  18393. return OVERLAY_VISIBILITY_DEFAULT;
  18394. if ((overlay_idx < 0) || (overlay_idx >= MAX_VISIBILITY))
  18395. return OVERLAY_VISIBILITY_DEFAULT;
  18396. return visibility[overlay_idx];
  18397. }
  18398. static bool input_overlay_is_hidden(
  18399. struct rarch_state *p_rarch,
  18400. int overlay_idx)
  18401. {
  18402. return (input_overlay_get_visibility(p_rarch, overlay_idx)
  18403. == OVERLAY_VISIBILITY_HIDDEN);
  18404. }
  18405. /**
  18406. * input_overlay_set_alpha_mod:
  18407. * @ol : Overlay handle.
  18408. * @mod : New modulating factor to apply.
  18409. *
  18410. * Sets a modulating factor for alpha channel. Default is 1.0.
  18411. * The alpha factor is applied for all overlays.
  18412. **/
  18413. static void input_overlay_set_alpha_mod(
  18414. struct rarch_state *p_rarch,
  18415. input_overlay_t *ol, float mod)
  18416. {
  18417. unsigned i;
  18418. if (!ol)
  18419. return;
  18420. for (i = 0; i < ol->active->load_images_size; i++)
  18421. {
  18422. if (input_overlay_is_hidden(p_rarch, i))
  18423. ol->iface->set_alpha(ol->iface_data, i, 0.0);
  18424. else
  18425. ol->iface->set_alpha(ol->iface_data, i, mod);
  18426. }
  18427. }
  18428. static void input_overlay_load_active(
  18429. struct rarch_state *p_rarch,
  18430. input_overlay_t *ol, float opacity)
  18431. {
  18432. if (ol->iface->load)
  18433. ol->iface->load(ol->iface_data, ol->active->load_images,
  18434. ol->active->load_images_size);
  18435. input_overlay_set_alpha_mod(p_rarch, ol, opacity);
  18436. input_overlay_set_vertex_geom(ol);
  18437. if (ol->iface->full_screen)
  18438. ol->iface->full_screen(ol->iface_data, ol->active->full_screen);
  18439. }
  18440. /* Attempts to automatically rotate the specified overlay.
  18441. * Depends upon proper naming conventions in overlay
  18442. * config file. */
  18443. static void input_overlay_auto_rotate_(
  18444. struct rarch_state *p_rarch, input_overlay_t *ol)
  18445. {
  18446. size_t i;
  18447. enum overlay_orientation screen_orientation = OVERLAY_ORIENTATION_NONE;
  18448. enum overlay_orientation active_overlay_orientation = OVERLAY_ORIENTATION_NONE;
  18449. settings_t *settings = p_rarch->configuration_settings;
  18450. bool input_overlay_enable = settings->bools.input_overlay_enable;
  18451. bool next_overlay_found = false;
  18452. bool tmp = false;
  18453. unsigned next_overlay_index = 0;
  18454. /* Sanity check */
  18455. if (!ol)
  18456. return;
  18457. if (!ol->alive || !input_overlay_enable)
  18458. return;
  18459. /* Get current screen orientation */
  18460. if (p_rarch->video_driver_width > p_rarch->video_driver_height)
  18461. screen_orientation = OVERLAY_ORIENTATION_LANDSCAPE;
  18462. else
  18463. screen_orientation = OVERLAY_ORIENTATION_PORTRAIT;
  18464. /* Get orientation of active overlay */
  18465. if (!string_is_empty(ol->active->name))
  18466. {
  18467. if (strstr(ol->active->name, "landscape"))
  18468. active_overlay_orientation = OVERLAY_ORIENTATION_LANDSCAPE;
  18469. else if (strstr(ol->active->name, "portrait"))
  18470. active_overlay_orientation = OVERLAY_ORIENTATION_PORTRAIT;
  18471. }
  18472. /* Sanity check */
  18473. if (active_overlay_orientation == OVERLAY_ORIENTATION_NONE)
  18474. return;
  18475. /* If screen and overlay have the same orientation,
  18476. * no action is required */
  18477. if (screen_orientation == active_overlay_orientation)
  18478. return;
  18479. /* Attempt to find index of overlay corresponding
  18480. * to opposite orientation */
  18481. for (i = 0; i < p_rarch->overlay_ptr->active->size; i++)
  18482. {
  18483. overlay_desc_t *desc = &p_rarch->overlay_ptr->active->descs[i];
  18484. if (!desc)
  18485. continue;
  18486. if (!string_is_empty(desc->next_index_name))
  18487. {
  18488. if (active_overlay_orientation == OVERLAY_ORIENTATION_LANDSCAPE)
  18489. next_overlay_found = (strstr(desc->next_index_name, "portrait") != 0);
  18490. else
  18491. next_overlay_found = (strstr(desc->next_index_name, "landscape") != 0);
  18492. if (next_overlay_found)
  18493. {
  18494. next_overlay_index = desc->next_index;
  18495. break;
  18496. }
  18497. }
  18498. }
  18499. /* Sanity check */
  18500. if (!next_overlay_found)
  18501. return;
  18502. /* We have a valid target overlay
  18503. * > Trigger 'overly next' command event
  18504. * Note: tmp == false. This prevents CMD_EVENT_OVERLAY_NEXT
  18505. * from calling input_overlay_auto_rotate_() again */
  18506. ol->next_index = next_overlay_index;
  18507. command_event(CMD_EVENT_OVERLAY_NEXT, &tmp);
  18508. }
  18509. /**
  18510. * inside_hitbox:
  18511. * @desc : Overlay descriptor handle.
  18512. * @x : X coordinate value.
  18513. * @y : Y coordinate value.
  18514. *
  18515. * Check whether the given @x and @y coordinates of the overlay
  18516. * descriptor @desc is inside the overlay descriptor's hitbox.
  18517. *
  18518. * Returns: true (1) if X, Y coordinates are inside a hitbox,
  18519. * otherwise false (0).
  18520. **/
  18521. static bool inside_hitbox(const struct overlay_desc *desc, float x, float y)
  18522. {
  18523. if (!desc)
  18524. return false;
  18525. switch (desc->hitbox)
  18526. {
  18527. case OVERLAY_HITBOX_RADIAL:
  18528. {
  18529. /* Ellipsis. */
  18530. float x_dist = (x - desc->x_shift) / desc->range_x_mod;
  18531. float y_dist = (y - desc->y_shift) / desc->range_y_mod;
  18532. float sq_dist = x_dist * x_dist + y_dist * y_dist;
  18533. return (sq_dist <= 1.0f);
  18534. }
  18535. case OVERLAY_HITBOX_RECT:
  18536. return
  18537. (fabs(x - desc->x_shift) <= desc->range_x_mod) &&
  18538. (fabs(y - desc->y_shift) <= desc->range_y_mod);
  18539. }
  18540. return false;
  18541. }
  18542. /**
  18543. * input_overlay_poll:
  18544. * @out : Polled output data.
  18545. * @norm_x : Normalized X coordinate.
  18546. * @norm_y : Normalized Y coordinate.
  18547. *
  18548. * Polls input overlay.
  18549. *
  18550. * @norm_x and @norm_y are the result of
  18551. * input_translate_coord_viewport().
  18552. **/
  18553. static void input_overlay_poll(
  18554. input_overlay_t *ol,
  18555. input_overlay_state_t *out,
  18556. int16_t norm_x, int16_t norm_y)
  18557. {
  18558. size_t i;
  18559. /* norm_x and norm_y is in [-0x7fff, 0x7fff] range,
  18560. * like RETRO_DEVICE_POINTER. */
  18561. float x = (float)(norm_x + 0x7fff) / 0xffff;
  18562. float y = (float)(norm_y + 0x7fff) / 0xffff;
  18563. x -= ol->active->mod_x;
  18564. y -= ol->active->mod_y;
  18565. x /= ol->active->mod_w;
  18566. y /= ol->active->mod_h;
  18567. for (i = 0; i < ol->active->size; i++)
  18568. {
  18569. float x_dist, y_dist;
  18570. unsigned int base = 0;
  18571. struct overlay_desc *desc = &ol->active->descs[i];
  18572. if (!inside_hitbox(desc, x, y))
  18573. continue;
  18574. desc->updated = true;
  18575. x_dist = x - desc->x_shift;
  18576. y_dist = y - desc->y_shift;
  18577. switch (desc->type)
  18578. {
  18579. case OVERLAY_TYPE_BUTTONS:
  18580. {
  18581. bits_or_bits(out->buttons.data,
  18582. desc->button_mask.data,
  18583. ARRAY_SIZE(desc->button_mask.data));
  18584. if (BIT256_GET(desc->button_mask, RARCH_OVERLAY_NEXT))
  18585. ol->next_index = desc->next_index;
  18586. }
  18587. break;
  18588. case OVERLAY_TYPE_KEYBOARD:
  18589. if (desc->retro_key_idx < RETROK_LAST)
  18590. OVERLAY_SET_KEY(out, desc->retro_key_idx);
  18591. break;
  18592. case OVERLAY_TYPE_ANALOG_RIGHT:
  18593. base = 2;
  18594. /* fall-through */
  18595. default:
  18596. {
  18597. float x_val = x_dist / desc->range_x;
  18598. float y_val = y_dist / desc->range_y;
  18599. float x_val_sat = x_val / desc->analog_saturate_pct;
  18600. float y_val_sat = y_val / desc->analog_saturate_pct;
  18601. out->analog[base + 0] = clamp_float(x_val_sat, -1.0f, 1.0f)
  18602. * 32767.0f;
  18603. out->analog[base + 1] = clamp_float(y_val_sat, -1.0f, 1.0f)
  18604. * 32767.0f;
  18605. }
  18606. break;
  18607. }
  18608. if (desc->movable)
  18609. {
  18610. desc->delta_x = clamp_float(x_dist, -desc->range_x, desc->range_x)
  18611. * ol->active->mod_w;
  18612. desc->delta_y = clamp_float(y_dist, -desc->range_y, desc->range_y)
  18613. * ol->active->mod_h;
  18614. }
  18615. }
  18616. if (!bits_any_set(out->buttons.data, ARRAY_SIZE(out->buttons.data)))
  18617. ol->blocked = false;
  18618. else if (ol->blocked)
  18619. memset(out, 0, sizeof(*out));
  18620. }
  18621. /**
  18622. * input_overlay_update_desc_geom:
  18623. * @ol : overlay handle.
  18624. * @desc : overlay descriptors handle.
  18625. *
  18626. * Update input overlay descriptors' vertex geometry.
  18627. **/
  18628. static void input_overlay_update_desc_geom(input_overlay_t *ol,
  18629. struct overlay_desc *desc)
  18630. {
  18631. if (!desc->image.pixels || !desc->movable)
  18632. return;
  18633. if (ol->iface->vertex_geom)
  18634. ol->iface->vertex_geom(ol->iface_data, desc->image_index,
  18635. desc->mod_x + desc->delta_x, desc->mod_y + desc->delta_y,
  18636. desc->mod_w, desc->mod_h);
  18637. desc->delta_x = 0.0f;
  18638. desc->delta_y = 0.0f;
  18639. }
  18640. /**
  18641. * input_overlay_post_poll:
  18642. *
  18643. * Called after all the input_overlay_poll() calls to
  18644. * update the range modifiers for pressed/unpressed regions
  18645. * and alpha mods.
  18646. **/
  18647. static void input_overlay_post_poll(
  18648. struct rarch_state *p_rarch,
  18649. input_overlay_t *ol, float opacity)
  18650. {
  18651. size_t i;
  18652. input_overlay_set_alpha_mod(p_rarch, ol, opacity);
  18653. for (i = 0; i < ol->active->size; i++)
  18654. {
  18655. struct overlay_desc *desc = &ol->active->descs[i];
  18656. desc->range_x_mod = desc->range_x;
  18657. desc->range_y_mod = desc->range_y;
  18658. if (desc->updated)
  18659. {
  18660. /* If pressed this frame, change the hitbox. */
  18661. desc->range_x_mod *= desc->range_mod;
  18662. desc->range_y_mod *= desc->range_mod;
  18663. if (desc->image.pixels)
  18664. {
  18665. if (ol->iface->set_alpha)
  18666. ol->iface->set_alpha(ol->iface_data, desc->image_index,
  18667. desc->alpha_mod * opacity);
  18668. }
  18669. }
  18670. input_overlay_update_desc_geom(ol, desc);
  18671. desc->updated = false;
  18672. }
  18673. }
  18674. /**
  18675. * input_overlay_poll_clear:
  18676. * @ol : overlay handle
  18677. *
  18678. * Call when there is nothing to poll. Allows overlay to
  18679. * clear certain state.
  18680. **/
  18681. static void input_overlay_poll_clear(
  18682. struct rarch_state *p_rarch,
  18683. input_overlay_t *ol, float opacity)
  18684. {
  18685. size_t i;
  18686. ol->blocked = false;
  18687. input_overlay_set_alpha_mod(p_rarch, ol, opacity);
  18688. for (i = 0; i < ol->active->size; i++)
  18689. {
  18690. struct overlay_desc *desc = &ol->active->descs[i];
  18691. desc->range_x_mod = desc->range_x;
  18692. desc->range_y_mod = desc->range_y;
  18693. desc->updated = false;
  18694. desc->delta_x = 0.0f;
  18695. desc->delta_y = 0.0f;
  18696. input_overlay_update_desc_geom(ol, desc);
  18697. }
  18698. }
  18699. /**
  18700. * input_overlay_free:
  18701. * @ol : Overlay handle.
  18702. *
  18703. * Frees overlay handle.
  18704. **/
  18705. static void input_overlay_free(input_overlay_t *ol)
  18706. {
  18707. if (!ol)
  18708. return;
  18709. input_overlay_free_overlays(ol);
  18710. if (ol->iface->enable)
  18711. ol->iface->enable(ol->iface_data, false);
  18712. free(ol);
  18713. }
  18714. /* task_data = overlay_task_data_t* */
  18715. static void input_overlay_loaded(retro_task_t *task,
  18716. void *task_data, void *user_data, const char *err)
  18717. {
  18718. size_t i;
  18719. struct rarch_state *p_rarch = &rarch_st;
  18720. overlay_task_data_t *data = (overlay_task_data_t*)task_data;
  18721. input_overlay_t *ol = NULL;
  18722. const video_overlay_interface_t *iface = NULL;
  18723. settings_t *settings = p_rarch->configuration_settings;
  18724. bool input_overlay_show_mouse_cursor = settings->bools.input_overlay_show_mouse_cursor;
  18725. bool inp_overlay_auto_rotate = settings->bools.input_overlay_auto_rotate;
  18726. if (err)
  18727. return;
  18728. if (data->overlay_enable)
  18729. {
  18730. #ifdef HAVE_MENU
  18731. /* We can't display when the menu is up */
  18732. if (data->hide_in_menu && p_rarch->menu_driver_alive)
  18733. goto abort_load;
  18734. #endif
  18735. /* If 'hide_when_gamepad_connected' is enabled,
  18736. * we can't display when a gamepad is connected */
  18737. if (data->hide_when_gamepad_connected &&
  18738. (input_config_get_device_name(0) != NULL))
  18739. goto abort_load;
  18740. }
  18741. if ( !data->overlay_enable ||
  18742. !video_driver_overlay_interface(&iface) ||
  18743. !iface)
  18744. {
  18745. RARCH_ERR("Overlay interface is not present in video driver,"
  18746. " or not enabled.\n");
  18747. goto abort_load;
  18748. }
  18749. ol = (input_overlay_t*)calloc(1, sizeof(*ol));
  18750. ol->overlays = data->overlays;
  18751. ol->size = data->size;
  18752. ol->active = data->active;
  18753. ol->iface = iface;
  18754. ol->iface_data = VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch, true);
  18755. input_overlay_load_active(p_rarch, ol, data->overlay_opacity);
  18756. /* Enable or disable the overlay. */
  18757. ol->enable = data->overlay_enable;
  18758. if (ol->iface->enable)
  18759. ol->iface->enable(ol->iface_data, data->overlay_enable);
  18760. input_overlay_set_scale_factor(p_rarch, ol, &data->layout_desc);
  18761. ol->next_index = (unsigned)((ol->index + 1) % ol->size);
  18762. ol->state = OVERLAY_STATUS_NONE;
  18763. ol->alive = true;
  18764. /* Due to the asynchronous nature of overlay loading
  18765. * it is possible for overlay_ptr to be non-NULL here
  18766. * > Ensure it is free()'d before assigning new pointer */
  18767. if (p_rarch->overlay_ptr)
  18768. {
  18769. input_overlay_free_overlays(p_rarch->overlay_ptr);
  18770. free(p_rarch->overlay_ptr);
  18771. }
  18772. p_rarch->overlay_ptr = ol;
  18773. free(data);
  18774. if (!input_overlay_show_mouse_cursor)
  18775. video_driver_hide_mouse();
  18776. /* Attempt to automatically rotate overlay, if required */
  18777. if (inp_overlay_auto_rotate)
  18778. input_overlay_auto_rotate_(p_rarch,
  18779. p_rarch->overlay_ptr);
  18780. return;
  18781. abort_load:
  18782. for (i = 0; i < data->size; i++)
  18783. input_overlay_free_overlay(&data->overlays[i]);
  18784. free(data->overlays);
  18785. free(data);
  18786. }
  18787. void input_overlay_set_visibility(int overlay_idx,
  18788. enum overlay_visibility vis)
  18789. {
  18790. struct rarch_state *p_rarch = &rarch_st;
  18791. input_overlay_t *ol = p_rarch->overlay_ptr;
  18792. if (!p_rarch->overlay_visibility)
  18793. {
  18794. unsigned i;
  18795. p_rarch->overlay_visibility = (enum overlay_visibility *)calloc(
  18796. MAX_VISIBILITY, sizeof(enum overlay_visibility));
  18797. for (i = 0; i < MAX_VISIBILITY; i++)
  18798. p_rarch->overlay_visibility[i] = OVERLAY_VISIBILITY_DEFAULT;
  18799. }
  18800. p_rarch->overlay_visibility[overlay_idx] = vis;
  18801. if (!ol)
  18802. return;
  18803. if (vis == OVERLAY_VISIBILITY_HIDDEN)
  18804. ol->iface->set_alpha(ol->iface_data, overlay_idx, 0.0);
  18805. }
  18806. /*
  18807. * input_poll_overlay:
  18808. *
  18809. * Poll pressed buttons/keys on currently active overlay.
  18810. **/
  18811. static void input_poll_overlay(
  18812. struct rarch_state *p_rarch,
  18813. input_overlay_t *ol, float opacity,
  18814. unsigned analog_dpad_mode,
  18815. float axis_threshold)
  18816. {
  18817. input_overlay_state_t old_key_state;
  18818. unsigned i, j;
  18819. uint16_t key_mod = 0;
  18820. bool polled = false;
  18821. bool button_pressed = false;
  18822. void *input_data = p_rarch->current_input_data;
  18823. input_overlay_state_t *ol_state = &ol->overlay_state;
  18824. input_driver_t *current_input = p_rarch->current_input;
  18825. settings_t *settings = p_rarch->configuration_settings;
  18826. bool input_overlay_show_physical_inputs = settings->bools.input_overlay_show_physical_inputs;
  18827. unsigned input_overlay_show_physical_inputs_port = settings->uints.input_overlay_show_physical_inputs_port;
  18828. if (!ol_state)
  18829. return;
  18830. memcpy(old_key_state.keys, ol_state->keys,
  18831. sizeof(ol_state->keys));
  18832. memset(ol_state, 0, sizeof(*ol_state));
  18833. if (current_input->input_state)
  18834. {
  18835. rarch_joypad_info_t joypad_info;
  18836. unsigned device = ol->active->full_screen
  18837. ? RARCH_DEVICE_POINTER_SCREEN
  18838. : RETRO_DEVICE_POINTER;
  18839. #ifdef HAVE_MFI
  18840. const input_device_driver_t
  18841. *sec_joypad = p_rarch->sec_joypad;
  18842. #else
  18843. const input_device_driver_t
  18844. *sec_joypad = NULL;
  18845. #endif
  18846. joypad_info.joy_idx = 0;
  18847. joypad_info.auto_binds = NULL;
  18848. joypad_info.axis_threshold = 0.0f;
  18849. for (i = 0;
  18850. current_input->input_state(
  18851. input_data,
  18852. p_rarch->joypad,
  18853. sec_joypad,
  18854. &joypad_info,
  18855. NULL,
  18856. p_rarch->keyboard_mapping_blocked,
  18857. 0,
  18858. device,
  18859. i,
  18860. RETRO_DEVICE_ID_POINTER_PRESSED);
  18861. i++)
  18862. {
  18863. input_overlay_state_t polled_data;
  18864. int16_t x = current_input->input_state(
  18865. input_data,
  18866. p_rarch->joypad,
  18867. sec_joypad,
  18868. &joypad_info,
  18869. NULL,
  18870. p_rarch->keyboard_mapping_blocked,
  18871. 0,
  18872. device,
  18873. i,
  18874. RETRO_DEVICE_ID_POINTER_X);
  18875. int16_t y = current_input->input_state(
  18876. input_data,
  18877. p_rarch->joypad,
  18878. sec_joypad,
  18879. &joypad_info,
  18880. NULL,
  18881. p_rarch->keyboard_mapping_blocked,
  18882. 0,
  18883. device,
  18884. i,
  18885. RETRO_DEVICE_ID_POINTER_Y);
  18886. memset(&polled_data, 0, sizeof(struct input_overlay_state));
  18887. if (ol->enable)
  18888. input_overlay_poll(ol, &polled_data, x, y);
  18889. else
  18890. ol->blocked = false;
  18891. bits_or_bits(ol_state->buttons.data,
  18892. polled_data.buttons.data,
  18893. ARRAY_SIZE(polled_data.buttons.data));
  18894. for (j = 0; j < ARRAY_SIZE(ol_state->keys); j++)
  18895. ol_state->keys[j] |= polled_data.keys[j];
  18896. /* Fingers pressed later take priority and matched up
  18897. * with overlay poll priorities. */
  18898. for (j = 0; j < 4; j++)
  18899. if (polled_data.analog[j])
  18900. ol_state->analog[j] = polled_data.analog[j];
  18901. polled = true;
  18902. }
  18903. }
  18904. if ( OVERLAY_GET_KEY(ol_state, RETROK_LSHIFT) ||
  18905. OVERLAY_GET_KEY(ol_state, RETROK_RSHIFT))
  18906. key_mod |= RETROKMOD_SHIFT;
  18907. if (OVERLAY_GET_KEY(ol_state, RETROK_LCTRL) ||
  18908. OVERLAY_GET_KEY(ol_state, RETROK_RCTRL))
  18909. key_mod |= RETROKMOD_CTRL;
  18910. if ( OVERLAY_GET_KEY(ol_state, RETROK_LALT) ||
  18911. OVERLAY_GET_KEY(ol_state, RETROK_RALT))
  18912. key_mod |= RETROKMOD_ALT;
  18913. if ( OVERLAY_GET_KEY(ol_state, RETROK_LMETA) ||
  18914. OVERLAY_GET_KEY(ol_state, RETROK_RMETA))
  18915. key_mod |= RETROKMOD_META;
  18916. /* CAPSLOCK SCROLLOCK NUMLOCK */
  18917. for (i = 0; i < ARRAY_SIZE(ol_state->keys); i++)
  18918. {
  18919. if (ol_state->keys[i] != old_key_state.keys[i])
  18920. {
  18921. uint32_t orig_bits = old_key_state.keys[i];
  18922. uint32_t new_bits = ol_state->keys[i];
  18923. for (j = 0; j < 32; j++)
  18924. if ((orig_bits & (1 << j)) != (new_bits & (1 << j)))
  18925. input_keyboard_event(new_bits & (1 << j),
  18926. i * 32 + j, 0, key_mod, RETRO_DEVICE_POINTER);
  18927. }
  18928. }
  18929. /* Map "analog" buttons to analog axes like regular input drivers do. */
  18930. for (j = 0; j < 4; j++)
  18931. {
  18932. unsigned bind_plus = RARCH_ANALOG_LEFT_X_PLUS + 2 * j;
  18933. unsigned bind_minus = bind_plus + 1;
  18934. if (ol_state->analog[j])
  18935. continue;
  18936. if ((BIT256_GET(ol->overlay_state.buttons, bind_plus)))
  18937. ol_state->analog[j] += 0x7fff;
  18938. if ((BIT256_GET(ol->overlay_state.buttons, bind_minus)))
  18939. ol_state->analog[j] -= 0x7fff;
  18940. }
  18941. /* Check for analog_dpad_mode.
  18942. * Map analogs to d-pad buttons when configured. */
  18943. switch (analog_dpad_mode)
  18944. {
  18945. case ANALOG_DPAD_LSTICK:
  18946. case ANALOG_DPAD_RSTICK:
  18947. {
  18948. float analog_x, analog_y;
  18949. unsigned analog_base = 2;
  18950. if (analog_dpad_mode == ANALOG_DPAD_LSTICK)
  18951. analog_base = 0;
  18952. analog_x = (float)ol_state->analog[analog_base + 0] / 0x7fff;
  18953. analog_y = (float)ol_state->analog[analog_base + 1] / 0x7fff;
  18954. if (analog_x <= -axis_threshold)
  18955. BIT256_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_LEFT);
  18956. if (analog_x >= axis_threshold)
  18957. BIT256_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_RIGHT);
  18958. if (analog_y <= -axis_threshold)
  18959. BIT256_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_UP);
  18960. if (analog_y >= axis_threshold)
  18961. BIT256_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_DOWN);
  18962. break;
  18963. }
  18964. default:
  18965. break;
  18966. }
  18967. if (input_overlay_show_physical_inputs)
  18968. button_pressed = input_overlay_add_inputs(ol,
  18969. input_overlay_show_physical_inputs_port,
  18970. analog_dpad_mode);
  18971. if (button_pressed || polled)
  18972. input_overlay_post_poll(p_rarch, ol, opacity);
  18973. else
  18974. input_overlay_poll_clear(p_rarch, ol, opacity);
  18975. }
  18976. static void retroarch_overlay_deinit(struct rarch_state *p_rarch)
  18977. {
  18978. input_overlay_free(p_rarch->overlay_ptr);
  18979. p_rarch->overlay_ptr = NULL;
  18980. }
  18981. static void retroarch_overlay_init(struct rarch_state *p_rarch)
  18982. {
  18983. settings_t *settings = p_rarch->configuration_settings;
  18984. bool input_overlay_enable = settings->bools.input_overlay_enable;
  18985. bool input_overlay_auto_scale = settings->bools.input_overlay_auto_scale;
  18986. const char *path_overlay = settings->paths.path_overlay;
  18987. float overlay_opacity = settings->floats.input_overlay_opacity;
  18988. float overlay_scale_landscape = settings->floats.input_overlay_scale_landscape;
  18989. float overlay_aspect_adjust_landscape = settings->floats.input_overlay_aspect_adjust_landscape;
  18990. float overlay_x_separation_landscape = settings->floats.input_overlay_x_separation_landscape;
  18991. float overlay_y_separation_landscape = settings->floats.input_overlay_y_separation_landscape;
  18992. float overlay_x_offset_landscape = settings->floats.input_overlay_x_offset_landscape;
  18993. float overlay_y_offset_landscape = settings->floats.input_overlay_y_offset_landscape;
  18994. float overlay_scale_portrait = settings->floats.input_overlay_scale_portrait;
  18995. float overlay_aspect_adjust_portrait = settings->floats.input_overlay_aspect_adjust_portrait;
  18996. float overlay_x_separation_portrait = settings->floats.input_overlay_x_separation_portrait;
  18997. float overlay_y_separation_portrait = settings->floats.input_overlay_y_separation_portrait;
  18998. float overlay_x_offset_portrait = settings->floats.input_overlay_x_offset_portrait;
  18999. float overlay_y_offset_portrait = settings->floats.input_overlay_y_offset_portrait;
  19000. bool load_enabled = input_overlay_enable;
  19001. #ifdef HAVE_MENU
  19002. bool overlay_hide_in_menu = settings->bools.input_overlay_hide_in_menu;
  19003. #else
  19004. bool overlay_hide_in_menu = false;
  19005. #endif
  19006. bool overlay_hide_when_gamepad_connected = settings->bools.input_overlay_hide_when_gamepad_connected;
  19007. #if defined(GEKKO)
  19008. /* Avoid a crash at startup or even when toggling overlay in rgui */
  19009. uint64_t memory_free = frontend_driver_get_free_memory();
  19010. if (memory_free < (3 * 1024 * 1024))
  19011. return;
  19012. #endif
  19013. retroarch_overlay_deinit(p_rarch);
  19014. #ifdef HAVE_MENU
  19015. /* Cancel load if 'hide_in_menu' is enabled and
  19016. * menu is currently active */
  19017. if (overlay_hide_in_menu)
  19018. load_enabled = load_enabled && !p_rarch->menu_driver_alive;
  19019. #endif
  19020. /* Cancel load if 'hide_when_gamepad_connected' is
  19021. * enabled and a gamepad is currently connected */
  19022. if (overlay_hide_when_gamepad_connected)
  19023. load_enabled = load_enabled && (input_config_get_device_name(0) == NULL);
  19024. if (load_enabled)
  19025. {
  19026. overlay_layout_desc_t layout_desc;
  19027. layout_desc.scale_landscape = overlay_scale_landscape;
  19028. layout_desc.aspect_adjust_landscape = overlay_aspect_adjust_landscape;
  19029. layout_desc.x_separation_landscape = overlay_x_separation_landscape;
  19030. layout_desc.y_separation_landscape = overlay_y_separation_landscape;
  19031. layout_desc.x_offset_landscape = overlay_x_offset_landscape;
  19032. layout_desc.y_offset_landscape = overlay_y_offset_landscape;
  19033. layout_desc.scale_portrait = overlay_scale_portrait;
  19034. layout_desc.aspect_adjust_portrait = overlay_aspect_adjust_portrait;
  19035. layout_desc.x_separation_portrait = overlay_x_separation_portrait;
  19036. layout_desc.y_separation_portrait = overlay_y_separation_portrait;
  19037. layout_desc.x_offset_portrait = overlay_x_offset_portrait;
  19038. layout_desc.y_offset_portrait = overlay_y_offset_portrait;
  19039. layout_desc.auto_scale = input_overlay_auto_scale;
  19040. task_push_overlay_load_default(input_overlay_loaded,
  19041. path_overlay,
  19042. overlay_hide_in_menu,
  19043. overlay_hide_when_gamepad_connected,
  19044. input_overlay_enable,
  19045. overlay_opacity,
  19046. &layout_desc,
  19047. NULL);
  19048. }
  19049. }
  19050. #endif
  19051. /* INPUT REMOTE */
  19052. #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD)
  19053. static bool input_remote_init_network(input_remote_t *handle,
  19054. uint16_t port, unsigned user)
  19055. {
  19056. int fd;
  19057. struct addrinfo *res = NULL;
  19058. port = port + user;
  19059. if (!network_init())
  19060. return false;
  19061. RARCH_LOG("Bringing up remote interface on port %hu.\n",
  19062. (unsigned short)port);
  19063. fd = socket_init((void**)&res, port, NULL, SOCKET_TYPE_DATAGRAM);
  19064. if (fd < 0)
  19065. goto error;
  19066. handle->net_fd[user] = fd;
  19067. if (!socket_nonblock(handle->net_fd[user]))
  19068. goto error;
  19069. if (!socket_bind(handle->net_fd[user], res))
  19070. {
  19071. RARCH_ERR("%s\n", msg_hash_to_str(MSG_FAILED_TO_BIND_SOCKET));
  19072. goto error;
  19073. }
  19074. freeaddrinfo_retro(res);
  19075. return true;
  19076. error:
  19077. if (res)
  19078. freeaddrinfo_retro(res);
  19079. return false;
  19080. }
  19081. static void input_remote_free(input_remote_t *handle, unsigned max_users)
  19082. {
  19083. unsigned user;
  19084. for (user = 0; user < max_users; user ++)
  19085. socket_close(handle->net_fd[user]);
  19086. free(handle);
  19087. }
  19088. static input_remote_t *input_remote_new(
  19089. settings_t *settings,
  19090. uint16_t port, unsigned max_users)
  19091. {
  19092. unsigned user;
  19093. input_remote_t *handle = (input_remote_t*)
  19094. calloc(1, sizeof(*handle));
  19095. if (!handle)
  19096. return NULL;
  19097. for (user = 0; user < max_users; user ++)
  19098. {
  19099. handle->net_fd[user] = -1;
  19100. if (settings->bools.network_remote_enable_user[user])
  19101. if (!input_remote_init_network(handle, port, user))
  19102. {
  19103. input_remote_free(handle, max_users);
  19104. return NULL;
  19105. }
  19106. }
  19107. return handle;
  19108. }
  19109. static void input_remote_parse_packet(
  19110. input_remote_state_t *input_state,
  19111. struct remote_message *msg, unsigned user)
  19112. {
  19113. /* Parse message */
  19114. switch (msg->device)
  19115. {
  19116. case RETRO_DEVICE_JOYPAD:
  19117. input_state->buttons[user] &= ~(1 << msg->id);
  19118. if (msg->state)
  19119. input_state->buttons[user] |= 1 << msg->id;
  19120. break;
  19121. case RETRO_DEVICE_ANALOG:
  19122. input_state->analog[msg->index * 2 + msg->id][user] = msg->state;
  19123. break;
  19124. }
  19125. }
  19126. #endif
  19127. /* INPUT */
  19128. void set_connection_listener(pad_connection_listener_t *listener)
  19129. {
  19130. struct rarch_state *p_rarch = &rarch_st;
  19131. p_rarch->pad_connection_listener = listener;
  19132. }
  19133. /**
  19134. * config_get_input_driver_options:
  19135. *
  19136. * Get an enumerated list of all input driver names, separated by '|'.
  19137. *
  19138. * Returns: string listing of all input driver names, separated by '|'.
  19139. **/
  19140. const char* config_get_input_driver_options(void)
  19141. {
  19142. return char_list_new_special(STRING_LIST_INPUT_DRIVERS, NULL);
  19143. }
  19144. /**
  19145. * input_driver_set_rumble_state:
  19146. * @port : User number.
  19147. * @effect : Rumble effect.
  19148. * @strength : Strength of rumble effect.
  19149. *
  19150. * Sets the rumble state.
  19151. * Used by RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE.
  19152. **/
  19153. bool input_driver_set_rumble_state(unsigned port,
  19154. enum retro_rumble_effect effect, uint16_t strength)
  19155. {
  19156. struct rarch_state *p_rarch = &rarch_st;
  19157. settings_t *settings = p_rarch->configuration_settings;
  19158. #ifdef HAVE_MFI
  19159. const input_device_driver_t *sec_joypad = p_rarch->sec_joypad;
  19160. #else
  19161. const input_device_driver_t *sec_joypad = NULL;
  19162. #endif
  19163. bool rumble_state = false;
  19164. unsigned joy_idx = settings->uints.input_joypad_map[port];
  19165. if (joy_idx >= MAX_USERS)
  19166. return false;
  19167. if (p_rarch->joypad && p_rarch->joypad->set_rumble)
  19168. rumble_state = p_rarch->joypad->set_rumble(
  19169. joy_idx, effect, strength);
  19170. if (sec_joypad && sec_joypad->set_rumble)
  19171. rumble_state = sec_joypad->set_rumble(
  19172. joy_idx, effect, strength);
  19173. return rumble_state;
  19174. }
  19175. const char *joypad_driver_name(unsigned i)
  19176. {
  19177. struct rarch_state *p_rarch = &rarch_st;
  19178. if (!p_rarch || !p_rarch->joypad || !p_rarch->joypad->name)
  19179. return NULL;
  19180. return p_rarch->joypad->name(i);
  19181. }
  19182. void joypad_driver_reinit(void *data, const char *joypad_driver_name)
  19183. {
  19184. struct rarch_state *p_rarch = &rarch_st;
  19185. if (!p_rarch)
  19186. return;
  19187. if (p_rarch->joypad)
  19188. p_rarch->joypad->destroy();
  19189. p_rarch->joypad = NULL;
  19190. #ifdef HAVE_MFI
  19191. if (p_rarch->sec_joypad)
  19192. p_rarch->sec_joypad->destroy();
  19193. p_rarch->sec_joypad = NULL;
  19194. #endif
  19195. p_rarch->joypad = input_joypad_init_driver(joypad_driver_name, data);
  19196. #ifdef HAVE_MFI
  19197. p_rarch->sec_joypad = input_joypad_init_driver("mfi", data);
  19198. #endif
  19199. }
  19200. static uint64_t input_driver_get_capabilities(void)
  19201. {
  19202. struct rarch_state *p_rarch = &rarch_st;
  19203. if (!p_rarch->current_input || !p_rarch->current_input->get_capabilities)
  19204. return 0;
  19205. return p_rarch->current_input->get_capabilities(p_rarch->current_input_data);
  19206. }
  19207. /**
  19208. * input_sensor_set_state:
  19209. * @port : User number.
  19210. * @effect : Sensor action.
  19211. * @rate : Sensor rate update.
  19212. *
  19213. * Sets the sensor state.
  19214. * Used by RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE.
  19215. **/
  19216. bool input_sensor_set_state(unsigned port,
  19217. enum retro_sensor_action action, unsigned rate)
  19218. {
  19219. struct rarch_state *p_rarch = &rarch_st;
  19220. settings_t *settings = p_rarch->configuration_settings;
  19221. bool input_sensors_enable = settings->bools.input_sensors_enable;
  19222. /* If sensors are disabled, inhibit any enable
  19223. * actions (but always allow disable actions) */
  19224. if (!input_sensors_enable &&
  19225. ((action == RETRO_SENSOR_ACCELEROMETER_ENABLE) ||
  19226. (action == RETRO_SENSOR_GYROSCOPE_ENABLE) ||
  19227. (action == RETRO_SENSOR_ILLUMINANCE_ENABLE)))
  19228. return false;
  19229. if (p_rarch->current_input_data &&
  19230. p_rarch->current_input->set_sensor_state)
  19231. return p_rarch->current_input->set_sensor_state(p_rarch->current_input_data,
  19232. port, action, rate);
  19233. return false;
  19234. }
  19235. float input_sensor_get_input(unsigned port, unsigned id)
  19236. {
  19237. struct rarch_state *p_rarch = &rarch_st;
  19238. settings_t *settings = p_rarch->configuration_settings;
  19239. bool input_sensors_enable = settings->bools.input_sensors_enable;
  19240. if (input_sensors_enable &&
  19241. p_rarch->current_input_data &&
  19242. p_rarch->current_input->get_sensor_input)
  19243. return p_rarch->current_input->get_sensor_input(p_rarch->current_input_data,
  19244. port, id);
  19245. return 0.0f;
  19246. }
  19247. /**
  19248. * input_poll:
  19249. *
  19250. * Input polling callback function.
  19251. **/
  19252. static void input_driver_poll(void)
  19253. {
  19254. size_t i, j;
  19255. rarch_joypad_info_t joypad_info[MAX_USERS];
  19256. struct rarch_state *p_rarch = &rarch_st;
  19257. settings_t *settings = p_rarch->configuration_settings;
  19258. #ifdef HAVE_MFI
  19259. const input_device_driver_t
  19260. *sec_joypad = p_rarch->sec_joypad;
  19261. #else
  19262. const input_device_driver_t
  19263. *sec_joypad = NULL;
  19264. #endif
  19265. #ifdef HAVE_OVERLAY
  19266. float input_overlay_opacity = settings->floats.input_overlay_opacity;
  19267. #endif
  19268. bool input_remap_binds_enable = settings->bools.input_remap_binds_enable;
  19269. uint8_t max_users = (uint8_t)p_rarch->input_driver_max_users;
  19270. if ( p_rarch->joypad
  19271. && p_rarch->joypad->poll)
  19272. p_rarch->joypad->poll();
  19273. #ifdef HAVE_MFI
  19274. if ( p_rarch->sec_joypad
  19275. && p_rarch->sec_joypad->poll)
  19276. p_rarch->sec_joypad->poll();
  19277. #endif
  19278. if ( p_rarch->current_input
  19279. && p_rarch->current_input->poll)
  19280. p_rarch->current_input->poll(p_rarch->current_input_data);
  19281. p_rarch->input_driver_turbo_btns.count++;
  19282. if (p_rarch->input_driver_block_libretro_input)
  19283. {
  19284. for (i = 0; i < max_users; i++)
  19285. p_rarch->input_driver_turbo_btns.frame_enable[i] = 0;
  19286. return;
  19287. }
  19288. for (i = 0; i < max_users; i++)
  19289. {
  19290. joypad_info[i].axis_threshold = p_rarch->input_driver_axis_threshold;
  19291. joypad_info[i].joy_idx = settings->uints.input_joypad_map[i];
  19292. joypad_info[i].auto_binds = input_autoconf_binds[joypad_info[i].joy_idx];
  19293. p_rarch->input_driver_turbo_btns.frame_enable[i] = p_rarch->libretro_input_binds[i][RARCH_TURBO_ENABLE].valid ?
  19294. input_state_wrap(
  19295. p_rarch->current_input,
  19296. p_rarch->current_input_data,
  19297. p_rarch->joypad,
  19298. sec_joypad,
  19299. &joypad_info[i],
  19300. p_rarch->libretro_input_binds,
  19301. p_rarch->keyboard_mapping_blocked,
  19302. (unsigned)i,
  19303. RETRO_DEVICE_JOYPAD,
  19304. 0,
  19305. RARCH_TURBO_ENABLE) : 0;
  19306. }
  19307. #ifdef HAVE_OVERLAY
  19308. if (p_rarch->overlay_ptr && p_rarch->overlay_ptr->alive)
  19309. input_poll_overlay(p_rarch,
  19310. p_rarch->overlay_ptr,
  19311. input_overlay_opacity,
  19312. settings->uints.input_analog_dpad_mode[0],
  19313. p_rarch->input_driver_axis_threshold);
  19314. #endif
  19315. #ifdef HAVE_MENU
  19316. if (!p_rarch->menu_driver_alive)
  19317. #endif
  19318. if (input_remap_binds_enable)
  19319. {
  19320. #ifdef HAVE_OVERLAY
  19321. input_overlay_t *overlay_pointer = (input_overlay_t*)p_rarch->overlay_ptr;
  19322. bool poll_overlay = (p_rarch->overlay_ptr && p_rarch->overlay_ptr->alive);
  19323. #endif
  19324. input_mapper_t *handle = p_rarch->input_driver_mapper;
  19325. const input_device_driver_t *joypad_driver
  19326. = p_rarch->joypad;
  19327. for (i = 0; i < max_users; i++)
  19328. {
  19329. input_bits_t current_inputs;
  19330. unsigned device
  19331. = settings->uints.input_libretro_device[i]
  19332. & RETRO_DEVICE_MASK;
  19333. input_bits_t *p_new_state
  19334. = (input_bits_t*)&current_inputs;
  19335. switch (device)
  19336. {
  19337. case RETRO_DEVICE_KEYBOARD:
  19338. case RETRO_DEVICE_JOYPAD:
  19339. case RETRO_DEVICE_ANALOG:
  19340. BIT256_CLEAR_ALL_PTR(&current_inputs);
  19341. if (joypad_driver)
  19342. {
  19343. unsigned k, j;
  19344. int16_t ret = input_state_wrap(
  19345. p_rarch->current_input,
  19346. p_rarch->current_input_data,
  19347. p_rarch->joypad,
  19348. sec_joypad,
  19349. &joypad_info[i],
  19350. p_rarch->libretro_input_binds,
  19351. p_rarch->keyboard_mapping_blocked,
  19352. (unsigned)i, RETRO_DEVICE_JOYPAD,
  19353. 0, RETRO_DEVICE_ID_JOYPAD_MASK);
  19354. for (k = 0; k < RARCH_FIRST_CUSTOM_BIND; k++)
  19355. {
  19356. if (ret & (1 << k))
  19357. {
  19358. bool valid_bind =
  19359. p_rarch->libretro_input_binds[i][k].valid;
  19360. if (valid_bind)
  19361. {
  19362. int16_t val =
  19363. input_joypad_analog_button(
  19364. p_rarch, settings,
  19365. joypad_driver, &joypad_info[i], (unsigned)i,
  19366. RETRO_DEVICE_INDEX_ANALOG_BUTTON, k,
  19367. p_rarch->libretro_input_binds[i]);
  19368. if (val)
  19369. p_new_state->analog_buttons[k] = val;
  19370. }
  19371. BIT256_SET_PTR(p_new_state, k);
  19372. }
  19373. }
  19374. /* This is the analog joypad index -
  19375. * handles only the two analog axes */
  19376. for (k = 0; k < 2; k++)
  19377. {
  19378. /* This is the analog joypad ident */
  19379. for (j = 0; j < 2; j++)
  19380. {
  19381. unsigned offset = 0 + (k * 4) + (j * 2);
  19382. int16_t val = input_joypad_analog_axis(
  19383. p_rarch,
  19384. settings,
  19385. joypad_driver,
  19386. &joypad_info[i], (unsigned)i, k, j,
  19387. p_rarch->libretro_input_binds[i]);
  19388. if (val >= 0)
  19389. p_new_state->analogs[offset] = val;
  19390. else
  19391. p_new_state->analogs[offset+1] = val;
  19392. }
  19393. }
  19394. }
  19395. break;
  19396. default:
  19397. break;
  19398. }
  19399. /* mapper */
  19400. switch (device)
  19401. {
  19402. /* keyboard to gamepad remapping */
  19403. case RETRO_DEVICE_KEYBOARD:
  19404. for (j = 0; j < RARCH_CUSTOM_BIND_LIST_END; j++)
  19405. {
  19406. unsigned current_button_value;
  19407. unsigned remap_key =
  19408. settings->uints.input_keymapper_ids[i][j];
  19409. if (remap_key == RETROK_UNKNOWN)
  19410. continue;
  19411. current_button_value =
  19412. BIT256_GET_PTR(p_new_state, j);
  19413. #ifdef HAVE_OVERLAY
  19414. if (poll_overlay && i == 0)
  19415. {
  19416. input_overlay_state_t *ol_state =
  19417. overlay_pointer
  19418. ? &overlay_pointer->overlay_state
  19419. : NULL;
  19420. if (ol_state)
  19421. current_button_value |=
  19422. BIT256_GET(ol_state->buttons, j);
  19423. }
  19424. #endif
  19425. /* Press */
  19426. if ((current_button_value == 1)
  19427. && !MAPPER_GET_KEY(handle, remap_key))
  19428. {
  19429. handle->key_button[remap_key] = (unsigned)j;
  19430. MAPPER_SET_KEY(handle, remap_key);
  19431. input_keyboard_event(true,
  19432. remap_key,
  19433. 0, 0, RETRO_DEVICE_KEYBOARD);
  19434. }
  19435. /* Release */
  19436. else if ((current_button_value == 0)
  19437. && MAPPER_GET_KEY(handle, remap_key))
  19438. {
  19439. if (handle->key_button[remap_key] != j)
  19440. continue;
  19441. input_keyboard_event(false,
  19442. remap_key,
  19443. 0, 0, RETRO_DEVICE_KEYBOARD);
  19444. MAPPER_UNSET_KEY(handle, remap_key);
  19445. }
  19446. }
  19447. break;
  19448. /* gamepad remapping */
  19449. case RETRO_DEVICE_JOYPAD:
  19450. case RETRO_DEVICE_ANALOG:
  19451. /* this loop iterates on all users and all buttons,
  19452. * and checks if a pressed button is assigned to any
  19453. * other button than the default one, then it sets
  19454. * the bit on the mapper input bitmap, later on the
  19455. * original input is cleared in input_state */
  19456. BIT256_CLEAR_ALL(handle->buttons[i]);
  19457. for (j = 0; j < 8; j++)
  19458. handle->analog_value[i][j] = 0;
  19459. for (j = 0; j < RARCH_FIRST_CUSTOM_BIND; j++)
  19460. {
  19461. bool remap_valid;
  19462. unsigned remap_button =
  19463. settings->uints.input_remap_ids[i][j];
  19464. unsigned current_button_value =
  19465. BIT256_GET_PTR(p_new_state, j);
  19466. #ifdef HAVE_OVERLAY
  19467. if (poll_overlay && i == 0)
  19468. {
  19469. input_overlay_state_t *ol_state =
  19470. overlay_pointer
  19471. ? &overlay_pointer->overlay_state
  19472. : NULL;
  19473. if (ol_state)
  19474. current_button_value |=
  19475. BIT256_GET(ol_state->buttons, j);
  19476. }
  19477. #endif
  19478. remap_valid =
  19479. (current_button_value == 1) &&
  19480. (j != remap_button) &&
  19481. (remap_button != RARCH_UNMAPPED);
  19482. #ifdef HAVE_ACCESSIBILITY
  19483. /* gamepad override */
  19484. if (i == 0 &&
  19485. p_rarch->gamepad_input_override & (1 << j))
  19486. {
  19487. BIT256_SET(handle->buttons[i], j);
  19488. }
  19489. #endif
  19490. if (remap_valid)
  19491. {
  19492. if (remap_button < RARCH_FIRST_CUSTOM_BIND)
  19493. {
  19494. BIT256_SET(handle->buttons[i], remap_button);
  19495. }
  19496. else
  19497. {
  19498. int invert = 1;
  19499. if (remap_button % 2 != 0)
  19500. invert = -1;
  19501. handle->analog_value[i][
  19502. remap_button - RARCH_FIRST_CUSTOM_BIND] =
  19503. (p_new_state->analog_buttons[j]
  19504. ? p_new_state->analog_buttons[j]
  19505. : 32767) * invert;
  19506. }
  19507. }
  19508. }
  19509. for (j = 0; j < 8; j++)
  19510. {
  19511. unsigned k = (unsigned)j + RARCH_FIRST_CUSTOM_BIND;
  19512. int16_t current_axis_value = p_new_state->analogs[j];
  19513. unsigned remap_axis =
  19514. settings->uints.input_remap_ids[i][k];
  19515. if (
  19516. (abs(current_axis_value) > 0 &&
  19517. (k != remap_axis) &&
  19518. (remap_axis != RARCH_UNMAPPED)
  19519. ))
  19520. {
  19521. if (remap_axis < RARCH_FIRST_CUSTOM_BIND &&
  19522. abs(current_axis_value) >
  19523. p_rarch->input_driver_axis_threshold
  19524. * 32767)
  19525. {
  19526. BIT256_SET(handle->buttons[i], remap_axis);
  19527. }
  19528. else
  19529. {
  19530. unsigned remap_axis_bind =
  19531. remap_axis - RARCH_FIRST_CUSTOM_BIND;
  19532. if (remap_axis_bind < sizeof(handle->analog_value[i]))
  19533. {
  19534. int invert = 1;
  19535. if ( (k % 2 == 0 && remap_axis % 2 != 0) ||
  19536. (k % 2 != 0 && remap_axis % 2 == 0)
  19537. )
  19538. invert = -1;
  19539. handle->analog_value[i][
  19540. remap_axis_bind] =
  19541. current_axis_value * invert;
  19542. }
  19543. }
  19544. }
  19545. }
  19546. break;
  19547. default:
  19548. break;
  19549. }
  19550. }
  19551. }
  19552. #ifdef HAVE_COMMAND
  19553. if (p_rarch->input_driver_command)
  19554. {
  19555. memset(p_rarch->input_driver_command->state,
  19556. 0, sizeof(p_rarch->input_driver_command->state));
  19557. #if defined(HAVE_NETWORK_CMD) && defined(HAVE_COMMAND)
  19558. command_network_poll(p_rarch,
  19559. p_rarch->input_driver_command);
  19560. #endif
  19561. #ifdef HAVE_STDIN_CMD
  19562. if (p_rarch->input_driver_command->stdin_enable)
  19563. command_stdin_poll(p_rarch,
  19564. p_rarch->input_driver_command);
  19565. #endif
  19566. }
  19567. #endif
  19568. #ifdef HAVE_NETWORKGAMEPAD
  19569. /* Poll remote */
  19570. if (p_rarch->input_driver_remote)
  19571. {
  19572. unsigned user;
  19573. for (user = 0; user < max_users; user++)
  19574. {
  19575. if (settings->bools.network_remote_enable_user[user])
  19576. {
  19577. #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD)
  19578. fd_set fds;
  19579. ssize_t ret;
  19580. struct remote_message msg;
  19581. if (p_rarch->input_driver_remote->net_fd[user] < 0)
  19582. return;
  19583. FD_ZERO(&fds);
  19584. FD_SET(p_rarch->input_driver_remote->net_fd[user], &fds);
  19585. ret = recvfrom(p_rarch->input_driver_remote->net_fd[user],
  19586. (char*)&msg,
  19587. sizeof(msg), 0, NULL, NULL);
  19588. if (ret == sizeof(msg))
  19589. input_remote_parse_packet(&p_rarch->remote_st_ptr, &msg, user);
  19590. else if ((ret != -1) || ((errno != EAGAIN) && (errno != ENOENT)))
  19591. #endif
  19592. {
  19593. input_remote_state_t *input_state = &p_rarch->remote_st_ptr;
  19594. input_state->buttons[user] = 0;
  19595. input_state->analog[0][user] = 0;
  19596. input_state->analog[1][user] = 0;
  19597. input_state->analog[2][user] = 0;
  19598. input_state->analog[3][user] = 0;
  19599. }
  19600. }
  19601. }
  19602. }
  19603. #endif
  19604. }
  19605. static int16_t input_state_device(
  19606. struct rarch_state *p_rarch,
  19607. int16_t ret,
  19608. unsigned port, unsigned device,
  19609. unsigned idx, unsigned id,
  19610. bool button_mask)
  19611. {
  19612. int16_t res = 0;
  19613. settings_t *settings = p_rarch->configuration_settings;
  19614. bool input_remap_binds_enable = settings->bools.input_remap_binds_enable;
  19615. switch (device)
  19616. {
  19617. case RETRO_DEVICE_JOYPAD:
  19618. if (id < RARCH_FIRST_META_KEY)
  19619. {
  19620. #ifdef HAVE_NETWORKGAMEPAD
  19621. /* Don't process binds if input is coming from Remote RetroPad */
  19622. if ( p_rarch->input_driver_remote
  19623. && INPUT_REMOTE_KEY_PRESSED(p_rarch, id, port))
  19624. res |= 1;
  19625. else
  19626. #endif
  19627. {
  19628. if (input_remap_binds_enable)
  19629. {
  19630. bool bind_valid = p_rarch->libretro_input_binds[port]
  19631. && p_rarch->libretro_input_binds[port][id].valid;
  19632. if (!
  19633. ( bind_valid
  19634. && id != settings->uints.input_remap_ids[port][id]
  19635. )
  19636. )
  19637. {
  19638. if (button_mask)
  19639. {
  19640. if (ret & (1 << id))
  19641. res |= (1 << id);
  19642. }
  19643. else
  19644. res = ret;
  19645. }
  19646. if (BIT256_GET(p_rarch->input_driver_mapper->buttons[port], id))
  19647. res = 1;
  19648. }
  19649. #ifdef HAVE_OVERLAY
  19650. if (port == 0)
  19651. {
  19652. if (p_rarch->overlay_ptr && p_rarch->overlay_ptr->alive)
  19653. if ((BIT256_GET(p_rarch->overlay_ptr->overlay_state.buttons, id)))
  19654. res |= 1;
  19655. }
  19656. #endif
  19657. }
  19658. }
  19659. /* Don't allow turbo for D-pad. */
  19660. if ( (id < RETRO_DEVICE_ID_JOYPAD_UP) ||
  19661. ( (id > RETRO_DEVICE_ID_JOYPAD_RIGHT) &&
  19662. (id <= RETRO_DEVICE_ID_JOYPAD_R3)))
  19663. {
  19664. /*
  19665. * Apply turbo button if activated.
  19666. */
  19667. unsigned turbo_mode = settings->uints.input_turbo_mode;
  19668. if (turbo_mode > INPUT_TURBO_MODE_CLASSIC)
  19669. {
  19670. /* Pressing turbo button toggles turbo mode on or off.
  19671. * Holding the button will
  19672. * pass through, else the pressed state will be modulated by a
  19673. * periodic pulse defined by the configured duty cycle.
  19674. */
  19675. /* Avoid detecting the turbo button being held as multiple toggles */
  19676. if (!p_rarch->input_driver_turbo_btns.frame_enable[port])
  19677. p_rarch->input_driver_turbo_btns.turbo_pressed[port] &= ~(1 << 31);
  19678. else if (p_rarch->input_driver_turbo_btns.turbo_pressed[port]>=0)
  19679. {
  19680. p_rarch->input_driver_turbo_btns.turbo_pressed[port] |= (1 << 31);
  19681. /* Toggle turbo for selected buttons. */
  19682. if (p_rarch->input_driver_turbo_btns.enable[port]
  19683. != (1 << settings->uints.input_turbo_default_button))
  19684. {
  19685. static const int button_map[]={
  19686. RETRO_DEVICE_ID_JOYPAD_B,
  19687. RETRO_DEVICE_ID_JOYPAD_Y,
  19688. RETRO_DEVICE_ID_JOYPAD_A,
  19689. RETRO_DEVICE_ID_JOYPAD_X,
  19690. RETRO_DEVICE_ID_JOYPAD_L,
  19691. RETRO_DEVICE_ID_JOYPAD_R,
  19692. RETRO_DEVICE_ID_JOYPAD_L2,
  19693. RETRO_DEVICE_ID_JOYPAD_R2,
  19694. RETRO_DEVICE_ID_JOYPAD_L3,
  19695. RETRO_DEVICE_ID_JOYPAD_R3};
  19696. p_rarch->input_driver_turbo_btns.enable[port] = 1 << button_map[
  19697. MIN(
  19698. sizeof(button_map)/sizeof(button_map[0])-1,
  19699. settings->uints.input_turbo_default_button)];
  19700. }
  19701. p_rarch->input_driver_turbo_btns.mode1_enable[port] ^= 1;
  19702. }
  19703. if (p_rarch->input_driver_turbo_btns.turbo_pressed[port] & (1 << 31))
  19704. {
  19705. /* Avoid detecting buttons being held as multiple toggles */
  19706. if (!res)
  19707. p_rarch->input_driver_turbo_btns.turbo_pressed[port] &= ~(1 << id);
  19708. else if (!(p_rarch->input_driver_turbo_btns.turbo_pressed[port] & (1 << id)) &&
  19709. turbo_mode == INPUT_TURBO_MODE_SINGLEBUTTON)
  19710. {
  19711. uint16_t enable_new;
  19712. p_rarch->input_driver_turbo_btns.turbo_pressed[port] |= 1 << id;
  19713. /* Toggle turbo for pressed button but make
  19714. * sure at least one button has turbo */
  19715. enable_new = p_rarch->input_driver_turbo_btns.enable[port] ^ (1 << id);
  19716. if (enable_new)
  19717. p_rarch->input_driver_turbo_btns.enable[port] = enable_new;
  19718. }
  19719. }
  19720. else if (turbo_mode == INPUT_TURBO_MODE_SINGLEBUTTON_HOLD &&
  19721. p_rarch->input_driver_turbo_btns.enable[port] &&
  19722. p_rarch->input_driver_turbo_btns.mode1_enable[port])
  19723. {
  19724. /* Hold mode stops turbo on release */
  19725. p_rarch->input_driver_turbo_btns.mode1_enable[port] = 0;
  19726. }
  19727. if (!res && p_rarch->input_driver_turbo_btns.mode1_enable[port] &&
  19728. p_rarch->input_driver_turbo_btns.enable[port] & (1 << id))
  19729. {
  19730. /* if turbo button is enabled for this key ID */
  19731. res = ((p_rarch->input_driver_turbo_btns.count
  19732. % settings->uints.input_turbo_period)
  19733. < settings->uints.input_turbo_duty_cycle);
  19734. }
  19735. }
  19736. else
  19737. {
  19738. /* If turbo button is held, all buttons pressed except
  19739. * for D-pad will go into a turbo mode. Until the button is
  19740. * released again, the input state will be modulated by a
  19741. * periodic pulse defined by the configured duty cycle.
  19742. */
  19743. if (res)
  19744. {
  19745. if (p_rarch->input_driver_turbo_btns.frame_enable[port])
  19746. p_rarch->input_driver_turbo_btns.enable[port] |= (1 << id);
  19747. if (p_rarch->input_driver_turbo_btns.enable[port] & (1 << id))
  19748. /* if turbo button is enabled for this key ID */
  19749. res = ((p_rarch->input_driver_turbo_btns.count
  19750. % settings->uints.input_turbo_period)
  19751. < settings->uints.input_turbo_duty_cycle);
  19752. }
  19753. else
  19754. p_rarch->input_driver_turbo_btns.enable[port] &= ~(1 << id);
  19755. }
  19756. }
  19757. break;
  19758. case RETRO_DEVICE_KEYBOARD:
  19759. res = ret;
  19760. if (id < RETROK_LAST)
  19761. {
  19762. #ifdef HAVE_OVERLAY
  19763. if (port == 0)
  19764. {
  19765. if (p_rarch->overlay_ptr && p_rarch->overlay_ptr->alive)
  19766. {
  19767. input_overlay_state_t
  19768. *ol_state = &p_rarch->overlay_ptr->overlay_state;
  19769. if (OVERLAY_GET_KEY(ol_state, id))
  19770. res |= 1;
  19771. }
  19772. }
  19773. #endif
  19774. if (input_remap_binds_enable)
  19775. if (MAPPER_GET_KEY(p_rarch->input_driver_mapper, id))
  19776. res |= 1;
  19777. }
  19778. break;
  19779. case RETRO_DEVICE_ANALOG:
  19780. {
  19781. #if defined(HAVE_NETWORKGAMEPAD) || defined(HAVE_OVERLAY)
  19782. #ifdef HAVE_NETWORKGAMEPAD
  19783. input_remote_state_t
  19784. *input_state = &p_rarch->remote_st_ptr;
  19785. #endif
  19786. unsigned base = (idx == RETRO_DEVICE_INDEX_ANALOG_RIGHT)
  19787. ? 2 : 0;
  19788. if (id == RETRO_DEVICE_ID_ANALOG_Y)
  19789. base += 1;
  19790. #ifdef HAVE_NETWORKGAMEPAD
  19791. if (p_rarch->input_driver_remote
  19792. && input_state && input_state->analog[base][port])
  19793. res = input_state->analog[base][port];
  19794. else
  19795. #endif
  19796. #endif
  19797. {
  19798. if (id < RARCH_FIRST_META_KEY)
  19799. {
  19800. bool bind_valid = p_rarch->libretro_input_binds[port]
  19801. && p_rarch->libretro_input_binds[port][id].valid;
  19802. if (bind_valid)
  19803. {
  19804. /* reset_state - used to reset input state of a button
  19805. * when the gamepad mapper is in action for that button*/
  19806. bool reset_state = false;
  19807. if (input_remap_binds_enable)
  19808. {
  19809. if (idx < 2 && id < 2)
  19810. {
  19811. unsigned offset = RARCH_FIRST_CUSTOM_BIND +
  19812. (idx * 4) + (id * 2);
  19813. if (settings->uints.input_remap_ids
  19814. [port][offset] != offset)
  19815. reset_state = true;
  19816. else if (settings->uints.input_remap_ids
  19817. [port][offset+1] != (offset+1))
  19818. reset_state = true;
  19819. }
  19820. }
  19821. if (reset_state)
  19822. res = 0;
  19823. else
  19824. {
  19825. res = ret;
  19826. #ifdef HAVE_OVERLAY
  19827. if ( p_rarch->overlay_ptr &&
  19828. p_rarch->overlay_ptr->alive && port == 0)
  19829. {
  19830. input_overlay_state_t *ol_state =
  19831. &p_rarch->overlay_ptr->overlay_state;
  19832. if (ol_state->analog[base])
  19833. res |= ol_state->analog[base];
  19834. }
  19835. #endif
  19836. }
  19837. }
  19838. }
  19839. }
  19840. if (input_remap_binds_enable)
  19841. {
  19842. if (idx < 2 && id < 2)
  19843. {
  19844. unsigned offset = 0 + (idx * 4) + (id * 2);
  19845. int val1 = p_rarch->input_driver_mapper->analog_value[port][offset];
  19846. int val2 = p_rarch->input_driver_mapper->analog_value[port][offset+1];
  19847. if (val1)
  19848. res |= val1;
  19849. else if (val2)
  19850. res |= val2;
  19851. }
  19852. }
  19853. }
  19854. break;
  19855. case RETRO_DEVICE_MOUSE:
  19856. case RETRO_DEVICE_LIGHTGUN:
  19857. case RETRO_DEVICE_POINTER:
  19858. if (id < RARCH_FIRST_META_KEY)
  19859. {
  19860. bool bind_valid = p_rarch->libretro_input_binds[port]
  19861. && p_rarch->libretro_input_binds[port][id].valid;
  19862. if (bind_valid)
  19863. {
  19864. if (button_mask)
  19865. {
  19866. if (ret & (1 << id))
  19867. res |= (1 << id);
  19868. }
  19869. else
  19870. res = ret;
  19871. }
  19872. }
  19873. break;
  19874. }
  19875. return res;
  19876. }
  19877. /**
  19878. * input_state:
  19879. * @port : user number.
  19880. * @device : device identifier of user.
  19881. * @idx : index value of user.
  19882. * @id : identifier of key pressed by user.
  19883. *
  19884. * Input state callback function.
  19885. *
  19886. * Returns: Non-zero if the given key (identified by @id)
  19887. * was pressed by the user (assigned to @port).
  19888. **/
  19889. static int16_t input_state(unsigned port, unsigned device,
  19890. unsigned idx, unsigned id)
  19891. {
  19892. rarch_joypad_info_t joypad_info;
  19893. struct rarch_state *p_rarch = &rarch_st;
  19894. settings_t *settings = p_rarch->configuration_settings;
  19895. int16_t result = 0;
  19896. int16_t ret = 0;
  19897. #ifdef HAVE_MFI
  19898. const input_device_driver_t
  19899. *sec_joypad = p_rarch->sec_joypad;
  19900. #else
  19901. const input_device_driver_t
  19902. *sec_joypad = NULL;
  19903. #endif
  19904. joypad_info.axis_threshold = p_rarch->input_driver_axis_threshold;
  19905. joypad_info.joy_idx = settings->uints.input_joypad_map[port];
  19906. joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx];
  19907. #ifdef HAVE_BSV_MOVIE
  19908. if (BSV_MOVIE_IS_PLAYBACK_ON())
  19909. {
  19910. int16_t bsv_result;
  19911. if (intfstream_read(p_rarch->bsv_movie_state_handle->file, &bsv_result, 2) == 2)
  19912. {
  19913. #ifdef HAVE_CHEEVOS
  19914. rcheevos_pause_hardcore();
  19915. #endif
  19916. return swap_if_big16(bsv_result);
  19917. }
  19918. p_rarch->bsv_movie_state.movie_end = true;
  19919. }
  19920. #endif
  19921. device &= RETRO_DEVICE_MASK;
  19922. ret = input_state_wrap(
  19923. p_rarch->current_input,
  19924. p_rarch->current_input_data,
  19925. p_rarch->joypad,
  19926. sec_joypad,
  19927. &joypad_info,
  19928. p_rarch->libretro_input_binds,
  19929. p_rarch->keyboard_mapping_blocked,
  19930. port, device, idx, id);
  19931. if ( (device == RETRO_DEVICE_ANALOG) &&
  19932. (ret == 0))
  19933. {
  19934. const input_device_driver_t *joypad = p_rarch->joypad;
  19935. #ifdef HAVE_MFI
  19936. const input_device_driver_t *sec_joypad = p_rarch->sec_joypad;
  19937. #else
  19938. const input_device_driver_t *sec_joypad = NULL;
  19939. #endif
  19940. if (p_rarch->libretro_input_binds[port])
  19941. {
  19942. if (idx == RETRO_DEVICE_INDEX_ANALOG_BUTTON)
  19943. {
  19944. if (id < RARCH_FIRST_CUSTOM_BIND)
  19945. {
  19946. bool valid_bind =
  19947. p_rarch->libretro_input_binds[port][id].valid;
  19948. if (valid_bind)
  19949. {
  19950. if (sec_joypad)
  19951. ret =
  19952. input_joypad_analog_button(
  19953. p_rarch, settings,
  19954. sec_joypad, &joypad_info,
  19955. port, idx, id, p_rarch->libretro_input_binds[port]);
  19956. if (joypad && (ret == 0))
  19957. ret = input_joypad_analog_button(
  19958. p_rarch, settings,
  19959. joypad, &joypad_info,
  19960. port, idx, id, p_rarch->libretro_input_binds[port]);
  19961. }
  19962. }
  19963. }
  19964. else
  19965. {
  19966. if (sec_joypad)
  19967. ret = input_joypad_analog_axis(p_rarch, settings,
  19968. sec_joypad, &joypad_info,
  19969. port, idx, id, p_rarch->libretro_input_binds[port]);
  19970. if (joypad && (ret == 0))
  19971. ret = input_joypad_analog_axis(p_rarch, settings,
  19972. joypad, &joypad_info,
  19973. port, idx, id, p_rarch->libretro_input_binds[port]);
  19974. }
  19975. }
  19976. }
  19977. if ( (p_rarch->input_driver_flushing_input == 0)
  19978. && !p_rarch->input_driver_block_libretro_input)
  19979. {
  19980. if ( (device == RETRO_DEVICE_JOYPAD) &&
  19981. (id == RETRO_DEVICE_ID_JOYPAD_MASK))
  19982. {
  19983. unsigned i;
  19984. {
  19985. for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
  19986. if (input_state_device(p_rarch, ret, port, device, idx, i, true))
  19987. result |= (1 << i);
  19988. }
  19989. }
  19990. else
  19991. result = input_state_device(p_rarch, ret, port, device, idx, id, false);
  19992. }
  19993. #ifdef HAVE_BSV_MOVIE
  19994. if (BSV_MOVIE_IS_PLAYBACK_OFF())
  19995. {
  19996. result = swap_if_big16(result);
  19997. intfstream_write(p_rarch->bsv_movie_state_handle->file, &result, 2);
  19998. }
  19999. #endif
  20000. return result;
  20001. }
  20002. static int16_t input_joypad_axis(
  20003. struct rarch_state *p_rarch,
  20004. const input_device_driver_t *drv,
  20005. unsigned port, uint32_t joyaxis, float normal_mag)
  20006. {
  20007. settings_t *settings = p_rarch->configuration_settings;
  20008. float input_analog_deadzone = settings->floats.input_analog_deadzone;
  20009. float input_analog_sensitivity = settings->floats.input_analog_sensitivity;
  20010. int16_t val = (joyaxis != AXIS_NONE) ? drv->axis(port, joyaxis) : 0;
  20011. if (input_analog_deadzone)
  20012. {
  20013. /* if analog value is below the deadzone, ignore it
  20014. * normal magnitude is calculated radially for analog sticks
  20015. * and linearly for analog buttons */
  20016. if (normal_mag <= input_analog_deadzone)
  20017. return 0;
  20018. /* due to the way normal_mag is calculated differently for buttons and
  20019. * sticks, this results in either a radial scaled deadzone for sticks
  20020. * or linear scaled deadzone for analog buttons */
  20021. val = val * MAX(1.0f,(1.0f / normal_mag)) * MIN(1.0f,((normal_mag - input_analog_deadzone)
  20022. / (1.0f - input_analog_deadzone)));
  20023. }
  20024. if (input_analog_sensitivity != 1.0f)
  20025. {
  20026. float normalized = (1.0f / 0x7fff) * val;
  20027. int new_val = 0x7fff * normalized *
  20028. input_analog_sensitivity;
  20029. if (new_val > 0x7fff)
  20030. return 0x7fff;
  20031. else if (new_val < -0x7fff)
  20032. return -0x7fff;
  20033. return new_val;
  20034. }
  20035. return val;
  20036. }
  20037. /* MENU INPUT */
  20038. #ifdef HAVE_MENU
  20039. /* Must be called inside menu_driver_toggle()
  20040. * Prevents phantom input when using an overlay to
  20041. * toggle menu ON if overlays are disabled in-menu */
  20042. static void menu_input_driver_toggle(
  20043. struct rarch_state *p_rarch,
  20044. menu_input_t *menu_input,
  20045. settings_t *settings,
  20046. bool on)
  20047. {
  20048. #ifdef HAVE_OVERLAY
  20049. if (on)
  20050. {
  20051. bool overlay_hide_in_menu = settings->bools.input_overlay_hide_in_menu;
  20052. bool input_overlay_enable = settings->bools.input_overlay_enable;
  20053. /* If an overlay was displayed before the toggle
  20054. * and overlays are disabled in menu, need to
  20055. * inhibit 'select' input */
  20056. if (overlay_hide_in_menu)
  20057. if ( input_overlay_enable &&
  20058. p_rarch->overlay_ptr &&
  20059. p_rarch->overlay_ptr->alive)
  20060. {
  20061. /* Inhibits pointer 'select' and 'cancel' actions
  20062. * (until the next time 'select'/'cancel' are released) */
  20063. menu_input->select_inhibit = true;
  20064. menu_input->cancel_inhibit = true;
  20065. }
  20066. }
  20067. else
  20068. #endif
  20069. {
  20070. /* Inhibits pointer 'select' and 'cancel' actions
  20071. * (until the next time 'select'/'cancel' are released) */
  20072. menu_input->select_inhibit = false;
  20073. menu_input->cancel_inhibit = false;
  20074. }
  20075. }
  20076. static int16_t menu_input_read_mouse_hw(
  20077. struct rarch_state *p_rarch,
  20078. enum menu_input_mouse_hw_id id)
  20079. {
  20080. rarch_joypad_info_t joypad_info;
  20081. unsigned type = 0;
  20082. unsigned device = RETRO_DEVICE_MOUSE;
  20083. input_driver_t *current_input = p_rarch->current_input;
  20084. #ifdef HAVE_MFI
  20085. const input_device_driver_t
  20086. *sec_joypad = p_rarch->sec_joypad;
  20087. #else
  20088. const input_device_driver_t
  20089. *sec_joypad = NULL;
  20090. #endif
  20091. joypad_info.joy_idx = 0;
  20092. joypad_info.auto_binds = NULL;
  20093. joypad_info.axis_threshold = 0.0f;
  20094. switch (id)
  20095. {
  20096. case MENU_MOUSE_X_AXIS:
  20097. device = RARCH_DEVICE_MOUSE_SCREEN;
  20098. type = RETRO_DEVICE_ID_MOUSE_X;
  20099. break;
  20100. case MENU_MOUSE_Y_AXIS:
  20101. device = RARCH_DEVICE_MOUSE_SCREEN;
  20102. type = RETRO_DEVICE_ID_MOUSE_Y;
  20103. break;
  20104. case MENU_MOUSE_LEFT_BUTTON:
  20105. type = RETRO_DEVICE_ID_MOUSE_LEFT;
  20106. break;
  20107. case MENU_MOUSE_RIGHT_BUTTON:
  20108. type = RETRO_DEVICE_ID_MOUSE_RIGHT;
  20109. break;
  20110. case MENU_MOUSE_WHEEL_UP:
  20111. type = RETRO_DEVICE_ID_MOUSE_WHEELUP;
  20112. break;
  20113. case MENU_MOUSE_WHEEL_DOWN:
  20114. type = RETRO_DEVICE_ID_MOUSE_WHEELDOWN;
  20115. break;
  20116. case MENU_MOUSE_HORIZ_WHEEL_UP:
  20117. type = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP;
  20118. break;
  20119. case MENU_MOUSE_HORIZ_WHEEL_DOWN:
  20120. type = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN;
  20121. break;
  20122. }
  20123. if (!current_input->input_state)
  20124. return 0;
  20125. return current_input->input_state(
  20126. p_rarch->current_input_data,
  20127. p_rarch->joypad,
  20128. sec_joypad,
  20129. &joypad_info,
  20130. NULL,
  20131. p_rarch->keyboard_mapping_blocked,
  20132. 0, device, 0, type);
  20133. }
  20134. static void menu_input_get_mouse_hw_state(
  20135. struct rarch_state *p_rarch,
  20136. menu_input_pointer_hw_state_t *hw_state)
  20137. {
  20138. settings_t *settings = p_rarch->configuration_settings;
  20139. static int16_t last_x = 0;
  20140. static int16_t last_y = 0;
  20141. static bool last_select_pressed = false;
  20142. static bool last_cancel_pressed = false;
  20143. bool mouse_enabled = settings->bools.menu_mouse_enable;
  20144. menu_handle_t *menu = p_rarch->menu_driver_data;
  20145. bool menu_has_fb =
  20146. (menu &&
  20147. menu->driver_ctx &&
  20148. menu->driver_ctx->set_texture);
  20149. #ifdef HAVE_OVERLAY
  20150. bool overlay_enable = settings->bools.input_overlay_enable;
  20151. /* Menu pointer controls are ignored when overlays are enabled. */
  20152. bool overlay_active = overlay_enable && p_rarch->overlay_ptr
  20153. && p_rarch->overlay_ptr->alive;
  20154. if (overlay_active)
  20155. mouse_enabled = false;
  20156. #endif
  20157. /* Easiest to set inactive by default, and toggle
  20158. * when input is detected */
  20159. hw_state->active = false;
  20160. if (!mouse_enabled)
  20161. {
  20162. hw_state->x = 0;
  20163. hw_state->y = 0;
  20164. hw_state->select_pressed = false;
  20165. hw_state->cancel_pressed = false;
  20166. hw_state->up_pressed = false;
  20167. hw_state->down_pressed = false;
  20168. hw_state->left_pressed = false;
  20169. hw_state->right_pressed = false;
  20170. return;
  20171. }
  20172. /* X pos */
  20173. hw_state->x = menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_X_AXIS);
  20174. if (hw_state->x != last_x)
  20175. hw_state->active = true;
  20176. last_x = hw_state->x;
  20177. /* Y pos */
  20178. hw_state->y = menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_Y_AXIS);
  20179. if (hw_state->y != last_y)
  20180. hw_state->active = true;
  20181. last_y = hw_state->y;
  20182. /* > X/Y adjustment */
  20183. if (menu_has_fb)
  20184. {
  20185. /* RGUI uses a framebuffer texture + custom viewports,
  20186. * which means we have to convert from screen space to
  20187. * menu space... */
  20188. size_t fb_pitch;
  20189. unsigned fb_width, fb_height;
  20190. struct video_viewport vp = {0};
  20191. /* Read display/framebuffer info */
  20192. gfx_display_get_fb_size(&fb_width, &fb_height, &fb_pitch);
  20193. video_driver_get_viewport_info(&vp);
  20194. /* Adjust X pos */
  20195. hw_state->x = (int16_t)(((float)(hw_state->x - vp.x) / (float)vp.width) * (float)fb_width);
  20196. hw_state->x = hw_state->x < 0 ? 0 : hw_state->x;
  20197. hw_state->x = hw_state->x >= fb_width ? fb_width - 1 : hw_state->x;
  20198. /* Adjust Y pos */
  20199. hw_state->y = (int16_t)(((float)(hw_state->y - vp.y) / (float)vp.height) * (float)fb_height);
  20200. hw_state->y = hw_state->y < 0 ? 0 : hw_state->y;
  20201. hw_state->y = hw_state->y >= fb_height ? fb_height - 1 : hw_state->y;
  20202. }
  20203. /* Select (LMB)
  20204. * Note that releasing select also counts as activity */
  20205. hw_state->select_pressed = (bool)
  20206. menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_LEFT_BUTTON);
  20207. if (hw_state->select_pressed || (hw_state->select_pressed != last_select_pressed))
  20208. hw_state->active = true;
  20209. last_select_pressed = hw_state->select_pressed;
  20210. /* Cancel (RMB)
  20211. * Note that releasing cancel also counts as activity */
  20212. hw_state->cancel_pressed = (bool)
  20213. menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_RIGHT_BUTTON);
  20214. if (hw_state->cancel_pressed || (hw_state->cancel_pressed != last_cancel_pressed))
  20215. hw_state->active = true;
  20216. last_cancel_pressed = hw_state->cancel_pressed;
  20217. /* Up (mouse wheel up) */
  20218. hw_state->up_pressed = (bool)
  20219. menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_WHEEL_UP);
  20220. if (hw_state->up_pressed)
  20221. hw_state->active = true;
  20222. /* Down (mouse wheel down) */
  20223. hw_state->down_pressed = (bool)
  20224. menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_WHEEL_DOWN);
  20225. if (hw_state->down_pressed)
  20226. hw_state->active = true;
  20227. /* Left (mouse wheel horizontal left) */
  20228. hw_state->left_pressed = (bool)
  20229. menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_HORIZ_WHEEL_DOWN);
  20230. if (hw_state->left_pressed)
  20231. hw_state->active = true;
  20232. /* Right (mouse wheel horizontal right) */
  20233. hw_state->right_pressed = (bool)
  20234. menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_HORIZ_WHEEL_UP);
  20235. if (hw_state->right_pressed)
  20236. hw_state->active = true;
  20237. }
  20238. static void menu_input_get_touchscreen_hw_state(
  20239. struct rarch_state *p_rarch,
  20240. menu_input_pointer_hw_state_t *hw_state)
  20241. {
  20242. rarch_joypad_info_t joypad_info;
  20243. size_t fb_pitch;
  20244. unsigned fb_width, fb_height;
  20245. int pointer_x = 0;
  20246. int pointer_y = 0;
  20247. settings_t *settings =
  20248. p_rarch->configuration_settings;
  20249. const struct retro_keybind *binds[MAX_USERS] = {NULL};
  20250. input_driver_t *current_input = p_rarch->current_input;
  20251. menu_handle_t *menu = p_rarch->menu_driver_data;
  20252. /* Is a background texture set for the current menu driver?
  20253. * Checks if the menu framebuffer is set.
  20254. * This would usually only return true
  20255. * for framebuffer-based menu drivers, like RGUI. */
  20256. int pointer_device =
  20257. (menu && menu->driver_ctx && menu->driver_ctx->set_texture) ?
  20258. RETRO_DEVICE_POINTER : RARCH_DEVICE_POINTER_SCREEN;
  20259. static int16_t last_x = 0;
  20260. static int16_t last_y = 0;
  20261. static bool last_select_pressed = false;
  20262. static bool last_cancel_pressed = false;
  20263. bool overlay_active = false;
  20264. bool pointer_enabled = settings->bools.menu_pointer_enable;
  20265. #ifdef HAVE_MFI
  20266. const input_device_driver_t
  20267. *sec_joypad = p_rarch->sec_joypad;
  20268. #else
  20269. const input_device_driver_t
  20270. *sec_joypad = NULL;
  20271. #endif
  20272. /* Easiest to set inactive by default, and toggle
  20273. * when input is detected */
  20274. hw_state->active = false;
  20275. /* Touch screens don't have mouse wheels, so these
  20276. * are always disabled */
  20277. hw_state->up_pressed = false;
  20278. hw_state->down_pressed = false;
  20279. hw_state->left_pressed = false;
  20280. hw_state->right_pressed = false;
  20281. #ifdef HAVE_OVERLAY
  20282. /* Menu pointer controls are ignored when overlays are enabled. */
  20283. overlay_active = settings->bools.input_overlay_enable
  20284. && p_rarch->overlay_ptr && p_rarch->overlay_ptr->alive;
  20285. if (overlay_active)
  20286. pointer_enabled = false;
  20287. #endif
  20288. /* If touchscreen is disabled, ignore all input */
  20289. if (!pointer_enabled)
  20290. {
  20291. hw_state->x = 0;
  20292. hw_state->y = 0;
  20293. hw_state->select_pressed = false;
  20294. hw_state->cancel_pressed = false;
  20295. return;
  20296. }
  20297. /* TODO/FIXME - this should only be used for framebuffer-based
  20298. * menu drivers like RGUI. Touchscreen input as a whole should
  20299. * NOT be dependent on this
  20300. */
  20301. gfx_display_get_fb_size(&fb_width, &fb_height, &fb_pitch);
  20302. joypad_info.joy_idx = 0;
  20303. joypad_info.auto_binds = NULL;
  20304. joypad_info.axis_threshold = 0.0f;
  20305. /* X pos */
  20306. if (current_input->input_state)
  20307. pointer_x = current_input->input_state(
  20308. p_rarch->current_input_data,
  20309. p_rarch->joypad,
  20310. sec_joypad,
  20311. &joypad_info, binds,
  20312. p_rarch->keyboard_mapping_blocked,
  20313. 0, pointer_device,
  20314. 0, RETRO_DEVICE_ID_POINTER_X);
  20315. hw_state->x = ((pointer_x + 0x7fff) * (int)fb_width) / 0xFFFF;
  20316. /* > An annoyance - we get different starting positions
  20317. * depending upon whether pointer_device is
  20318. * RETRO_DEVICE_POINTER or RARCH_DEVICE_POINTER_SCREEN,
  20319. * so different 'activity' checks are required to prevent
  20320. * false positives on first run */
  20321. if (pointer_device == RARCH_DEVICE_POINTER_SCREEN)
  20322. {
  20323. if (hw_state->x != last_x)
  20324. hw_state->active = true;
  20325. last_x = hw_state->x;
  20326. }
  20327. else
  20328. {
  20329. if (pointer_x != last_x)
  20330. hw_state->active = true;
  20331. last_x = pointer_x;
  20332. }
  20333. /* Y pos */
  20334. if (current_input->input_state)
  20335. pointer_y = current_input->input_state(
  20336. p_rarch->current_input_data,
  20337. p_rarch->joypad,
  20338. sec_joypad,
  20339. &joypad_info, binds,
  20340. p_rarch->keyboard_mapping_blocked,
  20341. 0, pointer_device,
  20342. 0, RETRO_DEVICE_ID_POINTER_Y);
  20343. hw_state->y = ((pointer_y + 0x7fff) * (int)fb_height) / 0xFFFF;
  20344. if (pointer_device == RARCH_DEVICE_POINTER_SCREEN)
  20345. {
  20346. if (hw_state->y != last_y)
  20347. hw_state->active = true;
  20348. last_y = hw_state->y;
  20349. }
  20350. else
  20351. {
  20352. if (pointer_y != last_y)
  20353. hw_state->active = true;
  20354. last_y = pointer_y;
  20355. }
  20356. /* Select (touch screen contact)
  20357. * Note that releasing select also counts as activity */
  20358. if (current_input->input_state)
  20359. hw_state->select_pressed = (bool)current_input->input_state(
  20360. p_rarch->current_input_data,
  20361. p_rarch->joypad,
  20362. sec_joypad,
  20363. &joypad_info, binds,
  20364. p_rarch->keyboard_mapping_blocked,
  20365. 0, pointer_device,
  20366. 0, RETRO_DEVICE_ID_POINTER_PRESSED);
  20367. if (hw_state->select_pressed || (hw_state->select_pressed != last_select_pressed))
  20368. hw_state->active = true;
  20369. last_select_pressed = hw_state->select_pressed;
  20370. /* Cancel (touch screen 'back' - don't know what is this, but whatever...)
  20371. * Note that releasing cancel also counts as activity */
  20372. if (current_input->input_state)
  20373. hw_state->cancel_pressed = (bool)current_input->input_state(
  20374. p_rarch->current_input_data,
  20375. p_rarch->joypad,
  20376. sec_joypad,
  20377. &joypad_info, binds,
  20378. p_rarch->keyboard_mapping_blocked,
  20379. 0, pointer_device,
  20380. 0, RARCH_DEVICE_ID_POINTER_BACK);
  20381. if (hw_state->cancel_pressed || (hw_state->cancel_pressed != last_cancel_pressed))
  20382. hw_state->active = true;
  20383. last_cancel_pressed = hw_state->cancel_pressed;
  20384. }
  20385. static INLINE bool input_event_osk_show_symbol_pages(
  20386. struct rarch_state *p_rarch)
  20387. {
  20388. #if defined(HAVE_LANGEXTRA)
  20389. #if defined(HAVE_RGUI)
  20390. menu_handle_t *menu = p_rarch->menu_driver_data;
  20391. bool menu_has_fb = (menu &&
  20392. menu->driver_ctx &&
  20393. menu->driver_ctx->set_texture);
  20394. unsigned language = *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE);
  20395. return !menu_has_fb ||
  20396. ((language == RETRO_LANGUAGE_JAPANESE) ||
  20397. (language == RETRO_LANGUAGE_KOREAN) ||
  20398. (language == RETRO_LANGUAGE_CHINESE_SIMPLIFIED) ||
  20399. (language == RETRO_LANGUAGE_CHINESE_TRADITIONAL));
  20400. #else /* HAVE_RGUI */
  20401. return true;
  20402. #endif /* HAVE_RGUI */
  20403. #else /* HAVE_LANGEXTRA */
  20404. return false;
  20405. #endif /* HAVE_LANGEXTRA */
  20406. }
  20407. static void input_event_osk_append(
  20408. struct rarch_state *p_rarch,
  20409. enum osk_type *osk_idx, int ptr,
  20410. bool show_symbol_pages,
  20411. const char *word)
  20412. {
  20413. #ifdef HAVE_LANGEXTRA
  20414. if (string_is_equal(word, "\xe2\x87\xa6")) /* backspace character */
  20415. input_keyboard_event(true, '\x7f', '\x7f', 0, RETRO_DEVICE_KEYBOARD);
  20416. else if (string_is_equal(word, "\xe2\x8f\x8e")) /* return character */
  20417. input_keyboard_event(true, '\n', '\n', 0, RETRO_DEVICE_KEYBOARD);
  20418. else
  20419. if (string_is_equal(word, "\xe2\x87\xa7")) /* up arrow */
  20420. *osk_idx = OSK_UPPERCASE_LATIN;
  20421. else if (string_is_equal(word, "\xe2\x87\xa9")) /* down arrow */
  20422. *osk_idx = OSK_LOWERCASE_LATIN;
  20423. else if (string_is_equal(word,"\xe2\x8a\x95")) /* plus sign (next button) */
  20424. #else
  20425. if (string_is_equal(word, "Bksp"))
  20426. input_keyboard_event(true, '\x7f', '\x7f', 0, RETRO_DEVICE_KEYBOARD);
  20427. else if (string_is_equal(word, "Enter"))
  20428. input_keyboard_event(true, '\n', '\n', 0, RETRO_DEVICE_KEYBOARD);
  20429. else
  20430. if (string_is_equal(word, "Upper"))
  20431. *osk_idx = OSK_UPPERCASE_LATIN;
  20432. else if (string_is_equal(word, "Lower"))
  20433. *osk_idx = OSK_LOWERCASE_LATIN;
  20434. else if (string_is_equal(word, "Next"))
  20435. #endif
  20436. if (*osk_idx < (show_symbol_pages ? OSK_TYPE_LAST - 1 : OSK_SYMBOLS_PAGE1))
  20437. *osk_idx = (enum osk_type)(*osk_idx + 1);
  20438. else
  20439. *osk_idx = ((enum osk_type)(OSK_TYPE_UNKNOWN + 1));
  20440. else
  20441. {
  20442. input_keyboard_line_append(&p_rarch->keyboard_line, word);
  20443. if (word[0] == 0)
  20444. {
  20445. p_rarch->osk_last_codepoint = 0;
  20446. p_rarch->osk_last_codepoint_len = 0;
  20447. }
  20448. else
  20449. osk_update_last_codepoint(
  20450. &p_rarch->osk_last_codepoint,
  20451. &p_rarch->osk_last_codepoint_len,
  20452. word);
  20453. }
  20454. }
  20455. static void input_event_osk_iterate(
  20456. struct rarch_state *p_rarch,
  20457. enum osk_type osk_idx)
  20458. {
  20459. switch (osk_idx)
  20460. {
  20461. #ifdef HAVE_LANGEXTRA
  20462. case OSK_HIRAGANA_PAGE1:
  20463. memcpy(p_rarch->osk_grid,
  20464. hiragana_page1_grid,
  20465. sizeof(hiragana_page1_grid));
  20466. break;
  20467. case OSK_HIRAGANA_PAGE2:
  20468. memcpy(p_rarch->osk_grid,
  20469. hiragana_page2_grid,
  20470. sizeof(hiragana_page2_grid));
  20471. break;
  20472. case OSK_KATAKANA_PAGE1:
  20473. memcpy(p_rarch->osk_grid,
  20474. katakana_page1_grid,
  20475. sizeof(katakana_page1_grid));
  20476. break;
  20477. case OSK_KATAKANA_PAGE2:
  20478. memcpy(p_rarch->osk_grid,
  20479. katakana_page2_grid,
  20480. sizeof(katakana_page2_grid));
  20481. break;
  20482. #endif
  20483. case OSK_SYMBOLS_PAGE1:
  20484. memcpy(p_rarch->osk_grid,
  20485. symbols_page1_grid,
  20486. sizeof(uppercase_grid));
  20487. break;
  20488. case OSK_UPPERCASE_LATIN:
  20489. memcpy(p_rarch->osk_grid,
  20490. uppercase_grid,
  20491. sizeof(uppercase_grid));
  20492. break;
  20493. case OSK_LOWERCASE_LATIN:
  20494. default:
  20495. memcpy(p_rarch->osk_grid,
  20496. lowercase_grid,
  20497. sizeof(lowercase_grid));
  20498. break;
  20499. }
  20500. }
  20501. /*
  20502. * This function gets called in order to process all input events
  20503. * for the current frame.
  20504. *
  20505. * Sends input code to menu for one frame.
  20506. *
  20507. * It uses as input the local variables 'input' and 'trigger_input'.
  20508. *
  20509. * Mouse and touch input events get processed inside this function.
  20510. *
  20511. * NOTE: 'input' and 'trigger_input' is sourced from the keyboard and/or
  20512. * the gamepad. It does not contain input state derived from the mouse
  20513. * and/or touch - this gets dealt with separately within this function.
  20514. *
  20515. * TODO/FIXME - maybe needs to be overhauled so we can send multiple
  20516. * events per frame if we want to, and we shouldn't send the
  20517. * entire button state either but do a separate event per button
  20518. * state.
  20519. */
  20520. static unsigned menu_event(
  20521. struct rarch_state *p_rarch,
  20522. input_bits_t *p_input,
  20523. input_bits_t *p_trigger_input,
  20524. bool display_kb)
  20525. {
  20526. /* Used for key repeat */
  20527. static float delay_timer = 0.0f;
  20528. static float delay_count = 0.0f;
  20529. static bool initial_held = true;
  20530. static bool first_held = false;
  20531. static unsigned ok_old = 0;
  20532. unsigned ret = MENU_ACTION_NOOP;
  20533. bool set_scroll = false;
  20534. size_t new_scroll_accel = 0;
  20535. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  20536. menu_input_t *menu_input = &p_rarch->menu_input_state;
  20537. menu_input_pointer_hw_state_t *pointer_hw_state = &p_rarch->menu_input_pointer_hw_state;
  20538. settings_t *settings = p_rarch->configuration_settings;
  20539. bool menu_mouse_enable = settings->bools.menu_mouse_enable;
  20540. bool menu_pointer_enable = settings->bools.menu_pointer_enable;
  20541. bool swap_ok_cancel_btns = settings->bools.input_menu_swap_ok_cancel_buttons;
  20542. bool menu_scroll_fast = settings->bools.menu_scroll_fast;
  20543. unsigned menu_ok_btn = swap_ok_cancel_btns ?
  20544. RETRO_DEVICE_ID_JOYPAD_B : RETRO_DEVICE_ID_JOYPAD_A;
  20545. unsigned menu_cancel_btn = swap_ok_cancel_btns ?
  20546. RETRO_DEVICE_ID_JOYPAD_A : RETRO_DEVICE_ID_JOYPAD_B;
  20547. unsigned ok_current = BIT256_GET_PTR(p_input, menu_ok_btn);
  20548. unsigned ok_trigger = ok_current & ~ok_old;
  20549. unsigned i = 0;
  20550. unsigned navigation_current = 0;
  20551. unsigned navigation_buttons[6] =
  20552. {
  20553. RETRO_DEVICE_ID_JOYPAD_UP,
  20554. RETRO_DEVICE_ID_JOYPAD_DOWN,
  20555. RETRO_DEVICE_ID_JOYPAD_LEFT,
  20556. RETRO_DEVICE_ID_JOYPAD_RIGHT,
  20557. RETRO_DEVICE_ID_JOYPAD_L,
  20558. RETRO_DEVICE_ID_JOYPAD_R
  20559. };
  20560. ok_old = ok_current;
  20561. /* Accelerate only navigation buttons */
  20562. for (i = 0; i < 6; i++)
  20563. navigation_current |= BIT256_GET_PTR(p_input, navigation_buttons[i]);
  20564. if (navigation_current)
  20565. {
  20566. if (!first_held)
  20567. {
  20568. /* don't run anything first frame, only capture held inputs
  20569. * for old_input_state. */
  20570. first_held = true;
  20571. if (menu_scroll_fast)
  20572. delay_timer = initial_held ? 256 : 100;
  20573. else
  20574. delay_timer = initial_held ? 256 : 20;
  20575. delay_count = 0;
  20576. }
  20577. if (delay_count >= delay_timer)
  20578. {
  20579. uint32_t input_repeat = 0;
  20580. for (i = 0; i < 6; i++)
  20581. BIT32_SET(input_repeat, navigation_buttons[i]);
  20582. set_scroll = true;
  20583. first_held = false;
  20584. p_trigger_input->data[0] |= p_input->data[0] & input_repeat;
  20585. new_scroll_accel = menu_st->scroll.acceleration;
  20586. if (menu_scroll_fast)
  20587. new_scroll_accel = MIN(new_scroll_accel + 1, 64);
  20588. else
  20589. new_scroll_accel = MIN(new_scroll_accel + 1, 5);
  20590. }
  20591. initial_held = false;
  20592. }
  20593. else
  20594. {
  20595. set_scroll = true;
  20596. first_held = false;
  20597. initial_held = true;
  20598. }
  20599. if (set_scroll)
  20600. menu_st->scroll.acceleration = (unsigned)(new_scroll_accel);
  20601. delay_count += p_rarch->anim.delta_time;
  20602. if (display_kb)
  20603. {
  20604. bool show_osk_symbols = input_event_osk_show_symbol_pages(p_rarch);
  20605. input_event_osk_iterate(p_rarch, p_rarch->osk_idx);
  20606. if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_DOWN))
  20607. {
  20608. if (p_rarch->osk_ptr < 33)
  20609. p_rarch->osk_ptr += OSK_CHARS_PER_LINE;
  20610. }
  20611. if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_UP))
  20612. {
  20613. if (p_rarch->osk_ptr >= OSK_CHARS_PER_LINE)
  20614. p_rarch->osk_ptr -= OSK_CHARS_PER_LINE;
  20615. }
  20616. if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_RIGHT))
  20617. {
  20618. if (p_rarch->osk_ptr < 43)
  20619. p_rarch->osk_ptr += 1;
  20620. }
  20621. if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_LEFT))
  20622. {
  20623. if (p_rarch->osk_ptr >= 1)
  20624. p_rarch->osk_ptr -= 1;
  20625. }
  20626. if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_L))
  20627. {
  20628. if (p_rarch->osk_idx > OSK_TYPE_UNKNOWN + 1)
  20629. p_rarch->osk_idx = ((enum osk_type)
  20630. (p_rarch->osk_idx - 1));
  20631. else
  20632. p_rarch->osk_idx = ((enum osk_type)(show_osk_symbols
  20633. ? OSK_TYPE_LAST - 1
  20634. : OSK_SYMBOLS_PAGE1));
  20635. }
  20636. if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_R))
  20637. {
  20638. if (p_rarch->osk_idx < (show_osk_symbols
  20639. ? OSK_TYPE_LAST - 1
  20640. : OSK_SYMBOLS_PAGE1))
  20641. p_rarch->osk_idx = ((enum osk_type)(
  20642. p_rarch->osk_idx + 1));
  20643. else
  20644. p_rarch->osk_idx = ((enum osk_type)(OSK_TYPE_UNKNOWN + 1));
  20645. }
  20646. if (BIT256_GET_PTR(p_trigger_input, menu_ok_btn))
  20647. {
  20648. if (p_rarch->osk_ptr >= 0)
  20649. input_event_osk_append(
  20650. p_rarch,
  20651. &p_rarch->osk_idx,
  20652. p_rarch->osk_ptr,
  20653. show_osk_symbols,
  20654. p_rarch->osk_grid[p_rarch->osk_ptr]);
  20655. }
  20656. if (BIT256_GET_PTR(p_trigger_input, menu_cancel_btn))
  20657. input_keyboard_event(true, '\x7f', '\x7f',
  20658. 0, RETRO_DEVICE_KEYBOARD);
  20659. /* send return key to close keyboard input window */
  20660. if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_START))
  20661. input_keyboard_event(true, '\n', '\n', 0, RETRO_DEVICE_KEYBOARD);
  20662. BIT256_CLEAR_ALL_PTR(p_trigger_input);
  20663. }
  20664. else
  20665. {
  20666. if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_UP))
  20667. ret = MENU_ACTION_UP;
  20668. else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_DOWN))
  20669. ret = MENU_ACTION_DOWN;
  20670. else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_LEFT))
  20671. ret = MENU_ACTION_LEFT;
  20672. else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_RIGHT))
  20673. ret = MENU_ACTION_RIGHT;
  20674. else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_L))
  20675. ret = MENU_ACTION_SCROLL_UP;
  20676. else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_R))
  20677. ret = MENU_ACTION_SCROLL_DOWN;
  20678. else if (ok_trigger)
  20679. ret = MENU_ACTION_OK;
  20680. else if (BIT256_GET_PTR(p_trigger_input, menu_cancel_btn))
  20681. ret = MENU_ACTION_CANCEL;
  20682. else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_X))
  20683. ret = MENU_ACTION_SEARCH;
  20684. else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_Y))
  20685. ret = MENU_ACTION_SCAN;
  20686. else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_START))
  20687. ret = MENU_ACTION_START;
  20688. else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_SELECT))
  20689. ret = MENU_ACTION_INFO;
  20690. else if (BIT256_GET_PTR(p_trigger_input, RARCH_MENU_TOGGLE))
  20691. ret = MENU_ACTION_TOGGLE;
  20692. }
  20693. /* Get pointer (mouse + touchscreen) input */
  20694. /* > If pointer input is disabled, do nothing */
  20695. if (!menu_mouse_enable && !menu_pointer_enable)
  20696. menu_input->pointer.type = MENU_POINTER_DISABLED;
  20697. else
  20698. {
  20699. menu_input_pointer_hw_state_t mouse_hw_state = {0};
  20700. menu_input_pointer_hw_state_t touchscreen_hw_state = {0};
  20701. /* Read mouse */
  20702. if (menu_mouse_enable)
  20703. menu_input_get_mouse_hw_state(p_rarch, &mouse_hw_state);
  20704. /* Read touchscreen
  20705. * Note: Could forgo this if mouse is currently active,
  20706. * but this is 'cleaner' code... (if performance is a
  20707. * concern - and it isn't - user can just disable touch
  20708. * screen support) */
  20709. if (menu_pointer_enable)
  20710. menu_input_get_touchscreen_hw_state(
  20711. p_rarch, &touchscreen_hw_state);
  20712. /* Mouse takes precedence */
  20713. if (mouse_hw_state.active)
  20714. menu_input->pointer.type = MENU_POINTER_MOUSE;
  20715. else if (touchscreen_hw_state.active)
  20716. menu_input->pointer.type = MENU_POINTER_TOUCHSCREEN;
  20717. /* Copy input from the current device */
  20718. if (menu_input->pointer.type == MENU_POINTER_MOUSE)
  20719. memcpy(pointer_hw_state, &mouse_hw_state, sizeof(menu_input_pointer_hw_state_t));
  20720. else if (menu_input->pointer.type == MENU_POINTER_TOUCHSCREEN)
  20721. memcpy(pointer_hw_state, &touchscreen_hw_state, sizeof(menu_input_pointer_hw_state_t));
  20722. }
  20723. /* Populate menu_input_state
  20724. * Note: dx, dy, ptr, y_accel, etc. entries are set elsewhere */
  20725. if (menu_input->select_inhibit || menu_input->cancel_inhibit)
  20726. {
  20727. menu_input->pointer.active = false;
  20728. menu_input->pointer.pressed = false;
  20729. menu_input->pointer.x = 0;
  20730. menu_input->pointer.y = 0;
  20731. }
  20732. else
  20733. {
  20734. menu_input->pointer.active = pointer_hw_state->active;
  20735. menu_input->pointer.pressed = pointer_hw_state->select_pressed;
  20736. menu_input->pointer.x = pointer_hw_state->x;
  20737. menu_input->pointer.y = pointer_hw_state->y;
  20738. }
  20739. return ret;
  20740. }
  20741. void menu_input_get_pointer_state(menu_input_pointer_t *pointer)
  20742. {
  20743. struct rarch_state *p_rarch = &rarch_st;
  20744. menu_input_t *menu_input = &p_rarch->menu_input_state;
  20745. if (!pointer)
  20746. return;
  20747. /* Copy parameters from global menu_input_state
  20748. * (i.e. don't pass by reference)
  20749. * This is a fast operation */
  20750. memcpy(pointer, &menu_input->pointer, sizeof(menu_input_pointer_t));
  20751. }
  20752. unsigned menu_input_get_pointer_selection(void)
  20753. {
  20754. struct rarch_state *p_rarch = &rarch_st;
  20755. menu_input_t *menu_input = &p_rarch->menu_input_state;
  20756. return menu_input->ptr;
  20757. }
  20758. void menu_input_set_pointer_selection(unsigned selection)
  20759. {
  20760. struct rarch_state *p_rarch = &rarch_st;
  20761. menu_input_t *menu_input = &p_rarch->menu_input_state;
  20762. menu_input->ptr = selection;
  20763. }
  20764. void menu_input_set_pointer_y_accel(float y_accel)
  20765. {
  20766. struct rarch_state *p_rarch = &rarch_st;
  20767. menu_input_t *menu_input = &p_rarch->menu_input_state;
  20768. menu_input->pointer.y_accel = y_accel;
  20769. }
  20770. static void menu_input_reset(
  20771. menu_input_t *menu_input,
  20772. menu_input_pointer_hw_state_t *pointer_hw_state
  20773. )
  20774. {
  20775. memset(menu_input, 0, sizeof(menu_input_t));
  20776. memset(pointer_hw_state, 0, sizeof(menu_input_pointer_hw_state_t));
  20777. }
  20778. static float menu_input_get_dpi(struct rarch_state *p_rarch)
  20779. {
  20780. static unsigned last_video_width = 0;
  20781. static unsigned last_video_height = 0;
  20782. static float dpi = 0.0f;
  20783. static bool dpi_cached = false;
  20784. menu_handle_t *menu = p_rarch->menu_driver_data;
  20785. /* Regardless of menu driver, need 'actual' screen DPI
  20786. * Note: DPI is a fixed hardware property. To minimise performance
  20787. * overheads we therefore only call video_context_driver_get_metrics()
  20788. * on first run, or when the current video resolution changes */
  20789. if (!dpi_cached ||
  20790. (p_rarch->video_driver_width != last_video_width) ||
  20791. (p_rarch->video_driver_height != last_video_height))
  20792. {
  20793. gfx_ctx_metrics_t mets;
  20794. /* Note: If video_context_driver_get_metrics() fails,
  20795. * we don't know what happened to dpi - so ensure it
  20796. * is reset to a sane value */
  20797. mets.type = DISPLAY_METRIC_DPI;
  20798. mets.value = &dpi;
  20799. if (!video_context_driver_get_metrics(&mets))
  20800. dpi = 0.0f;
  20801. dpi_cached = true;
  20802. last_video_width = p_rarch->video_driver_width;
  20803. last_video_height = p_rarch->video_driver_height;
  20804. }
  20805. /* RGUI uses a framebuffer texture, which means we
  20806. * operate in menu space, not screen space.
  20807. * DPI in a traditional sense is therefore meaningless,
  20808. * so generate a substitute value based upon framebuffer
  20809. * dimensions */
  20810. if (dpi > 0.0f)
  20811. {
  20812. bool menu_has_fb =
  20813. menu->driver_ctx
  20814. && menu->driver_ctx->set_texture;
  20815. if (menu_has_fb)
  20816. {
  20817. size_t fb_pitch;
  20818. unsigned fb_width, fb_height;
  20819. /* Read framebuffer info */
  20820. gfx_display_get_fb_size(&fb_width, &fb_height, &fb_pitch);
  20821. /* Rationale for current 'DPI' determination method:
  20822. * - Divide screen height by DPI, to get number of vertical
  20823. * '1 inch' squares
  20824. * - Divide RGUI framebuffer height by number of vertical
  20825. * '1 inch' squares to get number of menu space pixels
  20826. * per inch
  20827. * This is crude, but should be sufficient... */
  20828. return ((float)fb_height / (float)p_rarch->video_driver_height) * dpi;
  20829. }
  20830. }
  20831. return dpi;
  20832. }
  20833. static bool menu_should_pop_stack(const char *label)
  20834. {
  20835. /* > Info box */
  20836. if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_INFO_SCREEN)))
  20837. return true;
  20838. /* > Help box */
  20839. if (string_starts_with_size(label, "help", STRLEN_CONST("help")))
  20840. if (
  20841. string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP))
  20842. || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_CONTROLS))
  20843. || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_WHAT_IS_A_CORE))
  20844. || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_LOADING_CONTENT))
  20845. || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_SCANNING_CONTENT))
  20846. || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_CHANGE_VIRTUAL_GAMEPAD))
  20847. || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING))
  20848. || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_SEND_DEBUG_INFO))
  20849. || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CHEEVOS_DESCRIPTION)))
  20850. return true;
  20851. if (
  20852. string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CHEEVOS_DESCRIPTION)))
  20853. return true;
  20854. return false;
  20855. }
  20856. /* Used to close an active message box (help or info)
  20857. * TODO/FIXME: The way that message boxes are handled
  20858. * is complete garbage. generic_menu_iterate() and
  20859. * message boxes in general need a total rewrite.
  20860. * I consider this current 'close_messagebox' a hack,
  20861. * but at least it prevents undefined/dangerous
  20862. * behaviour... */
  20863. static void menu_input_pointer_close_messagebox(struct menu_state *menu_st)
  20864. {
  20865. const char *label = NULL;
  20866. /* Determine whether this is a help or info
  20867. * message box */
  20868. file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
  20869. NULL, &label, NULL, NULL);
  20870. /* Pop stack, if required */
  20871. if (menu_should_pop_stack(label))
  20872. {
  20873. size_t selection = menu_st->selection_ptr;
  20874. size_t new_selection = selection;
  20875. menu_entries_pop_stack(&new_selection, 0, 0);
  20876. menu_st->selection_ptr = selection;
  20877. }
  20878. }
  20879. static int menu_input_pointer_post_iterate(
  20880. struct rarch_state *p_rarch,
  20881. retro_time_t current_time,
  20882. menu_file_list_cbs_t *cbs,
  20883. menu_entry_t *entry, unsigned action)
  20884. {
  20885. static retro_time_t start_time = 0;
  20886. static int16_t start_x = 0;
  20887. static int16_t start_y = 0;
  20888. static int16_t last_x = 0;
  20889. static int16_t last_y = 0;
  20890. static uint16_t dx_start_right_max = 0;
  20891. static uint16_t dx_start_left_max = 0;
  20892. static uint16_t dy_start_up_max = 0;
  20893. static uint16_t dy_start_down_max = 0;
  20894. static bool last_select_pressed = false;
  20895. static bool last_cancel_pressed = false;
  20896. static bool last_left_pressed = false;
  20897. static bool last_right_pressed = false;
  20898. static retro_time_t last_left_action_time = 0;
  20899. static retro_time_t last_right_action_time = 0;
  20900. static retro_time_t last_press_direction_time = 0;
  20901. bool attenuate_y_accel = true;
  20902. bool osk_active = menu_input_dialog_get_display_kb();
  20903. bool messagebox_active = false;
  20904. int ret = 0;
  20905. menu_input_pointer_hw_state_t *pointer_hw_state = &p_rarch->menu_input_pointer_hw_state;
  20906. menu_input_t *menu_input = &p_rarch->menu_input_state;
  20907. menu_handle_t *menu = p_rarch->menu_driver_data;
  20908. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  20909. /* Check whether a message box is currently
  20910. * being shown
  20911. * > Note: This ignores input bind dialogs,
  20912. * since input binding overrides normal input
  20913. * and must be handled separately... */
  20914. if (menu)
  20915. messagebox_active = BIT64_GET(
  20916. menu->state, MENU_STATE_RENDER_MESSAGEBOX) &&
  20917. !string_is_empty(menu->menu_state_msg);
  20918. /* If onscreen keyboard is shown and we currently have
  20919. * active mouse input, highlight key under mouse cursor */
  20920. if (osk_active &&
  20921. (menu_input->pointer.type == MENU_POINTER_MOUSE) &&
  20922. pointer_hw_state->active)
  20923. {
  20924. menu_ctx_pointer_t point;
  20925. point.x = pointer_hw_state->x;
  20926. point.y = pointer_hw_state->y;
  20927. point.ptr = 0;
  20928. point.cbs = NULL;
  20929. point.entry = NULL;
  20930. point.action = 0;
  20931. point.gesture = MENU_INPUT_GESTURE_NONE;
  20932. point.retcode = 0;
  20933. menu_driver_ctl(RARCH_MENU_CTL_OSK_PTR_AT_POS, &point);
  20934. if (point.retcode > -1)
  20935. p_rarch->osk_ptr = point.retcode;
  20936. }
  20937. /* Select + X/Y position */
  20938. if (!menu_input->select_inhibit)
  20939. {
  20940. if (pointer_hw_state->select_pressed)
  20941. {
  20942. int16_t x = pointer_hw_state->x;
  20943. int16_t y = pointer_hw_state->y;
  20944. static float accel0 = 0.0f;
  20945. static float accel1 = 0.0f;
  20946. /* Transition from select unpressed to select pressed */
  20947. if (!last_select_pressed)
  20948. {
  20949. menu_ctx_pointer_t point;
  20950. /* Initialise variables */
  20951. start_time = current_time;
  20952. start_x = x;
  20953. start_y = y;
  20954. last_x = x;
  20955. last_y = y;
  20956. dx_start_right_max = 0;
  20957. dx_start_left_max = 0;
  20958. dy_start_up_max = 0;
  20959. dy_start_down_max = 0;
  20960. accel0 = 0.0f;
  20961. accel1 = 0.0f;
  20962. last_press_direction_time = 0;
  20963. /* If we are not currently showing the onscreen
  20964. * keyboard or a message box, trigger a 'pointer
  20965. * down' event */
  20966. if (!osk_active && !messagebox_active)
  20967. {
  20968. point.x = x;
  20969. point.y = y;
  20970. /* Note: menu_input->ptr is meaningless here when
  20971. * using a touchscreen... */
  20972. point.ptr = menu_input->ptr;
  20973. point.cbs = cbs;
  20974. point.entry = entry;
  20975. point.action = action;
  20976. point.gesture = MENU_INPUT_GESTURE_NONE;
  20977. menu_driver_ctl(RARCH_MENU_CTL_POINTER_DOWN, &point);
  20978. ret = point.retcode;
  20979. }
  20980. }
  20981. else
  20982. {
  20983. /* Pointer is being held down
  20984. * (i.e. for more than one frame) */
  20985. float dpi = menu ? menu_input_get_dpi(p_rarch) : 0.0f;
  20986. /* > Update deltas + acceleration & detect press direction
  20987. * Note: We only do this if the pointer has moved above
  20988. * a certain threshold - this requires dpi info */
  20989. if (dpi > 0.0f)
  20990. {
  20991. uint16_t dpi_threshold_drag =
  20992. (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_DRAG) + 0.5f);
  20993. int16_t dx_start = x - start_x;
  20994. int16_t dy_start = y - start_y;
  20995. uint16_t dx_start_abs = dx_start < 0 ? dx_start * -1 : dx_start;
  20996. uint16_t dy_start_abs = dy_start < 0 ? dy_start * -1 : dy_start;
  20997. if ((dx_start_abs > dpi_threshold_drag) ||
  20998. (dy_start_abs > dpi_threshold_drag))
  20999. {
  21000. uint16_t dpi_threshold_press_direction_min =
  21001. (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MIN) + 0.5f);
  21002. uint16_t dpi_threshold_press_direction_max =
  21003. (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MAX) + 0.5f);
  21004. uint16_t dpi_threshold_press_direction_tangent =
  21005. (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_TANGENT) + 0.5f);
  21006. enum menu_input_pointer_press_direction
  21007. press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
  21008. float press_direction_amplitude = 0.0f;
  21009. retro_time_t press_direction_delay = MENU_INPUT_PRESS_DIRECTION_DELAY_MAX;
  21010. /* Pointer has moved a sufficient distance to
  21011. * trigger a 'dragged' state */
  21012. menu_input->pointer.dragged = true;
  21013. /* Here we diverge:
  21014. * > If onscreen keyboard or a message box is
  21015. * active, pointer deltas, acceleration and
  21016. * press direction must be inhibited
  21017. * > If not, input is processed normally */
  21018. if (osk_active || messagebox_active)
  21019. {
  21020. /* Inhibit normal pointer input */
  21021. menu_input->pointer.dx = 0;
  21022. menu_input->pointer.dy = 0;
  21023. menu_input->pointer.y_accel = 0.0f;
  21024. menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
  21025. accel0 = 0.0f;
  21026. accel1 = 0.0f;
  21027. attenuate_y_accel = false;
  21028. }
  21029. else
  21030. {
  21031. /* Assign current deltas */
  21032. menu_input->pointer.dx = x - last_x;
  21033. menu_input->pointer.dy = y - last_y;
  21034. /* Update maximum start->current deltas */
  21035. if (dx_start > 0)
  21036. dx_start_right_max = (dx_start_abs > dx_start_right_max) ?
  21037. dx_start_abs : dx_start_right_max;
  21038. else
  21039. dx_start_left_max = (dx_start_abs > dx_start_left_max) ?
  21040. dx_start_abs : dx_start_left_max;
  21041. if (dy_start > 0)
  21042. dy_start_down_max = (dy_start_abs > dy_start_down_max) ?
  21043. dy_start_abs : dy_start_down_max;
  21044. else
  21045. dy_start_up_max = (dy_start_abs > dy_start_up_max) ?
  21046. dy_start_abs : dy_start_up_max;
  21047. /* Magic numbers... */
  21048. menu_input->pointer.y_accel = (accel0 + accel1 + (float)menu_input->pointer.dy) / 3.0f;
  21049. accel0 = accel1;
  21050. accel1 = menu_input->pointer.y_accel;
  21051. /* Acceleration decays over time - but if the value
  21052. * has been set on this frame, attenuation should
  21053. * be skipped */
  21054. attenuate_y_accel = false;
  21055. /* Check if pointer is being held in a particular
  21056. * direction */
  21057. menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
  21058. /* > Press directions are actually triggered as a pulse train,
  21059. * since a continuous direction prevents fine control in the
  21060. * context of menu actions (i.e. it would be the same
  21061. * as always holding down a cursor key all the time - too fast
  21062. * to control). We therefore apply a low pass filter, with
  21063. * a variable frequency based upon the distance the user has
  21064. * dragged the pointer */
  21065. /* > Horizontal */
  21066. if ((dx_start_abs >= dpi_threshold_press_direction_min) &&
  21067. (dy_start_abs < dpi_threshold_press_direction_tangent))
  21068. {
  21069. press_direction = (dx_start > 0) ?
  21070. MENU_INPUT_PRESS_DIRECTION_RIGHT : MENU_INPUT_PRESS_DIRECTION_LEFT;
  21071. /* Get effective amplitude of press direction offset */
  21072. press_direction_amplitude =
  21073. (float)(dx_start_abs - dpi_threshold_press_direction_min) /
  21074. (float)(dpi_threshold_press_direction_max - dpi_threshold_press_direction_min);
  21075. }
  21076. /* > Vertical */
  21077. else if ((dy_start_abs >= dpi_threshold_press_direction_min) &&
  21078. (dx_start_abs < dpi_threshold_press_direction_tangent))
  21079. {
  21080. press_direction = (dy_start > 0) ?
  21081. MENU_INPUT_PRESS_DIRECTION_DOWN : MENU_INPUT_PRESS_DIRECTION_UP;
  21082. /* Get effective amplitude of press direction offset */
  21083. press_direction_amplitude =
  21084. (float)(dy_start_abs - dpi_threshold_press_direction_min) /
  21085. (float)(dpi_threshold_press_direction_max - dpi_threshold_press_direction_min);
  21086. }
  21087. if (press_direction != MENU_INPUT_PRESS_DIRECTION_NONE)
  21088. {
  21089. /* > Update low pass filter frequency */
  21090. if (press_direction_amplitude > 1.0f)
  21091. press_direction_delay = MENU_INPUT_PRESS_DIRECTION_DELAY_MIN;
  21092. else
  21093. press_direction_delay = MENU_INPUT_PRESS_DIRECTION_DELAY_MIN +
  21094. ((MENU_INPUT_PRESS_DIRECTION_DELAY_MAX - MENU_INPUT_PRESS_DIRECTION_DELAY_MIN)*
  21095. (1.0f - press_direction_amplitude));
  21096. /* > Apply low pass filter */
  21097. if (current_time - last_press_direction_time > press_direction_delay)
  21098. {
  21099. menu_input->pointer.press_direction = press_direction;
  21100. last_press_direction_time = current_time;
  21101. }
  21102. }
  21103. }
  21104. }
  21105. else
  21106. {
  21107. /* Pointer is stationary */
  21108. menu_input->pointer.dx = 0;
  21109. menu_input->pointer.dy = 0;
  21110. menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
  21111. /* Standard behaviour (on Android, at least) is to stop
  21112. * scrolling when the user touches the screen. We should
  21113. * therefore 'reset' y acceleration whenever the pointer
  21114. * is stationary - with two caveats:
  21115. * - We only disable scrolling if the pointer *remains*
  21116. * stationary. If the pointer is held down then
  21117. * subsequently moves, normal scrolling should resume
  21118. * - Halting the scroll immediately produces a very
  21119. * unpleasant 'jerky' user experience. To avoid this,
  21120. * we add a small delay between detecting a pointer
  21121. * down event and forcing y acceleration to zero
  21122. * NOTE: Of course, we must also 'reset' y acceleration
  21123. * whenever the onscreen keyboard or a message box is
  21124. * shown */
  21125. if ((!menu_input->pointer.dragged &&
  21126. (menu_input->pointer.press_duration > MENU_INPUT_Y_ACCEL_RESET_DELAY)) ||
  21127. (osk_active || messagebox_active))
  21128. {
  21129. menu_input->pointer.y_accel = 0.0f;
  21130. accel0 = 0.0f;
  21131. accel1 = 0.0f;
  21132. attenuate_y_accel = false;
  21133. }
  21134. }
  21135. }
  21136. else
  21137. {
  21138. /* No dpi info - just fallback to zero... */
  21139. menu_input->pointer.dx = 0;
  21140. menu_input->pointer.dy = 0;
  21141. menu_input->pointer.y_accel = 0.0f;
  21142. menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
  21143. accel0 = 0.0f;
  21144. accel1 = 0.0f;
  21145. attenuate_y_accel = false;
  21146. }
  21147. /* > Update remaining variables */
  21148. menu_input->pointer.press_duration = current_time - start_time;
  21149. last_x = x;
  21150. last_y = y;
  21151. }
  21152. }
  21153. else if (last_select_pressed)
  21154. {
  21155. /* Transition from select pressed to select unpressed */
  21156. int16_t x;
  21157. int16_t y;
  21158. menu_ctx_pointer_t point;
  21159. if (menu_input->pointer.dragged)
  21160. {
  21161. /* Pointer has moved.
  21162. * When using a touchscreen, releasing a press
  21163. * resets the x/y position - so cannot use
  21164. * current hardware x/y values. Instead, use
  21165. * previous position from last time that a
  21166. * press was active */
  21167. x = last_x;
  21168. y = last_y;
  21169. }
  21170. else
  21171. {
  21172. /* Pointer is considered stationary,
  21173. * so use start position */
  21174. x = start_x;
  21175. y = start_y;
  21176. }
  21177. point.x = x;
  21178. point.y = y;
  21179. point.ptr = menu_input->ptr;
  21180. point.cbs = cbs;
  21181. point.entry = entry;
  21182. point.action = action;
  21183. point.gesture = MENU_INPUT_GESTURE_NONE;
  21184. /* On screen keyboard overrides normal menu input... */
  21185. if (osk_active)
  21186. {
  21187. /* If pointer has been 'dragged', then it counts as
  21188. * a miss. Only register 'release' event if pointer
  21189. * has remained stationary */
  21190. if (!menu_input->pointer.dragged)
  21191. {
  21192. menu_driver_ctl(RARCH_MENU_CTL_OSK_PTR_AT_POS, &point);
  21193. if (point.retcode > -1)
  21194. {
  21195. bool show_osk_symbols = input_event_osk_show_symbol_pages(p_rarch);
  21196. p_rarch->osk_ptr = point.retcode;
  21197. input_event_osk_append(
  21198. p_rarch,
  21199. &p_rarch->osk_idx,
  21200. point.retcode,
  21201. show_osk_symbols,
  21202. p_rarch->osk_grid[p_rarch->osk_ptr]);
  21203. }
  21204. }
  21205. }
  21206. /* Message boxes override normal menu input...
  21207. * > If a message box is shown, any kind of pointer
  21208. * gesture should close it */
  21209. else if (messagebox_active)
  21210. menu_input_pointer_close_messagebox(
  21211. &p_rarch->menu_driver_state);
  21212. /* Normal menu input */
  21213. else
  21214. {
  21215. /* Detect gesture type */
  21216. if (!menu_input->pointer.dragged)
  21217. {
  21218. /* Pointer hasn't moved - check press duration */
  21219. if (menu_input->pointer.press_duration
  21220. < MENU_INPUT_PRESS_TIME_SHORT)
  21221. point.gesture = MENU_INPUT_GESTURE_TAP;
  21222. else if (menu_input->pointer.press_duration
  21223. < MENU_INPUT_PRESS_TIME_LONG)
  21224. point.gesture = MENU_INPUT_GESTURE_SHORT_PRESS;
  21225. else
  21226. point.gesture = MENU_INPUT_GESTURE_LONG_PRESS;
  21227. }
  21228. else
  21229. {
  21230. /* Pointer has moved - check if this is a swipe */
  21231. float dpi = menu ? menu_input_get_dpi(p_rarch) : 0.0f;
  21232. if ((dpi > 0.0f)
  21233. &&
  21234. (menu_input->pointer.press_duration <
  21235. MENU_INPUT_SWIPE_TIMEOUT))
  21236. {
  21237. uint16_t dpi_threshold_swipe =
  21238. (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_SWIPE) + 0.5f);
  21239. uint16_t dpi_threshold_swipe_tangent =
  21240. (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_SWIPE_TANGENT) + 0.5f);
  21241. int16_t dx_start = x - start_x;
  21242. int16_t dy_start = y - start_y;
  21243. uint16_t dx_start_right_final = 0;
  21244. uint16_t dx_start_left_final = 0;
  21245. uint16_t dy_start_up_final = 0;
  21246. uint16_t dy_start_down_final = 0;
  21247. /* Get final deltas */
  21248. if (dx_start > 0)
  21249. dx_start_right_final = (uint16_t)dx_start;
  21250. else
  21251. dx_start_left_final = (uint16_t)
  21252. (dx_start * -1);
  21253. if (dy_start > 0)
  21254. dy_start_down_final = (uint16_t)dy_start;
  21255. else
  21256. dy_start_up_final = (uint16_t)
  21257. (dy_start * -1);
  21258. /* Swipe right */
  21259. if ( (dx_start_right_final > dpi_threshold_swipe)
  21260. && (dx_start_left_max < dpi_threshold_swipe_tangent)
  21261. && (dy_start_up_max < dpi_threshold_swipe_tangent)
  21262. && (dy_start_down_max < dpi_threshold_swipe_tangent)
  21263. )
  21264. point.gesture = MENU_INPUT_GESTURE_SWIPE_RIGHT;
  21265. /* Swipe left */
  21266. else if (
  21267. (dx_start_right_max < dpi_threshold_swipe_tangent)
  21268. && (dx_start_left_final > dpi_threshold_swipe)
  21269. && (dy_start_up_max < dpi_threshold_swipe_tangent)
  21270. && (dy_start_down_max < dpi_threshold_swipe_tangent)
  21271. )
  21272. point.gesture = MENU_INPUT_GESTURE_SWIPE_LEFT;
  21273. /* Swipe up */
  21274. else if (
  21275. (dx_start_right_max < dpi_threshold_swipe_tangent)
  21276. && (dx_start_left_max < dpi_threshold_swipe_tangent)
  21277. && (dy_start_up_final > dpi_threshold_swipe)
  21278. && (dy_start_down_max < dpi_threshold_swipe_tangent)
  21279. )
  21280. point.gesture = MENU_INPUT_GESTURE_SWIPE_UP;
  21281. /* Swipe down */
  21282. else if (
  21283. (dx_start_right_max < dpi_threshold_swipe_tangent)
  21284. && (dx_start_left_max < dpi_threshold_swipe_tangent)
  21285. && (dy_start_up_max < dpi_threshold_swipe_tangent)
  21286. && (dy_start_down_final > dpi_threshold_swipe)
  21287. )
  21288. point.gesture = MENU_INPUT_GESTURE_SWIPE_DOWN;
  21289. }
  21290. }
  21291. /* Trigger a 'pointer up' event */
  21292. menu_driver_ctl(RARCH_MENU_CTL_POINTER_UP, &point);
  21293. ret = point.retcode;
  21294. }
  21295. /* Reset variables */
  21296. start_x = 0;
  21297. start_y = 0;
  21298. last_x = 0;
  21299. last_y = 0;
  21300. dx_start_right_max = 0;
  21301. dx_start_left_max = 0;
  21302. dy_start_up_max = 0;
  21303. dy_start_down_max = 0;
  21304. last_press_direction_time = 0;
  21305. menu_input->pointer.press_duration = 0;
  21306. menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
  21307. menu_input->pointer.dx = 0;
  21308. menu_input->pointer.dy = 0;
  21309. menu_input->pointer.dragged = false;
  21310. }
  21311. }
  21312. /* Adjust acceleration
  21313. * > If acceleration has not been set on this frame,
  21314. * apply normal attenuation */
  21315. if (attenuate_y_accel)
  21316. menu_input->pointer.y_accel *= MENU_INPUT_Y_ACCEL_DECAY_FACTOR;
  21317. /* If select has been released, disable any existing
  21318. * select inhibit */
  21319. if (!pointer_hw_state->select_pressed)
  21320. menu_input->select_inhibit = false;
  21321. /* Cancel */
  21322. if ( !menu_input->cancel_inhibit
  21323. && pointer_hw_state->cancel_pressed
  21324. && !last_cancel_pressed)
  21325. {
  21326. /* If currently showing a message box, close it */
  21327. if (messagebox_active)
  21328. menu_input_pointer_close_messagebox(&p_rarch->menu_driver_state);
  21329. /* ...otherwise, invoke standard MENU_ACTION_CANCEL
  21330. * action */
  21331. else
  21332. {
  21333. size_t selection = menu_st->selection_ptr;
  21334. ret = menu_entry_action(entry, selection, MENU_ACTION_CANCEL);
  21335. }
  21336. }
  21337. /* If cancel has been released, disable any existing
  21338. * cancel inhibit */
  21339. if (!pointer_hw_state->cancel_pressed)
  21340. menu_input->cancel_inhibit = false;
  21341. if (!messagebox_active)
  21342. {
  21343. /* Up/Down
  21344. * > Note 1: These always correspond to a mouse wheel, which
  21345. * handles differently from other inputs - i.e. we don't
  21346. * want a 'last pressed' check
  21347. * > Note 2: If a message box is currently shown, must
  21348. * inhibit input */
  21349. /* > Up */
  21350. if (pointer_hw_state->up_pressed)
  21351. {
  21352. size_t selection = menu_st->selection_ptr;
  21353. ret = menu_entry_action(
  21354. entry, selection, MENU_ACTION_UP);
  21355. }
  21356. /* > Down */
  21357. if (pointer_hw_state->down_pressed)
  21358. {
  21359. size_t selection = menu_st->selection_ptr;
  21360. ret = menu_entry_action(
  21361. entry, selection, MENU_ACTION_DOWN);
  21362. }
  21363. /* Left/Right
  21364. * > Note 1: These also always correspond to a mouse wheel...
  21365. * In this case, it's a mouse wheel *tilt* operation, which
  21366. * is incredibly annoying because holding a tilt direction
  21367. * rapidly toggles the input state. The repeat speed is so
  21368. * high that any sort of useable control is impossible - so
  21369. * we have to apply a 'low pass' filter by ignoring inputs
  21370. * that occur below a certain frequency...
  21371. * > Note 2: If a message box is currently shown, must
  21372. * inhibit input */
  21373. /* > Left */
  21374. if ( pointer_hw_state->left_pressed
  21375. && !last_left_pressed)
  21376. {
  21377. if (current_time - last_left_action_time
  21378. > MENU_INPUT_HORIZ_WHEEL_DELAY)
  21379. {
  21380. size_t selection = menu_st->selection_ptr;
  21381. last_left_action_time = current_time;
  21382. ret = menu_entry_action(
  21383. entry, selection, MENU_ACTION_LEFT);
  21384. }
  21385. }
  21386. /* > Right */
  21387. if (
  21388. pointer_hw_state->right_pressed
  21389. && !last_right_pressed)
  21390. {
  21391. if (current_time - last_right_action_time
  21392. > MENU_INPUT_HORIZ_WHEEL_DELAY)
  21393. {
  21394. size_t selection = menu_st->selection_ptr;
  21395. last_right_action_time = current_time;
  21396. ret = menu_entry_action(
  21397. entry, selection, MENU_ACTION_RIGHT);
  21398. }
  21399. }
  21400. }
  21401. last_select_pressed = pointer_hw_state->select_pressed;
  21402. last_cancel_pressed = pointer_hw_state->cancel_pressed;
  21403. last_left_pressed = pointer_hw_state->left_pressed;
  21404. last_right_pressed = pointer_hw_state->right_pressed;
  21405. return ret;
  21406. }
  21407. static int menu_input_post_iterate(
  21408. struct rarch_state *p_rarch,
  21409. unsigned action,
  21410. retro_time_t current_time)
  21411. {
  21412. menu_entry_t entry;
  21413. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  21414. menu_list_t *menu_list = menu_st->entries.list;
  21415. file_list_t *selection_buf = menu_list ? MENU_LIST_GET_SELECTION(menu_list, (unsigned)0) : NULL;
  21416. size_t selection = menu_st->selection_ptr;
  21417. menu_file_list_cbs_t *cbs = selection_buf ?
  21418. (menu_file_list_cbs_t*)selection_buf->list[selection].actiondata
  21419. : NULL;
  21420. MENU_ENTRY_INIT(entry);
  21421. /* Note: If menu_input_pointer_post_iterate() is
  21422. * modified, will have to verify that these
  21423. * parameters remain unused... */
  21424. entry.rich_label_enabled = false;
  21425. entry.value_enabled = false;
  21426. entry.sublabel_enabled = false;
  21427. menu_entry_get(&entry, 0, selection, NULL, false);
  21428. return menu_input_pointer_post_iterate(p_rarch,
  21429. current_time, cbs, &entry, action);
  21430. }
  21431. #endif
  21432. static INLINE bool input_keys_pressed_other_sources(
  21433. struct rarch_state *p_rarch,
  21434. unsigned i,
  21435. input_bits_t* p_new_state)
  21436. {
  21437. #ifdef HAVE_OVERLAY
  21438. if (p_rarch->overlay_ptr &&
  21439. ((BIT256_GET(p_rarch->overlay_ptr->overlay_state.buttons, i))))
  21440. return true;
  21441. #endif
  21442. #ifdef HAVE_COMMAND
  21443. if (p_rarch->input_driver_command)
  21444. return ((i < RARCH_BIND_LIST_END)
  21445. && p_rarch->input_driver_command->state[i]);
  21446. #endif
  21447. #ifdef HAVE_NETWORKGAMEPAD
  21448. /* Only process key presses related to game input if using Remote RetroPad */
  21449. if (i < RARCH_CUSTOM_BIND_LIST_END
  21450. && p_rarch->input_driver_remote
  21451. && INPUT_REMOTE_KEY_PRESSED(p_rarch, i, 0))
  21452. return true;
  21453. #endif
  21454. return false;
  21455. }
  21456. /**
  21457. * input_keys_pressed:
  21458. *
  21459. * Grab an input sample for this frame.
  21460. *
  21461. * Returns: Input sample containing a mask of all pressed keys.
  21462. */
  21463. static void input_keys_pressed(
  21464. unsigned port,
  21465. bool is_menu,
  21466. int input_hotkey_block_delay,
  21467. struct rarch_state *p_rarch,
  21468. input_bits_t *p_new_state,
  21469. const struct retro_keybind **binds,
  21470. const struct retro_keybind *binds_norm,
  21471. const struct retro_keybind *binds_auto,
  21472. rarch_joypad_info_t *joypad_info)
  21473. {
  21474. unsigned i;
  21475. #ifdef HAVE_MFI
  21476. const input_device_driver_t
  21477. *sec_joypad = p_rarch->sec_joypad;
  21478. #else
  21479. const input_device_driver_t
  21480. *sec_joypad = NULL;
  21481. #endif
  21482. if (CHECK_INPUT_DRIVER_BLOCK_HOTKEY(binds_norm, binds_auto))
  21483. {
  21484. if ( input_state_wrap(
  21485. p_rarch->current_input,
  21486. p_rarch->current_input_data,
  21487. p_rarch->joypad,
  21488. sec_joypad,
  21489. joypad_info,
  21490. &binds[port],
  21491. p_rarch->keyboard_mapping_blocked,
  21492. port, RETRO_DEVICE_JOYPAD, 0,
  21493. RARCH_ENABLE_HOTKEY))
  21494. {
  21495. if (p_rarch->input_hotkey_block_counter < input_hotkey_block_delay)
  21496. p_rarch->input_hotkey_block_counter++;
  21497. else
  21498. p_rarch->input_driver_block_libretro_input = true;
  21499. }
  21500. else
  21501. {
  21502. p_rarch->input_hotkey_block_counter = 0;
  21503. p_rarch->input_driver_block_hotkey = true;
  21504. }
  21505. }
  21506. if ( !is_menu
  21507. && binds[port][RARCH_GAME_FOCUS_TOGGLE].valid)
  21508. {
  21509. const struct retro_keybind *focus_binds_auto =
  21510. &input_autoconf_binds[port][RARCH_GAME_FOCUS_TOGGLE];
  21511. const struct retro_keybind *focus_normal =
  21512. &binds[port][RARCH_GAME_FOCUS_TOGGLE];
  21513. /* Allows rarch_focus_toggle hotkey to still work
  21514. * even though every hotkey is blocked */
  21515. if (CHECK_INPUT_DRIVER_BLOCK_HOTKEY(
  21516. focus_normal, focus_binds_auto))
  21517. {
  21518. if (input_state_wrap(
  21519. p_rarch->current_input,
  21520. p_rarch->current_input_data,
  21521. p_rarch->joypad,
  21522. sec_joypad,
  21523. joypad_info,
  21524. &binds[port],
  21525. p_rarch->keyboard_mapping_blocked,
  21526. port,
  21527. RETRO_DEVICE_JOYPAD, 0, RARCH_GAME_FOCUS_TOGGLE))
  21528. p_rarch->input_driver_block_hotkey = false;
  21529. }
  21530. }
  21531. /* Check the libretro input first */
  21532. if (p_rarch->input_driver_block_libretro_input)
  21533. {
  21534. for (i = 0; i < RARCH_FIRST_META_KEY; i++)
  21535. {
  21536. if (input_keys_pressed_other_sources(p_rarch,
  21537. i, p_new_state))
  21538. {
  21539. BIT256_SET_PTR(p_new_state, i);
  21540. }
  21541. }
  21542. }
  21543. else
  21544. {
  21545. int16_t ret = input_state_wrap(
  21546. p_rarch->current_input,
  21547. p_rarch->current_input_data,
  21548. p_rarch->joypad,
  21549. sec_joypad,
  21550. joypad_info, &binds[port],
  21551. p_rarch->keyboard_mapping_blocked,
  21552. port, RETRO_DEVICE_JOYPAD, 0,
  21553. RETRO_DEVICE_ID_JOYPAD_MASK);
  21554. for (i = 0; i < RARCH_FIRST_META_KEY; i++)
  21555. {
  21556. if (
  21557. (ret & (UINT64_C(1) << i)) ||
  21558. input_keys_pressed_other_sources(p_rarch,
  21559. i, p_new_state))
  21560. {
  21561. BIT256_SET_PTR(p_new_state, i);
  21562. }
  21563. }
  21564. }
  21565. /* Check the hotkeys */
  21566. if (p_rarch->input_driver_block_hotkey)
  21567. {
  21568. for (i = RARCH_FIRST_META_KEY; i < RARCH_BIND_LIST_END; i++)
  21569. {
  21570. if (
  21571. BIT64_GET(lifecycle_state, i)
  21572. || input_keys_pressed_other_sources(p_rarch, i, p_new_state))
  21573. {
  21574. BIT256_SET_PTR(p_new_state, i);
  21575. }
  21576. }
  21577. }
  21578. else
  21579. {
  21580. for (i = RARCH_FIRST_META_KEY; i < RARCH_BIND_LIST_END; i++)
  21581. {
  21582. bool bit_pressed = binds[port][i].valid
  21583. && input_state_wrap(
  21584. p_rarch->current_input,
  21585. p_rarch->current_input_data,
  21586. p_rarch->joypad,
  21587. sec_joypad,
  21588. joypad_info,
  21589. &binds[port],
  21590. p_rarch->keyboard_mapping_blocked,
  21591. port, RETRO_DEVICE_JOYPAD, 0, i);
  21592. if ( bit_pressed
  21593. || BIT64_GET(lifecycle_state, i)
  21594. || input_keys_pressed_other_sources(p_rarch, i, p_new_state))
  21595. {
  21596. BIT256_SET_PTR(p_new_state, i);
  21597. }
  21598. }
  21599. }
  21600. }
  21601. void *input_driver_get_data(void)
  21602. {
  21603. struct rarch_state *p_rarch = &rarch_st;
  21604. return p_rarch->current_input_data;
  21605. }
  21606. void input_driver_init_joypads(void)
  21607. {
  21608. struct rarch_state *p_rarch = &rarch_st;
  21609. settings_t *settings = p_rarch->configuration_settings;
  21610. p_rarch->joypad = input_joypad_init_driver(
  21611. settings->arrays.input_joypad_driver,
  21612. p_rarch->current_input_data);
  21613. #ifdef HAVE_MFI
  21614. p_rarch->sec_joypad = input_joypad_init_driver(
  21615. "mfi",
  21616. p_rarch->current_input_data);
  21617. #endif
  21618. }
  21619. void *input_driver_init_wrap(input_driver_t *input, const char *name)
  21620. {
  21621. void *ret = NULL;
  21622. if (!input)
  21623. return NULL;
  21624. if ((ret = input->init(name)))
  21625. {
  21626. input_driver_init_joypads();
  21627. return ret;
  21628. }
  21629. return NULL;
  21630. }
  21631. static bool input_driver_init(struct rarch_state *p_rarch)
  21632. {
  21633. if (p_rarch->current_input)
  21634. {
  21635. settings_t *settings = p_rarch->configuration_settings;
  21636. p_rarch->current_input_data = input_driver_init_wrap(
  21637. p_rarch->current_input, settings->arrays.input_joypad_driver);
  21638. }
  21639. return (p_rarch->current_input_data != NULL);
  21640. }
  21641. static bool input_driver_find_driver(struct rarch_state *p_rarch)
  21642. {
  21643. settings_t *settings = p_rarch->configuration_settings;
  21644. int i = (int)driver_find_index(
  21645. "input_driver",
  21646. settings->arrays.input_driver);
  21647. if (i >= 0)
  21648. {
  21649. p_rarch->current_input = (input_driver_t*)input_drivers[i];
  21650. RARCH_LOG("[Input]: Found input driver: \"%s\".\n",
  21651. p_rarch->current_input->ident);
  21652. }
  21653. else
  21654. {
  21655. unsigned d;
  21656. RARCH_ERR("Couldn't find any input driver named \"%s\"\n",
  21657. settings->arrays.input_driver);
  21658. RARCH_LOG_OUTPUT("Available input drivers are:\n");
  21659. for (d = 0; input_drivers[d]; d++)
  21660. RARCH_LOG_OUTPUT("\t%s\n", input_drivers[d]->ident);
  21661. RARCH_WARN("Going to default to first input driver...\n");
  21662. p_rarch->current_input = (input_driver_t*)input_drivers[0];
  21663. if (!p_rarch->current_input)
  21664. {
  21665. retroarch_fail(1, "find_input_driver()");
  21666. return false;
  21667. }
  21668. }
  21669. return true;
  21670. }
  21671. void input_driver_set_nonblock_state(void)
  21672. {
  21673. struct rarch_state *p_rarch = &rarch_st;
  21674. p_rarch->input_driver_nonblock_state = true;
  21675. }
  21676. void input_driver_unset_nonblock_state(void)
  21677. {
  21678. struct rarch_state *p_rarch = &rarch_st;
  21679. p_rarch->input_driver_nonblock_state = false;
  21680. }
  21681. #ifdef HAVE_COMMAND
  21682. static bool input_driver_init_command(struct rarch_state *p_rarch)
  21683. {
  21684. settings_t *settings = p_rarch->configuration_settings;
  21685. bool input_stdin_cmd_enable = settings->bools.stdin_cmd_enable;
  21686. bool input_network_cmd_enable = settings->bools.network_cmd_enable;
  21687. unsigned network_cmd_port = settings->uints.network_cmd_port;
  21688. bool grab_stdin = p_rarch->current_input->grab_stdin &&
  21689. p_rarch->current_input->grab_stdin(p_rarch->current_input_data);
  21690. if (!input_stdin_cmd_enable && !input_network_cmd_enable)
  21691. return false;
  21692. if (input_stdin_cmd_enable && grab_stdin)
  21693. {
  21694. RARCH_WARN("stdin command interface is desired, but input driver has already claimed stdin.\n"
  21695. "Cannot use this command interface.\n");
  21696. }
  21697. p_rarch->input_driver_command = (command_t*)
  21698. calloc(1, sizeof(*p_rarch->input_driver_command));
  21699. if (p_rarch->input_driver_command)
  21700. if (command_network_new(
  21701. p_rarch->input_driver_command,
  21702. input_stdin_cmd_enable && !grab_stdin,
  21703. input_network_cmd_enable,
  21704. network_cmd_port))
  21705. return true;
  21706. RARCH_ERR("Failed to initialize command interface.\n");
  21707. return false;
  21708. }
  21709. static void input_driver_deinit_command(struct rarch_state *p_rarch)
  21710. {
  21711. if (p_rarch->input_driver_command)
  21712. command_free(p_rarch->input_driver_command);
  21713. p_rarch->input_driver_command = NULL;
  21714. }
  21715. #endif
  21716. #ifdef HAVE_NETWORKGAMEPAD
  21717. static input_remote_t *input_driver_init_remote(
  21718. settings_t *settings,
  21719. unsigned num_active_users)
  21720. {
  21721. unsigned network_remote_base_port = settings->uints.network_remote_base_port;
  21722. return input_remote_new(
  21723. settings,
  21724. network_remote_base_port,
  21725. num_active_users);
  21726. }
  21727. #endif
  21728. float *input_driver_get_float(enum input_action action)
  21729. {
  21730. struct rarch_state *p_rarch = &rarch_st;
  21731. switch (action)
  21732. {
  21733. case INPUT_ACTION_AXIS_THRESHOLD:
  21734. return &p_rarch->input_driver_axis_threshold;
  21735. default:
  21736. case INPUT_ACTION_NONE:
  21737. break;
  21738. }
  21739. return NULL;
  21740. }
  21741. unsigned *input_driver_get_uint(enum input_action action)
  21742. {
  21743. struct rarch_state *p_rarch = &rarch_st;
  21744. switch (action)
  21745. {
  21746. case INPUT_ACTION_MAX_USERS:
  21747. return &p_rarch->input_driver_max_users;
  21748. default:
  21749. case INPUT_ACTION_NONE:
  21750. break;
  21751. }
  21752. return NULL;
  21753. }
  21754. /**
  21755. * config_get_joypad_driver_options:
  21756. *
  21757. * Get an enumerated list of all joypad driver names, separated by '|'.
  21758. *
  21759. * Returns: string listing of all joypad driver names, separated by '|'.
  21760. **/
  21761. const char* config_get_joypad_driver_options(void)
  21762. {
  21763. return char_list_new_special(STRING_LIST_INPUT_JOYPAD_DRIVERS, NULL);
  21764. }
  21765. /**
  21766. * input_joypad_init_first:
  21767. *
  21768. * Finds first suitable joypad driver and initializes.
  21769. *
  21770. * Returns: joypad driver if found, otherwise NULL.
  21771. **/
  21772. static const input_device_driver_t *input_joypad_init_first(void *data)
  21773. {
  21774. unsigned i;
  21775. for (i = 0; joypad_drivers[i]; i++)
  21776. {
  21777. if ( joypad_drivers[i]
  21778. && joypad_drivers[i]->init)
  21779. {
  21780. void *ptr = joypad_drivers[i]->init(data);
  21781. if (ptr)
  21782. {
  21783. RARCH_LOG("[Joypad]: Found joypad driver: \"%s\".\n",
  21784. joypad_drivers[i]->ident);
  21785. return joypad_drivers[i];
  21786. }
  21787. }
  21788. }
  21789. return NULL;
  21790. }
  21791. /**
  21792. * input_joypad_init_driver:
  21793. * @ident : identifier of driver to initialize.
  21794. *
  21795. * Initialize a joypad driver of name @ident.
  21796. *
  21797. * If ident points to NULL or a zero-length string,
  21798. * equivalent to calling input_joypad_init_first().
  21799. *
  21800. * Returns: joypad driver if found, otherwise NULL.
  21801. **/
  21802. const input_device_driver_t *input_joypad_init_driver(
  21803. const char *ident, void *data)
  21804. {
  21805. unsigned i;
  21806. if (ident && *ident)
  21807. {
  21808. for (i = 0; joypad_drivers[i]; i++)
  21809. {
  21810. if (string_is_equal(ident, joypad_drivers[i]->ident)
  21811. && joypad_drivers[i]->init)
  21812. {
  21813. void *ptr = joypad_drivers[i]->init(data);
  21814. if (ptr)
  21815. {
  21816. RARCH_LOG("[Joypad]: Found joypad driver: \"%s\".\n",
  21817. joypad_drivers[i]->ident);
  21818. return joypad_drivers[i];
  21819. }
  21820. }
  21821. }
  21822. }
  21823. return input_joypad_init_first(data);
  21824. }
  21825. bool input_key_pressed(int key, bool keyboard_pressed)
  21826. {
  21827. /* If a keyboard key is pressed then immediately return
  21828. * true, otherwise call button_is_pressed to determine
  21829. * if the input comes from another input device */
  21830. if (!(
  21831. (key < RARCH_BIND_LIST_END)
  21832. && keyboard_pressed
  21833. )
  21834. )
  21835. {
  21836. rarch_joypad_info_t joypad_info;
  21837. struct rarch_state
  21838. *p_rarch = &rarch_st;
  21839. const input_device_driver_t
  21840. *joypad = (const input_device_driver_t*)p_rarch->joypad;
  21841. joypad_info.joy_idx = 0;
  21842. joypad_info.auto_binds = input_autoconf_binds[0];
  21843. joypad_info.axis_threshold = p_rarch->input_driver_axis_threshold;
  21844. return button_is_pressed(
  21845. joypad, &joypad_info,
  21846. input_config_binds[0],
  21847. joypad_info.joy_idx,
  21848. key);
  21849. }
  21850. return true;
  21851. }
  21852. bool input_mouse_grabbed(void)
  21853. {
  21854. struct rarch_state *p_rarch = &rarch_st;
  21855. return p_rarch->input_driver_grab_mouse_state;
  21856. }
  21857. int16_t button_is_pressed(
  21858. const input_device_driver_t *joypad,
  21859. rarch_joypad_info_t *joypad_info,
  21860. const struct retro_keybind *binds,
  21861. unsigned port, unsigned id)
  21862. {
  21863. /* Auto-binds are per joypad, not per user. */
  21864. const uint64_t joykey = (binds[id].joykey != NO_BTN)
  21865. ? binds[id].joykey : joypad_info->auto_binds[id].joykey;
  21866. const uint32_t joyaxis = (binds[id].joyaxis != AXIS_NONE)
  21867. ? binds[id].joyaxis : joypad_info->auto_binds[id].joyaxis;
  21868. if ((uint16_t)joykey != NO_BTN && joypad->button(
  21869. joypad_info->joy_idx, (uint16_t)joykey))
  21870. return 1;
  21871. if (joyaxis != AXIS_NONE &&
  21872. ((float)abs(joypad->axis(joypad_info->joy_idx, joyaxis))
  21873. / 0x8000) > joypad_info->axis_threshold)
  21874. return 1;
  21875. return 0;
  21876. }
  21877. /**
  21878. * input_joypad_analog:
  21879. * @drv : Input device driver handle.
  21880. * @port : User number.
  21881. * @idx : Analog key index.
  21882. * E.g.:
  21883. * - RETRO_DEVICE_INDEX_ANALOG_LEFT
  21884. * - RETRO_DEVICE_INDEX_ANALOG_RIGHT
  21885. * @ident : Analog key identifier.
  21886. * E.g.:
  21887. * - RETRO_DEVICE_ID_ANALOG_X
  21888. * - RETRO_DEVICE_ID_ANALOG_Y
  21889. * @binds : Binds of user.
  21890. *
  21891. * Gets analog value of analog key identifiers @idx and @ident
  21892. * from user with number @port with provided keybinds (@binds).
  21893. *
  21894. * Returns: analog value on success, otherwise 0.
  21895. **/
  21896. static int16_t input_joypad_analog_button(
  21897. struct rarch_state *p_rarch,
  21898. settings_t *settings,
  21899. const input_device_driver_t *drv,
  21900. rarch_joypad_info_t *joypad_info,
  21901. unsigned port, unsigned idx, unsigned ident,
  21902. const struct retro_keybind *binds)
  21903. {
  21904. int16_t res = 0;
  21905. float normal_mag = 0.0f;
  21906. float input_analog_deadzone = settings->floats.input_analog_deadzone;
  21907. const struct retro_keybind *bind = &binds[ ident ];
  21908. uint32_t axis = (bind->joyaxis == AXIS_NONE)
  21909. ? joypad_info->auto_binds[ident].joyaxis
  21910. : bind->joyaxis;
  21911. /* Analog button. */
  21912. if (input_analog_deadzone)
  21913. {
  21914. int16_t mult = 0;
  21915. if (axis != AXIS_NONE)
  21916. mult = drv->axis(
  21917. joypad_info->joy_idx, axis);
  21918. normal_mag = fabs((1.0f / 0x7fff) * mult);
  21919. }
  21920. res = abs(input_joypad_axis(p_rarch, drv,
  21921. joypad_info->joy_idx, axis, normal_mag));
  21922. /* If the result is zero, it's got a digital button
  21923. * attached to it instead */
  21924. if (res == 0)
  21925. {
  21926. uint16_t key = (bind->joykey == NO_BTN)
  21927. ? joypad_info->auto_binds[ident].joykey
  21928. : bind->joykey;
  21929. if (drv->button(joypad_info->joy_idx, key))
  21930. return 0x7fff;
  21931. return 0;
  21932. }
  21933. return res;
  21934. }
  21935. static int16_t input_joypad_analog_axis(
  21936. struct rarch_state *p_rarch,
  21937. settings_t *settings,
  21938. const input_device_driver_t *drv,
  21939. rarch_joypad_info_t *joypad_info,
  21940. unsigned port, unsigned idx, unsigned ident,
  21941. const struct retro_keybind *binds)
  21942. {
  21943. int16_t res = 0;
  21944. /* Analog sticks. Either RETRO_DEVICE_INDEX_ANALOG_LEFT
  21945. * or RETRO_DEVICE_INDEX_ANALOG_RIGHT */
  21946. unsigned ident_minus = 0;
  21947. unsigned ident_plus = 0;
  21948. unsigned ident_x_minus = 0;
  21949. unsigned ident_x_plus = 0;
  21950. unsigned ident_y_minus = 0;
  21951. unsigned ident_y_plus = 0;
  21952. const struct retro_keybind *bind_minus = NULL;
  21953. const struct retro_keybind *bind_plus = NULL;
  21954. const struct retro_keybind *bind_x_minus = NULL;
  21955. const struct retro_keybind *bind_x_plus = NULL;
  21956. const struct retro_keybind *bind_y_minus = NULL;
  21957. const struct retro_keybind *bind_y_plus = NULL;
  21958. /* Skip analog input with analog_dpad_mode */
  21959. switch (settings->uints.input_analog_dpad_mode[port])
  21960. {
  21961. case ANALOG_DPAD_LSTICK:
  21962. if (idx == RETRO_DEVICE_INDEX_ANALOG_LEFT)
  21963. return 0;
  21964. break;
  21965. case ANALOG_DPAD_RSTICK:
  21966. if (idx == RETRO_DEVICE_INDEX_ANALOG_RIGHT)
  21967. return 0;
  21968. break;
  21969. default:
  21970. break;
  21971. }
  21972. input_conv_analog_id_to_bind_id(idx, ident, ident_minus, ident_plus);
  21973. bind_minus = &binds[ident_minus];
  21974. bind_plus = &binds[ident_plus];
  21975. if (!bind_minus->valid || !bind_plus->valid)
  21976. return 0;
  21977. input_conv_analog_id_to_bind_id(idx,
  21978. RETRO_DEVICE_ID_ANALOG_X, ident_x_minus, ident_x_plus);
  21979. bind_x_minus = &binds[ident_x_minus];
  21980. bind_x_plus = &binds[ident_x_plus];
  21981. if (!bind_x_minus->valid || !bind_x_plus->valid)
  21982. return 0;
  21983. input_conv_analog_id_to_bind_id(idx,
  21984. RETRO_DEVICE_ID_ANALOG_Y, ident_y_minus, ident_y_plus);
  21985. bind_y_minus = &binds[ident_y_minus];
  21986. bind_y_plus = &binds[ident_y_plus];
  21987. if (!bind_y_minus->valid || !bind_y_plus->valid)
  21988. return 0;
  21989. {
  21990. uint32_t axis_minus = (bind_minus->joyaxis == AXIS_NONE)
  21991. ? joypad_info->auto_binds[ident_minus].joyaxis
  21992. : bind_minus->joyaxis;
  21993. uint32_t axis_plus = (bind_plus->joyaxis == AXIS_NONE)
  21994. ? joypad_info->auto_binds[ident_plus].joyaxis
  21995. : bind_plus->joyaxis;
  21996. float input_analog_deadzone =
  21997. settings->floats.input_analog_deadzone;
  21998. float normal_mag = 0.0f;
  21999. /* normalized magnitude of stick actuation, needed for scaled
  22000. * radial deadzone */
  22001. if (input_analog_deadzone)
  22002. {
  22003. float x = 0.0f;
  22004. float y = 0.0f;
  22005. uint32_t x_axis_minus = (bind_x_minus->joyaxis == AXIS_NONE)
  22006. ? joypad_info->auto_binds[ident_x_minus].joyaxis
  22007. : bind_x_minus->joyaxis;
  22008. uint32_t x_axis_plus = (bind_x_plus->joyaxis == AXIS_NONE)
  22009. ? joypad_info->auto_binds[ident_x_plus].joyaxis
  22010. : bind_x_plus->joyaxis;
  22011. uint32_t y_axis_minus = (bind_y_minus->joyaxis == AXIS_NONE)
  22012. ? joypad_info->auto_binds[ident_y_minus].joyaxis
  22013. : bind_y_minus->joyaxis;
  22014. uint32_t y_axis_plus = (bind_y_plus->joyaxis == AXIS_NONE)
  22015. ? joypad_info->auto_binds[ident_y_plus].joyaxis
  22016. : bind_y_plus->joyaxis;
  22017. /* normalized magnitude for radial scaled analog deadzone */
  22018. if (x_axis_plus != AXIS_NONE)
  22019. x = drv->axis(
  22020. joypad_info->joy_idx, x_axis_plus);
  22021. if (x_axis_minus != AXIS_NONE)
  22022. x += drv->axis(joypad_info->joy_idx,
  22023. x_axis_minus);
  22024. if (y_axis_plus != AXIS_NONE)
  22025. y = drv->axis(
  22026. joypad_info->joy_idx, y_axis_plus);
  22027. if (y_axis_minus != AXIS_NONE)
  22028. y += drv->axis(
  22029. joypad_info->joy_idx, y_axis_minus);
  22030. normal_mag = (1.0f / 0x7fff) * sqrt(x * x + y * y);
  22031. }
  22032. res = abs(
  22033. input_joypad_axis(p_rarch,
  22034. drv, joypad_info->joy_idx,
  22035. axis_plus, normal_mag));
  22036. res -= abs(
  22037. input_joypad_axis(p_rarch,
  22038. drv, joypad_info->joy_idx,
  22039. axis_minus, normal_mag));
  22040. }
  22041. if (res == 0)
  22042. {
  22043. uint16_t key_minus = (bind_minus->joykey == NO_BTN)
  22044. ? joypad_info->auto_binds[ident_minus].joykey
  22045. : bind_minus->joykey;
  22046. uint16_t key_plus = (bind_plus->joykey == NO_BTN)
  22047. ? joypad_info->auto_binds[ident_plus].joykey
  22048. : bind_plus->joykey;
  22049. if (drv->button(joypad_info->joy_idx, key_plus))
  22050. res = 0x7fff;
  22051. if (drv->button(joypad_info->joy_idx, key_minus))
  22052. res += -0x7fff;
  22053. }
  22054. return res;
  22055. }
  22056. #ifdef HAVE_MENU
  22057. /**
  22058. * input_mouse_button_raw:
  22059. * @port : Mouse number.
  22060. * @button : Identifier of key (libretro mouse constant).
  22061. *
  22062. * Checks if key (@button) was being pressed by user
  22063. * with mouse number @port.
  22064. *
  22065. * Returns: true (1) if key was pressed, otherwise
  22066. * false (0).
  22067. **/
  22068. static bool input_mouse_button_raw(
  22069. struct rarch_state *p_rarch,
  22070. settings_t *settings,
  22071. unsigned port, unsigned id)
  22072. {
  22073. rarch_joypad_info_t joypad_info;
  22074. input_driver_t *current_input = p_rarch->current_input;
  22075. #ifdef HAVE_MFI
  22076. const input_device_driver_t
  22077. *sec_joypad = p_rarch->sec_joypad;
  22078. #else
  22079. const input_device_driver_t
  22080. *sec_joypad = NULL;
  22081. #endif
  22082. /*ignore axes*/
  22083. if (id == RETRO_DEVICE_ID_MOUSE_X || id == RETRO_DEVICE_ID_MOUSE_Y)
  22084. return false;
  22085. joypad_info.axis_threshold = p_rarch->input_driver_axis_threshold;
  22086. joypad_info.joy_idx = settings->uints.input_joypad_map[port];
  22087. joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx];
  22088. if (current_input->input_state)
  22089. return current_input->input_state(
  22090. p_rarch->current_input_data,
  22091. p_rarch->joypad,
  22092. sec_joypad,
  22093. &joypad_info,
  22094. p_rarch->libretro_input_binds,
  22095. p_rarch->keyboard_mapping_blocked,
  22096. port,
  22097. RETRO_DEVICE_MOUSE, 0, id);
  22098. return false;
  22099. }
  22100. #endif
  22101. void input_pad_connect(unsigned port, input_device_driver_t *driver)
  22102. {
  22103. struct rarch_state *p_rarch = &rarch_st;
  22104. if (port >= MAX_USERS || !driver)
  22105. {
  22106. RARCH_ERR("[Input]: input_pad_connect: bad parameters\n");
  22107. return;
  22108. }
  22109. if (p_rarch->pad_connection_listener)
  22110. p_rarch->pad_connection_listener->connected(port, driver);
  22111. input_autoconfigure_connect(driver->name(port), NULL, driver->ident,
  22112. port, 0, 0);
  22113. }
  22114. #ifdef HAVE_HID
  22115. const void *hid_driver_get_data(void)
  22116. {
  22117. struct rarch_state *p_rarch = &rarch_st;
  22118. return p_rarch->hid_data;
  22119. }
  22120. /* This is only to be called after we've invoked free() on the
  22121. * HID driver; the memory will have already been freed, so we need to
  22122. * reset the pointer.
  22123. */
  22124. void hid_driver_reset_data(void)
  22125. {
  22126. struct rarch_state *p_rarch = &rarch_st;
  22127. p_rarch->hid_data = NULL;
  22128. }
  22129. /**
  22130. * config_get_hid_driver_options:
  22131. *
  22132. * Get an enumerated list of all HID driver names, separated by '|'.
  22133. *
  22134. * Returns: string listing of all HID driver names, separated by '|'.
  22135. **/
  22136. const char* config_get_hid_driver_options(void)
  22137. {
  22138. return char_list_new_special(STRING_LIST_INPUT_HID_DRIVERS, NULL);
  22139. }
  22140. /**
  22141. * input_hid_init_first:
  22142. *
  22143. * Finds first suitable HID driver and initializes.
  22144. *
  22145. * Returns: HID driver if found, otherwise NULL.
  22146. **/
  22147. const hid_driver_t *input_hid_init_first(void)
  22148. {
  22149. unsigned i;
  22150. struct rarch_state *p_rarch = &rarch_st;
  22151. for (i = 0; hid_drivers[i]; i++)
  22152. {
  22153. p_rarch->hid_data = hid_drivers[i]->init();
  22154. if (p_rarch->hid_data)
  22155. {
  22156. RARCH_LOG("[Input]: Found HID driver: \"%s\".\n",
  22157. hid_drivers[i]->ident);
  22158. return hid_drivers[i];
  22159. }
  22160. }
  22161. return NULL;
  22162. }
  22163. #endif
  22164. /**
  22165. * input_keyboard_line_event:
  22166. * @state : Input keyboard line handle.
  22167. * @character : Inputted character.
  22168. *
  22169. * Called on every keyboard character event.
  22170. *
  22171. * Returns: true (1) on success, otherwise false (0).
  22172. **/
  22173. static bool input_keyboard_line_event(
  22174. struct rarch_state *p_rarch,
  22175. input_keyboard_line_t *state, uint32_t character)
  22176. {
  22177. char array[2];
  22178. bool ret = false;
  22179. const char *word = NULL;
  22180. char c = (character >= 128) ? '?' : character;
  22181. /* Treat extended chars as ? as we cannot support
  22182. * printable characters for unicode stuff. */
  22183. if (c == '\r' || c == '\n')
  22184. {
  22185. state->cb(state->userdata, state->buffer);
  22186. array[0] = c;
  22187. array[1] = 0;
  22188. ret = true;
  22189. word = array;
  22190. }
  22191. else if (c == '\b' || c == '\x7f') /* 0x7f is ASCII for del */
  22192. {
  22193. if (state->ptr)
  22194. {
  22195. unsigned i;
  22196. for (i = 0; i < p_rarch->osk_last_codepoint_len; i++)
  22197. {
  22198. memmove(state->buffer + state->ptr - 1,
  22199. state->buffer + state->ptr,
  22200. state->size - state->ptr + 1);
  22201. state->ptr--;
  22202. state->size--;
  22203. }
  22204. word = state->buffer;
  22205. }
  22206. }
  22207. else if (ISPRINT(c))
  22208. {
  22209. /* Handle left/right here when suitable */
  22210. char *newbuf = (char*)
  22211. realloc(state->buffer, state->size + 2);
  22212. if (!newbuf)
  22213. return false;
  22214. memmove(newbuf + state->ptr + 1,
  22215. newbuf + state->ptr,
  22216. state->size - state->ptr + 1);
  22217. newbuf[state->ptr] = c;
  22218. state->ptr++;
  22219. state->size++;
  22220. newbuf[state->size] = '\0';
  22221. state->buffer = newbuf;
  22222. array[0] = c;
  22223. array[1] = 0;
  22224. word = array;
  22225. }
  22226. if (word)
  22227. {
  22228. /* OSK - update last character */
  22229. if (word[0] == 0)
  22230. {
  22231. p_rarch->osk_last_codepoint = 0;
  22232. p_rarch->osk_last_codepoint_len = 0;
  22233. }
  22234. else
  22235. osk_update_last_codepoint(
  22236. &p_rarch->osk_last_codepoint,
  22237. &p_rarch->osk_last_codepoint_len,
  22238. word);
  22239. }
  22240. return ret;
  22241. }
  22242. #ifdef HAVE_MENU
  22243. static bool input_keyboard_line_append(
  22244. struct input_keyboard_line *keyboard_line,
  22245. const char *word)
  22246. {
  22247. unsigned i = 0;
  22248. unsigned len = (unsigned)strlen(word);
  22249. char *newbuf = (char*)realloc(
  22250. keyboard_line->buffer,
  22251. keyboard_line->size + len * 2);
  22252. if (!newbuf)
  22253. return false;
  22254. memmove(
  22255. newbuf + keyboard_line->ptr + len,
  22256. newbuf + keyboard_line->ptr,
  22257. keyboard_line->size - keyboard_line->ptr + len);
  22258. for (i = 0; i < len; i++)
  22259. {
  22260. newbuf[keyboard_line->ptr]= word[i];
  22261. keyboard_line->ptr++;
  22262. keyboard_line->size++;
  22263. }
  22264. newbuf[keyboard_line->size] = '\0';
  22265. keyboard_line->buffer = newbuf;
  22266. return true;
  22267. }
  22268. /**
  22269. * input_keyboard_start_line:
  22270. * @userdata : Userdata.
  22271. * @cb : Line complete callback function.
  22272. *
  22273. * Sets function pointer for keyboard line handle.
  22274. *
  22275. * The underlying buffer can be reallocated at any time
  22276. * (or be NULL), but the pointer to it remains constant
  22277. * throughout the objects lifetime.
  22278. *
  22279. * Returns: underlying buffer of the keyboard line.
  22280. **/
  22281. static const char **input_keyboard_start_line(
  22282. void *userdata,
  22283. struct input_keyboard_line *keyboard_line,
  22284. input_keyboard_line_complete_t cb)
  22285. {
  22286. keyboard_line->buffer = NULL;
  22287. keyboard_line->ptr = 0;
  22288. keyboard_line->size = 0;
  22289. keyboard_line->cb = cb;
  22290. keyboard_line->userdata = userdata;
  22291. keyboard_line->enabled = true;
  22292. return (const char**)&keyboard_line->buffer;
  22293. }
  22294. #endif
  22295. /**
  22296. * input_keyboard_event:
  22297. * @down : Keycode was pressed down?
  22298. * @code : Keycode.
  22299. * @character : Character inputted.
  22300. * @mod : TODO/FIXME: ???
  22301. *
  22302. * Keyboard event utils. Called by drivers when keyboard events are fired.
  22303. * This interfaces with the global system driver struct and libretro callbacks.
  22304. **/
  22305. void input_keyboard_event(bool down, unsigned code,
  22306. uint32_t character, uint16_t mod, unsigned device)
  22307. {
  22308. static bool deferred_wait_keys;
  22309. struct rarch_state *p_rarch = &rarch_st;
  22310. #ifdef HAVE_ACCESSIBILITY
  22311. #ifdef HAVE_MENU
  22312. if (menu_input_dialog_get_display_kb()
  22313. && down && is_accessibility_enabled(p_rarch))
  22314. {
  22315. if (code != 303 && code != 0)
  22316. {
  22317. char* say_char = (char*)malloc(sizeof(char)+1);
  22318. if (say_char)
  22319. {
  22320. char c = (char) character;
  22321. *say_char = c;
  22322. if (character == 127)
  22323. accessibility_speak_priority(p_rarch, "backspace", 10);
  22324. else if (c == '`')
  22325. accessibility_speak_priority(p_rarch, "left quote", 10);
  22326. else if (c == '`')
  22327. accessibility_speak_priority(p_rarch, "tilde", 10);
  22328. else if (c == '!')
  22329. accessibility_speak_priority(p_rarch, "exclamation point", 10);
  22330. else if (c == '@')
  22331. accessibility_speak_priority(p_rarch, "at sign", 10);
  22332. else if (c == '#')
  22333. accessibility_speak_priority(p_rarch, "hash sign", 10);
  22334. else if (c == '$')
  22335. accessibility_speak_priority(p_rarch, "dollar sign", 10);
  22336. else if (c == '%')
  22337. accessibility_speak_priority(p_rarch, "percent sign", 10);
  22338. else if (c == '^')
  22339. accessibility_speak_priority(p_rarch, "carrot", 10);
  22340. else if (c == '&')
  22341. accessibility_speak_priority(p_rarch, "ampersand", 10);
  22342. else if (c == '*')
  22343. accessibility_speak_priority(p_rarch, "asterisk", 10);
  22344. else if (c == '(')
  22345. accessibility_speak_priority(p_rarch, "left bracket", 10);
  22346. else if (c == ')')
  22347. accessibility_speak_priority(p_rarch, "right bracket", 10);
  22348. else if (c == '-')
  22349. accessibility_speak_priority(p_rarch, "minus", 10);
  22350. else if (c == '_')
  22351. accessibility_speak_priority(p_rarch, "underscore", 10);
  22352. else if (c == '=')
  22353. accessibility_speak_priority(p_rarch, "equals", 10);
  22354. else if (c == '+')
  22355. accessibility_speak_priority(p_rarch, "plus", 10);
  22356. else if (c == '[')
  22357. accessibility_speak_priority(p_rarch, "left square bracket", 10);
  22358. else if (c == '{')
  22359. accessibility_speak_priority(p_rarch, "left curl bracket", 10);
  22360. else if (c == ']')
  22361. accessibility_speak_priority(p_rarch, "right square bracket", 10);
  22362. else if (c == '}')
  22363. accessibility_speak_priority(p_rarch, "right curl bracket", 10);
  22364. else if (c == '\\')
  22365. accessibility_speak_priority(p_rarch, "back slash", 10);
  22366. else if (c == '|')
  22367. accessibility_speak_priority(p_rarch, "pipe", 10);
  22368. else if (c == ';')
  22369. accessibility_speak_priority(p_rarch, "semicolon", 10);
  22370. else if (c == ':')
  22371. accessibility_speak_priority(p_rarch, "colon", 10);
  22372. else if (c == '\'')
  22373. accessibility_speak_priority(p_rarch, "single quote", 10);
  22374. else if (c == '\"')
  22375. accessibility_speak_priority(p_rarch, "double quote", 10);
  22376. else if (c == ',')
  22377. accessibility_speak_priority(p_rarch, "comma", 10);
  22378. else if (c == '<')
  22379. accessibility_speak_priority(p_rarch, "left angle bracket", 10);
  22380. else if (c == '.')
  22381. accessibility_speak_priority(p_rarch, "period", 10);
  22382. else if (c == '>')
  22383. accessibility_speak_priority(p_rarch, "right angle bracket", 10);
  22384. else if (c == '/')
  22385. accessibility_speak_priority(p_rarch, "front slash", 10);
  22386. else if (c == '?')
  22387. accessibility_speak_priority(p_rarch, "question mark", 10);
  22388. else if (c == ' ')
  22389. accessibility_speak_priority(p_rarch, "space", 10);
  22390. else if (character != 0)
  22391. accessibility_speak_priority(p_rarch, say_char, 10);
  22392. free(say_char);
  22393. }
  22394. }
  22395. }
  22396. #endif
  22397. #endif
  22398. if (deferred_wait_keys)
  22399. {
  22400. if (down)
  22401. return;
  22402. p_rarch->keyboard_press_cb = NULL;
  22403. p_rarch->keyboard_press_data = NULL;
  22404. p_rarch->keyboard_mapping_blocked = false;
  22405. deferred_wait_keys = false;
  22406. }
  22407. else if (p_rarch->keyboard_press_cb)
  22408. {
  22409. if (!down || code == RETROK_UNKNOWN)
  22410. return;
  22411. if (p_rarch->keyboard_press_cb(p_rarch->keyboard_press_data, code))
  22412. return;
  22413. deferred_wait_keys = true;
  22414. }
  22415. else if (p_rarch->keyboard_line.enabled)
  22416. {
  22417. if (!down)
  22418. return;
  22419. switch (device)
  22420. {
  22421. case RETRO_DEVICE_POINTER:
  22422. if (code != 0x12d)
  22423. character = (char)code;
  22424. /* fall-through */
  22425. default:
  22426. if (!input_keyboard_line_event(p_rarch,
  22427. &p_rarch->keyboard_line, character))
  22428. return;
  22429. break;
  22430. }
  22431. /* Line is complete, can free it now. */
  22432. if (p_rarch->keyboard_line.buffer)
  22433. free(p_rarch->keyboard_line.buffer);
  22434. p_rarch->keyboard_line.buffer = NULL;
  22435. p_rarch->keyboard_line.ptr = 0;
  22436. p_rarch->keyboard_line.size = 0;
  22437. p_rarch->keyboard_line.cb = NULL;
  22438. p_rarch->keyboard_line.userdata = NULL;
  22439. p_rarch->keyboard_line.enabled = false;
  22440. /* Unblock all hotkeys. */
  22441. p_rarch->keyboard_mapping_blocked = false;
  22442. }
  22443. else
  22444. {
  22445. if (code == RETROK_UNKNOWN)
  22446. return;
  22447. /* Block hotkey + RetroPad mapped keyboard key events,
  22448. * but not with game focus and from keyboard device type */
  22449. if (!p_rarch->game_focus_state.enabled)
  22450. {
  22451. input_mapper_t *handle = p_rarch->input_driver_mapper;
  22452. if (BIT512_GET(
  22453. p_rarch->keyboard_mapping_bits, code))
  22454. if (!(handle && MAPPER_GET_KEY(handle, code)))
  22455. return;
  22456. }
  22457. {
  22458. retro_keyboard_event_t *key_event = &p_rarch->runloop_key_event;
  22459. if (*key_event)
  22460. (*key_event)(down, code, character, mod);
  22461. }
  22462. }
  22463. }
  22464. static bool input_config_bind_map_get_valid(unsigned i)
  22465. {
  22466. const struct input_bind_map *keybind =
  22467. (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i);
  22468. if (!keybind)
  22469. return false;
  22470. return keybind->valid;
  22471. }
  22472. unsigned input_config_bind_map_get_meta(unsigned i)
  22473. {
  22474. const struct input_bind_map *keybind =
  22475. (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i);
  22476. if (!keybind)
  22477. return 0;
  22478. return keybind->meta;
  22479. }
  22480. const char *input_config_bind_map_get_base(unsigned i)
  22481. {
  22482. const struct input_bind_map *keybind =
  22483. (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i);
  22484. if (!keybind)
  22485. return NULL;
  22486. return keybind->base;
  22487. }
  22488. const char *input_config_bind_map_get_desc(unsigned i)
  22489. {
  22490. const struct input_bind_map *keybind =
  22491. (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i);
  22492. if (!keybind)
  22493. return NULL;
  22494. return msg_hash_to_str(keybind->desc);
  22495. }
  22496. uint8_t input_config_bind_map_get_retro_key(unsigned i)
  22497. {
  22498. const struct input_bind_map *keybind =
  22499. (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i);
  22500. if (!keybind)
  22501. return 0;
  22502. return keybind->retro_key;
  22503. }
  22504. static void input_config_parse_key(
  22505. config_file_t *conf,
  22506. const char *prefix, const char *btn,
  22507. struct retro_keybind *bind)
  22508. {
  22509. char key[64];
  22510. struct config_entry_list *entry = NULL;
  22511. key[0] = '\0';
  22512. fill_pathname_join_delim(key, prefix, btn, '_', sizeof(key));
  22513. if (
  22514. (entry = config_get_entry(conf, key))
  22515. && (!string_is_empty(entry->value))
  22516. )
  22517. bind->key = input_config_translate_str_to_rk(entry->value);
  22518. /* Store mapping bit */
  22519. input_keyboard_mapping_bits(1, bind->key);
  22520. }
  22521. static const char *input_config_get_prefix(unsigned user, bool meta)
  22522. {
  22523. static const char *bind_user_prefix[MAX_USERS] = {
  22524. "input_player1",
  22525. "input_player2",
  22526. "input_player3",
  22527. "input_player4",
  22528. "input_player5",
  22529. "input_player6",
  22530. "input_player7",
  22531. "input_player8",
  22532. "input_player9",
  22533. "input_player10",
  22534. "input_player11",
  22535. "input_player12",
  22536. "input_player13",
  22537. "input_player14",
  22538. "input_player15",
  22539. "input_player16",
  22540. };
  22541. const char *prefix = bind_user_prefix[user];
  22542. if (user == 0)
  22543. return meta ? "input" : prefix;
  22544. if (!meta)
  22545. return prefix;
  22546. /* Don't bother with meta bind for anyone else than first user. */
  22547. return NULL;
  22548. }
  22549. /**
  22550. * input_config_translate_str_to_rk:
  22551. * @str : String to translate to key ID.
  22552. *
  22553. * Translates tring representation to key identifier.
  22554. *
  22555. * Returns: key identifier.
  22556. **/
  22557. enum retro_key input_config_translate_str_to_rk(const char *str)
  22558. {
  22559. size_t i;
  22560. if (strlen(str) == 1 && ISALPHA((int)*str))
  22561. return (enum retro_key)(RETROK_a + (TOLOWER((int)*str) - (int)'a'));
  22562. for (i = 0; input_config_key_map[i].str; i++)
  22563. {
  22564. if (string_is_equal_noncase(input_config_key_map[i].str, str))
  22565. return input_config_key_map[i].key;
  22566. }
  22567. RARCH_WARN("[Input]: Key name \"%s\" not found.\n", str);
  22568. return RETROK_UNKNOWN;
  22569. }
  22570. /**
  22571. * input_config_translate_str_to_bind_id:
  22572. * @str : String to translate to bind ID.
  22573. *
  22574. * Translate string representation to bind ID.
  22575. *
  22576. * Returns: Bind ID value on success, otherwise
  22577. * RARCH_BIND_LIST_END on not found.
  22578. **/
  22579. unsigned input_config_translate_str_to_bind_id(const char *str)
  22580. {
  22581. unsigned i;
  22582. for (i = 0; input_config_bind_map[i].valid; i++)
  22583. if (string_is_equal(str, input_config_bind_map[i].base))
  22584. return i;
  22585. return RARCH_BIND_LIST_END;
  22586. }
  22587. static void parse_hat(struct retro_keybind *bind, const char *str)
  22588. {
  22589. uint16_t hat_dir = 0;
  22590. char *dir = NULL;
  22591. uint16_t hat = strtoul(str, &dir, 0);
  22592. if (!dir)
  22593. {
  22594. RARCH_WARN("[Input]: Found invalid hat in config!\n");
  22595. return;
  22596. }
  22597. if ( dir[0] == 'u'
  22598. && dir[1] == 'p'
  22599. && dir[2] == '\0'
  22600. )
  22601. hat_dir = HAT_UP_MASK;
  22602. else if ( dir[0] == 'd'
  22603. && dir[1] == 'o'
  22604. && dir[2] == 'w'
  22605. && dir[3] == 'n'
  22606. && dir[4] == '\0'
  22607. )
  22608. hat_dir = HAT_DOWN_MASK;
  22609. else if ( dir[0] == 'l'
  22610. && dir[1] == 'e'
  22611. && dir[2] == 'f'
  22612. && dir[3] == 't'
  22613. && dir[4] == '\0'
  22614. )
  22615. hat_dir = HAT_LEFT_MASK;
  22616. else if ( dir[0] == 'r'
  22617. && dir[1] == 'i'
  22618. && dir[2] == 'g'
  22619. && dir[3] == 'h'
  22620. && dir[4] == 't'
  22621. && dir[5] == '\0'
  22622. )
  22623. hat_dir = HAT_RIGHT_MASK;
  22624. if (hat_dir)
  22625. bind->joykey = HAT_MAP(hat, hat_dir);
  22626. }
  22627. static void input_config_parse_joy_button(
  22628. config_file_t *conf, const char *prefix,
  22629. const char *btn, struct retro_keybind *bind)
  22630. {
  22631. char str[256];
  22632. char tmp[64];
  22633. char key[64];
  22634. char key_label[64];
  22635. struct config_entry_list *tmp_a = NULL;
  22636. str[0] = tmp[0] = key[0] = key_label[0] = '\0';
  22637. fill_pathname_join_delim(str, prefix, btn,
  22638. '_', sizeof(str));
  22639. fill_pathname_join_delim(key, str,
  22640. "btn", '_', sizeof(key));
  22641. fill_pathname_join_delim(key_label, str,
  22642. "btn_label", '_', sizeof(key_label));
  22643. if (config_get_array(conf, key, tmp, sizeof(tmp)))
  22644. {
  22645. btn = tmp;
  22646. if ( btn[0] == 'n'
  22647. && btn[1] == 'u'
  22648. && btn[2] == 'l'
  22649. && btn[3] == '\0'
  22650. )
  22651. bind->joykey = NO_BTN;
  22652. else
  22653. {
  22654. if (*btn == 'h')
  22655. {
  22656. const char *str = btn + 1;
  22657. if (str && ISDIGIT((int)*str))
  22658. parse_hat(bind, str);
  22659. }
  22660. else
  22661. bind->joykey = strtoull(tmp, NULL, 0);
  22662. }
  22663. }
  22664. tmp_a = config_get_entry(conf, key_label);
  22665. if (tmp_a && !string_is_empty(tmp_a->value))
  22666. {
  22667. if (!string_is_empty(bind->joykey_label))
  22668. free(bind->joykey_label);
  22669. bind->joykey_label = strdup(tmp_a->value);
  22670. }
  22671. }
  22672. static void input_config_parse_joy_axis(
  22673. config_file_t *conf, const char *prefix,
  22674. const char *axis, struct retro_keybind *bind)
  22675. {
  22676. char str[256];
  22677. char tmp[64];
  22678. char key[64];
  22679. char key_label[64];
  22680. struct config_entry_list *tmp_a = NULL;
  22681. str[0] = tmp[0] = key[0] = key_label[0] = '\0';
  22682. fill_pathname_join_delim(str, prefix, axis,
  22683. '_', sizeof(str));
  22684. fill_pathname_join_delim(key, str,
  22685. "axis", '_', sizeof(key));
  22686. fill_pathname_join_delim(key_label, str,
  22687. "axis_label", '_', sizeof(key_label));
  22688. if (config_get_array(conf, key, tmp, sizeof(tmp)))
  22689. {
  22690. if ( tmp[0] == 'n'
  22691. && tmp[1] == 'u'
  22692. && tmp[2] == 'l'
  22693. && tmp[3] == '\0'
  22694. )
  22695. bind->joyaxis = AXIS_NONE;
  22696. else if (strlen(tmp) >= 2 && (*tmp == '+' || *tmp == '-'))
  22697. {
  22698. int i_axis = (int)strtol(tmp + 1, NULL, 0);
  22699. if (*tmp == '+')
  22700. bind->joyaxis = AXIS_POS(i_axis);
  22701. else
  22702. bind->joyaxis = AXIS_NEG(i_axis);
  22703. }
  22704. /* Ensure that D-pad emulation doesn't screw this over. */
  22705. bind->orig_joyaxis = bind->joyaxis;
  22706. }
  22707. tmp_a = config_get_entry(conf, key_label);
  22708. if (tmp_a && (!string_is_empty(tmp_a->value)))
  22709. {
  22710. if (bind->joyaxis_label &&
  22711. !string_is_empty(bind->joyaxis_label))
  22712. free(bind->joyaxis_label);
  22713. bind->joyaxis_label = strdup(tmp_a->value);
  22714. }
  22715. }
  22716. static void input_config_parse_mouse_button(
  22717. config_file_t *conf, const char *prefix,
  22718. const char *btn, struct retro_keybind *bind)
  22719. {
  22720. int val;
  22721. char str[256];
  22722. char tmp[64];
  22723. char key[64];
  22724. str[0] = tmp[0] = key[0] = '\0';
  22725. fill_pathname_join_delim(str, prefix, btn,
  22726. '_', sizeof(str));
  22727. fill_pathname_join_delim(key, str,
  22728. "mbtn", '_', sizeof(key));
  22729. if (config_get_array(conf, key, tmp, sizeof(tmp)))
  22730. {
  22731. bind->mbutton = NO_BTN;
  22732. if (tmp[0]=='w')
  22733. {
  22734. switch (tmp[1])
  22735. {
  22736. case 'u':
  22737. bind->mbutton = RETRO_DEVICE_ID_MOUSE_WHEELUP;
  22738. break;
  22739. case 'd':
  22740. bind->mbutton = RETRO_DEVICE_ID_MOUSE_WHEELDOWN;
  22741. break;
  22742. case 'h':
  22743. switch (tmp[2])
  22744. {
  22745. case 'u':
  22746. bind->mbutton = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP;
  22747. break;
  22748. case 'd':
  22749. bind->mbutton = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN;
  22750. break;
  22751. }
  22752. break;
  22753. }
  22754. }
  22755. else
  22756. {
  22757. val = atoi(tmp);
  22758. switch (val)
  22759. {
  22760. case 1:
  22761. bind->mbutton = RETRO_DEVICE_ID_MOUSE_LEFT;
  22762. break;
  22763. case 2:
  22764. bind->mbutton = RETRO_DEVICE_ID_MOUSE_RIGHT;
  22765. break;
  22766. case 3:
  22767. bind->mbutton = RETRO_DEVICE_ID_MOUSE_MIDDLE;
  22768. break;
  22769. case 4:
  22770. bind->mbutton = RETRO_DEVICE_ID_MOUSE_BUTTON_4;
  22771. break;
  22772. case 5:
  22773. bind->mbutton = RETRO_DEVICE_ID_MOUSE_BUTTON_5;
  22774. break;
  22775. }
  22776. }
  22777. }
  22778. }
  22779. static void input_config_get_bind_string_joykey(
  22780. settings_t *settings,
  22781. char *buf, const char *prefix,
  22782. const struct retro_keybind *bind, size_t size)
  22783. {
  22784. bool label_show =
  22785. settings->bools.input_descriptor_label_show;
  22786. if (GET_HAT_DIR(bind->joykey))
  22787. {
  22788. if (bind->joykey_label &&
  22789. !string_is_empty(bind->joykey_label) && label_show)
  22790. fill_pathname_join_delim_concat(buf, prefix,
  22791. bind->joykey_label, ' ', " (hat)", size);
  22792. else
  22793. {
  22794. const char *dir = "?";
  22795. switch (GET_HAT_DIR(bind->joykey))
  22796. {
  22797. case HAT_UP_MASK:
  22798. dir = "up";
  22799. break;
  22800. case HAT_DOWN_MASK:
  22801. dir = "down";
  22802. break;
  22803. case HAT_LEFT_MASK:
  22804. dir = "left";
  22805. break;
  22806. case HAT_RIGHT_MASK:
  22807. dir = "right";
  22808. break;
  22809. default:
  22810. break;
  22811. }
  22812. snprintf(buf, size, "%sHat #%u %s (%s)", prefix,
  22813. (unsigned)GET_HAT(bind->joykey), dir,
  22814. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
  22815. }
  22816. }
  22817. else
  22818. {
  22819. if (bind->joykey_label &&
  22820. !string_is_empty(bind->joykey_label) && label_show)
  22821. fill_pathname_join_delim_concat(buf, prefix,
  22822. bind->joykey_label, ' ', " (btn)", size);
  22823. else
  22824. snprintf(buf, size, "%s%u (%s)", prefix, (unsigned)bind->joykey,
  22825. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
  22826. }
  22827. }
  22828. static void input_config_get_bind_string_joyaxis(
  22829. settings_t *settings,
  22830. char *buf, const char *prefix,
  22831. const struct retro_keybind *bind, size_t size)
  22832. {
  22833. bool input_descriptor_label_show =
  22834. settings->bools.input_descriptor_label_show;
  22835. if (bind->joyaxis_label &&
  22836. !string_is_empty(bind->joyaxis_label)
  22837. && input_descriptor_label_show)
  22838. fill_pathname_join_delim_concat(buf, prefix,
  22839. bind->joyaxis_label, ' ', " (axis)", size);
  22840. else
  22841. {
  22842. unsigned axis = 0;
  22843. char dir = '\0';
  22844. if (AXIS_NEG_GET(bind->joyaxis) != AXIS_DIR_NONE)
  22845. {
  22846. dir = '-';
  22847. axis = AXIS_NEG_GET(bind->joyaxis);
  22848. }
  22849. else if (AXIS_POS_GET(bind->joyaxis) != AXIS_DIR_NONE)
  22850. {
  22851. dir = '+';
  22852. axis = AXIS_POS_GET(bind->joyaxis);
  22853. }
  22854. snprintf(buf, size, "%s%c%u (%s)", prefix, dir, axis,
  22855. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
  22856. }
  22857. }
  22858. void input_config_get_bind_string(char *buf,
  22859. const struct retro_keybind *bind,
  22860. const struct retro_keybind *auto_bind,
  22861. size_t size)
  22862. {
  22863. int delim = 0;
  22864. struct rarch_state *p_rarch = &rarch_st;
  22865. *buf = '\0';
  22866. if (bind && bind->joykey != NO_BTN)
  22867. input_config_get_bind_string_joykey(
  22868. p_rarch->configuration_settings, buf, "", bind, size);
  22869. else if (bind && bind->joyaxis != AXIS_NONE)
  22870. input_config_get_bind_string_joyaxis(
  22871. p_rarch->configuration_settings, buf, "", bind, size);
  22872. else if (auto_bind && auto_bind->joykey != NO_BTN)
  22873. input_config_get_bind_string_joykey(
  22874. p_rarch->configuration_settings, buf, "Auto: ", auto_bind, size);
  22875. else if (auto_bind && auto_bind->joyaxis != AXIS_NONE)
  22876. input_config_get_bind_string_joyaxis(
  22877. p_rarch->configuration_settings, buf, "Auto: ", auto_bind, size);
  22878. if (*buf)
  22879. delim = 1;
  22880. #ifndef RARCH_CONSOLE
  22881. {
  22882. char key[64];
  22883. key[0] = '\0';
  22884. input_keymaps_translate_rk_to_str(bind->key, key, sizeof(key));
  22885. if ( key[0] == 'n'
  22886. && key[1] == 'u'
  22887. && key[2] == 'l'
  22888. && key[3] == '\0'
  22889. )
  22890. *key = '\0';
  22891. /*empty?*/
  22892. if (*key != '\0')
  22893. {
  22894. char keybuf[64];
  22895. keybuf[0] = '\0';
  22896. if (delim)
  22897. strlcat(buf, ", ", size);
  22898. snprintf(keybuf, sizeof(keybuf),
  22899. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_KEY), key);
  22900. strlcat(buf, keybuf, size);
  22901. delim = 1;
  22902. }
  22903. }
  22904. #endif
  22905. if (bind->mbutton != NO_BTN)
  22906. {
  22907. int tag = 0;
  22908. switch (bind->mbutton)
  22909. {
  22910. case RETRO_DEVICE_ID_MOUSE_LEFT:
  22911. tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_LEFT;
  22912. break;
  22913. case RETRO_DEVICE_ID_MOUSE_RIGHT:
  22914. tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_RIGHT;
  22915. break;
  22916. case RETRO_DEVICE_ID_MOUSE_MIDDLE:
  22917. tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_MIDDLE;
  22918. break;
  22919. case RETRO_DEVICE_ID_MOUSE_BUTTON_4:
  22920. tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON4;
  22921. break;
  22922. case RETRO_DEVICE_ID_MOUSE_BUTTON_5:
  22923. tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON5;
  22924. break;
  22925. case RETRO_DEVICE_ID_MOUSE_WHEELUP:
  22926. tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_UP;
  22927. break;
  22928. case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
  22929. tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_DOWN;
  22930. break;
  22931. case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
  22932. tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_UP;
  22933. break;
  22934. case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
  22935. tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_DOWN;
  22936. break;
  22937. }
  22938. if (tag != 0)
  22939. {
  22940. if (delim)
  22941. strlcat(buf, ", ", size);
  22942. strlcat(buf, msg_hash_to_str((enum msg_hash_enums)tag), size);
  22943. }
  22944. }
  22945. /*completely empty?*/
  22946. if (*buf == '\0')
  22947. strlcat(buf, "---", size);
  22948. }
  22949. /* input_device_info wrappers START */
  22950. unsigned input_config_get_device_count(void)
  22951. {
  22952. struct rarch_state *p_rarch = &rarch_st;
  22953. unsigned num_devices;
  22954. for (num_devices = 0; num_devices < MAX_INPUT_DEVICES; ++num_devices)
  22955. {
  22956. if (string_is_empty(p_rarch->input_device_info[num_devices].name))
  22957. break;
  22958. }
  22959. return num_devices;
  22960. }
  22961. /* Adds an index to devices with the same name,
  22962. * so they can be uniquely identified in the
  22963. * frontend */
  22964. static void input_config_reindex_device_names(void)
  22965. {
  22966. unsigned i;
  22967. unsigned j;
  22968. unsigned name_index;
  22969. /* Reset device name indices */
  22970. for (i = 0; i < MAX_INPUT_DEVICES; i++)
  22971. input_config_set_device_name_index(i, 0);
  22972. /* Scan device names */
  22973. for (i = 0; i < MAX_INPUT_DEVICES; i++)
  22974. {
  22975. const char *device_name = input_config_get_device_name(i);
  22976. /* If current device name is empty, or a non-zero
  22977. * name index has already been assigned, continue
  22978. * to the next device */
  22979. if (string_is_empty(device_name) ||
  22980. (input_config_get_device_name_index(i) != 0))
  22981. continue;
  22982. /* > Uniquely named devices have a name index
  22983. * of 0
  22984. * > Devices with the same name have a name
  22985. * index starting from 1 */
  22986. name_index = 1;
  22987. /* Loop over all devices following the current
  22988. * selection */
  22989. for (j = i + 1; j < MAX_INPUT_DEVICES; j++)
  22990. {
  22991. const char *next_device_name = input_config_get_device_name(j);
  22992. if (string_is_empty(next_device_name))
  22993. continue;
  22994. /* Check if names match */
  22995. if (string_is_equal(device_name, next_device_name))
  22996. {
  22997. /* If this is the first match, set a starting
  22998. * index for the current device selection */
  22999. if (input_config_get_device_name_index(i) == 0)
  23000. input_config_set_device_name_index(i, name_index++);
  23001. /* Set name index for the next device
  23002. * (will keep incrementing as more matches
  23003. * are found) */
  23004. input_config_set_device_name_index(j, name_index++);
  23005. }
  23006. }
  23007. }
  23008. }
  23009. /* > Get input_device_info */
  23010. const char *input_config_get_device_name(unsigned port)
  23011. {
  23012. struct rarch_state *p_rarch = &rarch_st;
  23013. if (string_is_empty(p_rarch->input_device_info[port].name))
  23014. return NULL;
  23015. return p_rarch->input_device_info[port].name;
  23016. }
  23017. const char *input_config_get_device_display_name(unsigned port)
  23018. {
  23019. struct rarch_state *p_rarch = &rarch_st;
  23020. if (string_is_empty(p_rarch->input_device_info[port].display_name))
  23021. return NULL;
  23022. return p_rarch->input_device_info[port].display_name;
  23023. }
  23024. const char *input_config_get_device_config_path(unsigned port)
  23025. {
  23026. struct rarch_state *p_rarch = &rarch_st;
  23027. if (string_is_empty(p_rarch->input_device_info[port].config_path))
  23028. return NULL;
  23029. return p_rarch->input_device_info[port].config_path;
  23030. }
  23031. const char *input_config_get_device_config_name(unsigned port)
  23032. {
  23033. struct rarch_state *p_rarch = &rarch_st;
  23034. if (string_is_empty(p_rarch->input_device_info[port].config_name))
  23035. return NULL;
  23036. return p_rarch->input_device_info[port].config_name;
  23037. }
  23038. const char *input_config_get_device_joypad_driver(unsigned port)
  23039. {
  23040. struct rarch_state *p_rarch = &rarch_st;
  23041. if (string_is_empty(p_rarch->input_device_info[port].joypad_driver))
  23042. return NULL;
  23043. return p_rarch->input_device_info[port].joypad_driver;
  23044. }
  23045. uint16_t input_config_get_device_vid(unsigned port)
  23046. {
  23047. struct rarch_state *p_rarch = &rarch_st;
  23048. return p_rarch->input_device_info[port].vid;
  23049. }
  23050. uint16_t input_config_get_device_pid(unsigned port)
  23051. {
  23052. struct rarch_state *p_rarch = &rarch_st;
  23053. return p_rarch->input_device_info[port].pid;
  23054. }
  23055. bool input_config_get_device_autoconfigured(unsigned port)
  23056. {
  23057. struct rarch_state *p_rarch = &rarch_st;
  23058. return p_rarch->input_device_info[port].autoconfigured;
  23059. }
  23060. unsigned input_config_get_device_name_index(unsigned port)
  23061. {
  23062. struct rarch_state *p_rarch = &rarch_st;
  23063. return p_rarch->input_device_info[port].name_index;
  23064. }
  23065. /* TODO/FIXME: This is required by linuxraw_joypad.c
  23066. * and parport_joypad.c. These input drivers should
  23067. * be refactored such that this dubious low-level
  23068. * access is not required */
  23069. char *input_config_get_device_name_ptr(unsigned port)
  23070. {
  23071. struct rarch_state *p_rarch = &rarch_st;
  23072. return p_rarch->input_device_info[port].name;
  23073. }
  23074. size_t input_config_get_device_name_size(unsigned port)
  23075. {
  23076. struct rarch_state *p_rarch = &rarch_st;
  23077. return sizeof(p_rarch->input_device_info[port].name);
  23078. }
  23079. /* > Set input_device_info */
  23080. void input_config_set_device_name(unsigned port, const char *name)
  23081. {
  23082. struct rarch_state *p_rarch = &rarch_st;
  23083. if (string_is_empty(name))
  23084. return;
  23085. strlcpy(p_rarch->input_device_info[port].name, name,
  23086. sizeof(p_rarch->input_device_info[port].name));
  23087. input_config_reindex_device_names();
  23088. }
  23089. void input_config_set_device_display_name(unsigned port, const char *name)
  23090. {
  23091. struct rarch_state *p_rarch = &rarch_st;
  23092. if (!string_is_empty(name))
  23093. strlcpy(p_rarch->input_device_info[port].display_name, name,
  23094. sizeof(p_rarch->input_device_info[port].display_name));
  23095. }
  23096. void input_config_set_device_config_path(unsigned port, const char *path)
  23097. {
  23098. if (!string_is_empty(path))
  23099. {
  23100. char parent_dir_name[128];
  23101. struct rarch_state *p_rarch = &rarch_st;
  23102. parent_dir_name[0] = '\0';
  23103. if (fill_pathname_parent_dir_name(parent_dir_name,
  23104. path, sizeof(parent_dir_name)))
  23105. fill_pathname_join(p_rarch->input_device_info[port].config_path,
  23106. parent_dir_name, path_basename(path),
  23107. sizeof(p_rarch->input_device_info[port].config_path));
  23108. }
  23109. }
  23110. void input_config_set_device_config_name(unsigned port, const char *name)
  23111. {
  23112. struct rarch_state *p_rarch = &rarch_st;
  23113. if (!string_is_empty(name))
  23114. strlcpy(p_rarch->input_device_info[port].config_name, name,
  23115. sizeof(p_rarch->input_device_info[port].config_name));
  23116. }
  23117. void input_config_set_device_joypad_driver(unsigned port, const char *driver)
  23118. {
  23119. struct rarch_state *p_rarch = &rarch_st;
  23120. if (!string_is_empty(driver))
  23121. strlcpy(p_rarch->input_device_info[port].joypad_driver, driver,
  23122. sizeof(p_rarch->input_device_info[port].joypad_driver));
  23123. }
  23124. void input_config_set_device_vid(unsigned port, uint16_t vid)
  23125. {
  23126. struct rarch_state *p_rarch = &rarch_st;
  23127. p_rarch->input_device_info[port].vid = vid;
  23128. }
  23129. void input_config_set_device_pid(unsigned port, uint16_t pid)
  23130. {
  23131. struct rarch_state *p_rarch = &rarch_st;
  23132. p_rarch->input_device_info[port].pid = pid;
  23133. }
  23134. void input_config_set_device_autoconfigured(unsigned port, bool autoconfigured)
  23135. {
  23136. struct rarch_state *p_rarch = &rarch_st;
  23137. p_rarch->input_device_info[port].autoconfigured = autoconfigured;
  23138. }
  23139. void input_config_set_device_name_index(unsigned port, unsigned name_index)
  23140. {
  23141. struct rarch_state *p_rarch = &rarch_st;
  23142. p_rarch->input_device_info[port].name_index = name_index;
  23143. }
  23144. /* > Clear input_device_info */
  23145. void input_config_clear_device_name(unsigned port)
  23146. {
  23147. struct rarch_state *p_rarch = &rarch_st;
  23148. p_rarch->input_device_info[port].name[0] = '\0';
  23149. input_config_reindex_device_names();
  23150. }
  23151. void input_config_clear_device_display_name(unsigned port)
  23152. {
  23153. struct rarch_state *p_rarch = &rarch_st;
  23154. p_rarch->input_device_info[port].display_name[0] = '\0';
  23155. }
  23156. void input_config_clear_device_config_path(unsigned port)
  23157. {
  23158. struct rarch_state *p_rarch = &rarch_st;
  23159. p_rarch->input_device_info[port].config_path[0] = '\0';
  23160. }
  23161. void input_config_clear_device_config_name(unsigned port)
  23162. {
  23163. struct rarch_state *p_rarch = &rarch_st;
  23164. p_rarch->input_device_info[port].config_name[0] = '\0';
  23165. }
  23166. void input_config_clear_device_joypad_driver(unsigned port)
  23167. {
  23168. struct rarch_state *p_rarch = &rarch_st;
  23169. p_rarch->input_device_info[port].joypad_driver[0] = '\0';
  23170. }
  23171. /* input_device_info wrappers END */
  23172. unsigned *input_config_get_device_ptr(unsigned port)
  23173. {
  23174. struct rarch_state *p_rarch = &rarch_st;
  23175. settings_t *settings = p_rarch->configuration_settings;
  23176. return &settings->uints.input_libretro_device[port];
  23177. }
  23178. unsigned input_config_get_device(unsigned port)
  23179. {
  23180. struct rarch_state *p_rarch = &rarch_st;
  23181. settings_t *settings = p_rarch->configuration_settings;
  23182. return settings->uints.input_libretro_device[port];
  23183. }
  23184. void input_config_set_device(unsigned port, unsigned id)
  23185. {
  23186. struct rarch_state *p_rarch = &rarch_st;
  23187. settings_t *settings = p_rarch->configuration_settings;
  23188. if (settings)
  23189. configuration_set_uint(settings,
  23190. settings->uints.input_libretro_device[port], id);
  23191. }
  23192. const struct retro_keybind *input_config_get_bind_auto(
  23193. unsigned port, unsigned id)
  23194. {
  23195. struct rarch_state *p_rarch = &rarch_st;
  23196. settings_t *settings = p_rarch->configuration_settings;
  23197. unsigned joy_idx = settings->uints.input_joypad_map[port];
  23198. if (joy_idx < MAX_USERS)
  23199. return &input_autoconf_binds[joy_idx][id];
  23200. return NULL;
  23201. }
  23202. void input_config_reset_autoconfig_binds(unsigned port)
  23203. {
  23204. unsigned i;
  23205. if (port >= MAX_USERS)
  23206. return;
  23207. for (i = 0; i < RARCH_BIND_LIST_END; i++)
  23208. {
  23209. input_autoconf_binds[port][i].joykey = NO_BTN;
  23210. input_autoconf_binds[port][i].joyaxis = AXIS_NONE;
  23211. if (input_autoconf_binds[port][i].joykey_label)
  23212. {
  23213. free(input_autoconf_binds[port][i].joykey_label);
  23214. input_autoconf_binds[port][i].joykey_label = NULL;
  23215. }
  23216. if (input_autoconf_binds[port][i].joyaxis_label)
  23217. {
  23218. free(input_autoconf_binds[port][i].joyaxis_label);
  23219. input_autoconf_binds[port][i].joyaxis_label = NULL;
  23220. }
  23221. }
  23222. }
  23223. void input_config_reset(void)
  23224. {
  23225. unsigned i;
  23226. struct rarch_state *p_rarch = &rarch_st;
  23227. retro_assert(sizeof(input_config_binds[0]) >= sizeof(retro_keybinds_1));
  23228. retro_assert(sizeof(input_config_binds[1]) >= sizeof(retro_keybinds_rest));
  23229. memcpy(input_config_binds[0], retro_keybinds_1, sizeof(retro_keybinds_1));
  23230. for (i = 1; i < MAX_USERS; i++)
  23231. memcpy(input_config_binds[i], retro_keybinds_rest,
  23232. sizeof(retro_keybinds_rest));
  23233. for (i = 0; i < MAX_USERS; i++)
  23234. {
  23235. /* Note: Don't use input_config_clear_device_name()
  23236. * here, since this will re-index devices each time
  23237. * (not required - we are setting all 'name indices'
  23238. * to zero manually) */
  23239. p_rarch->input_device_info[i].name[0] = '\0';
  23240. input_config_clear_device_display_name(i);
  23241. input_config_clear_device_config_path(i);
  23242. input_config_clear_device_config_name(i);
  23243. input_config_clear_device_joypad_driver(i);
  23244. input_config_set_device_vid(i, 0);
  23245. input_config_set_device_pid(i, 0);
  23246. input_config_set_device_autoconfigured(i, false);
  23247. input_config_set_device_name_index(i, 0);
  23248. input_config_reset_autoconfig_binds(i);
  23249. p_rarch->libretro_input_binds[i] = input_config_binds[i];
  23250. }
  23251. }
  23252. void config_read_keybinds_conf(void *data)
  23253. {
  23254. unsigned i;
  23255. config_file_t *conf = (config_file_t*)data;
  23256. if (!conf)
  23257. return;
  23258. for (i = 0; i < MAX_USERS; i++)
  23259. {
  23260. unsigned j;
  23261. for (j = 0; input_config_bind_map_get_valid(j); j++)
  23262. {
  23263. struct retro_keybind *bind = &input_config_binds[i][j];
  23264. const char *prefix = input_config_get_prefix(i, input_config_bind_map_get_meta(j));
  23265. const char *btn = input_config_bind_map_get_base(j);
  23266. if (!bind || !bind->valid)
  23267. continue;
  23268. if (!input_config_bind_map_get_valid(j))
  23269. continue;
  23270. if (!btn || !prefix)
  23271. continue;
  23272. input_config_parse_key(conf, prefix, btn, bind);
  23273. input_config_parse_joy_button(conf, prefix, btn, bind);
  23274. input_config_parse_joy_axis(conf, prefix, btn, bind);
  23275. input_config_parse_mouse_button(conf, prefix, btn, bind);
  23276. }
  23277. }
  23278. }
  23279. void input_config_set_autoconfig_binds(unsigned port, void *data)
  23280. {
  23281. config_file_t *config = (config_file_t*)data;
  23282. struct retro_keybind *binds = NULL;
  23283. unsigned i;
  23284. if ((port >= MAX_USERS) || !config)
  23285. return;
  23286. binds = input_autoconf_binds[port];
  23287. for (i = 0; i < RARCH_BIND_LIST_END; i++)
  23288. {
  23289. input_config_parse_joy_button(config, "input",
  23290. input_config_bind_map_get_base(i), &binds[i]);
  23291. input_config_parse_joy_axis (config, "input",
  23292. input_config_bind_map_get_base(i), &binds[i]);
  23293. }
  23294. }
  23295. /**
  23296. * input_config_save_keybinds_user:
  23297. * @conf : pointer to config file object
  23298. * @user : user number
  23299. *
  23300. * Save the current keybinds of a user (@user) to the config file (@conf).
  23301. */
  23302. void input_config_save_keybinds_user(void *data, unsigned user)
  23303. {
  23304. unsigned i = 0;
  23305. config_file_t *conf = (config_file_t*)data;
  23306. for (i = 0; input_config_bind_map_get_valid(i); i++)
  23307. {
  23308. char key[64];
  23309. char btn[64];
  23310. const char *prefix = input_config_get_prefix(user,
  23311. input_config_bind_map_get_meta(i));
  23312. const struct retro_keybind *bind = &input_config_binds[user][i];
  23313. const char *base = input_config_bind_map_get_base(i);
  23314. if (!prefix || !bind->valid)
  23315. continue;
  23316. key[0] = btn[0] = '\0';
  23317. fill_pathname_join_delim(key, prefix, base, '_', sizeof(key));
  23318. input_keymaps_translate_rk_to_str(bind->key, btn, sizeof(btn));
  23319. config_set_string(conf, key, btn);
  23320. input_config_save_keybind(conf, prefix, base, bind, true);
  23321. }
  23322. }
  23323. static void save_keybind_hat(config_file_t *conf, const char *key,
  23324. const struct retro_keybind *bind)
  23325. {
  23326. char config[16];
  23327. unsigned hat = (unsigned)GET_HAT(bind->joykey);
  23328. const char *dir = NULL;
  23329. config[0] = '\0';
  23330. switch (GET_HAT_DIR(bind->joykey))
  23331. {
  23332. case HAT_UP_MASK:
  23333. dir = "up";
  23334. break;
  23335. case HAT_DOWN_MASK:
  23336. dir = "down";
  23337. break;
  23338. case HAT_LEFT_MASK:
  23339. dir = "left";
  23340. break;
  23341. case HAT_RIGHT_MASK:
  23342. dir = "right";
  23343. break;
  23344. default:
  23345. break;
  23346. }
  23347. snprintf(config, sizeof(config), "h%u%s", hat, dir);
  23348. config_set_string(conf, key, config);
  23349. }
  23350. static void save_keybind_joykey(config_file_t *conf,
  23351. const char *prefix,
  23352. const char *base,
  23353. const struct retro_keybind *bind, bool save_empty)
  23354. {
  23355. char key[64];
  23356. key[0] = '\0';
  23357. fill_pathname_join_delim_concat(key, prefix,
  23358. base, '_', "_btn", sizeof(key));
  23359. if (bind->joykey == NO_BTN)
  23360. {
  23361. if (save_empty)
  23362. config_set_string(conf, key, "nul");
  23363. }
  23364. else if (GET_HAT_DIR(bind->joykey))
  23365. save_keybind_hat(conf, key, bind);
  23366. else
  23367. config_set_uint64(conf, key, bind->joykey);
  23368. }
  23369. static void save_keybind_axis(config_file_t *conf,
  23370. const char *prefix,
  23371. const char *base,
  23372. const struct retro_keybind *bind, bool save_empty)
  23373. {
  23374. char key[64];
  23375. unsigned axis = 0;
  23376. char dir = '\0';
  23377. key[0] = '\0';
  23378. fill_pathname_join_delim_concat(key,
  23379. prefix, base, '_',
  23380. "_axis",
  23381. sizeof(key));
  23382. if (bind->joyaxis == AXIS_NONE)
  23383. {
  23384. if (save_empty)
  23385. config_set_string(conf, key, "nul");
  23386. }
  23387. else if (AXIS_NEG_GET(bind->joyaxis) != AXIS_DIR_NONE)
  23388. {
  23389. dir = '-';
  23390. axis = AXIS_NEG_GET(bind->joyaxis);
  23391. }
  23392. else if (AXIS_POS_GET(bind->joyaxis) != AXIS_DIR_NONE)
  23393. {
  23394. dir = '+';
  23395. axis = AXIS_POS_GET(bind->joyaxis);
  23396. }
  23397. if (dir)
  23398. {
  23399. char config[16];
  23400. config[0] = '\0';
  23401. snprintf(config, sizeof(config), "%c%u", dir, axis);
  23402. config_set_string(conf, key, config);
  23403. }
  23404. }
  23405. static void save_keybind_mbutton(config_file_t *conf,
  23406. const char *prefix,
  23407. const char *base,
  23408. const struct retro_keybind *bind, bool save_empty)
  23409. {
  23410. char key[64];
  23411. key[0] = '\0';
  23412. fill_pathname_join_delim_concat(key, prefix,
  23413. base, '_', "_mbtn", sizeof(key));
  23414. switch (bind->mbutton)
  23415. {
  23416. case RETRO_DEVICE_ID_MOUSE_LEFT:
  23417. config_set_uint64(conf, key, 1);
  23418. break;
  23419. case RETRO_DEVICE_ID_MOUSE_RIGHT:
  23420. config_set_uint64(conf, key, 2);
  23421. break;
  23422. case RETRO_DEVICE_ID_MOUSE_MIDDLE:
  23423. config_set_uint64(conf, key, 3);
  23424. break;
  23425. case RETRO_DEVICE_ID_MOUSE_BUTTON_4:
  23426. config_set_uint64(conf, key, 4);
  23427. break;
  23428. case RETRO_DEVICE_ID_MOUSE_BUTTON_5:
  23429. config_set_uint64(conf, key, 5);
  23430. break;
  23431. case RETRO_DEVICE_ID_MOUSE_WHEELUP:
  23432. config_set_string(conf, key, "wu");
  23433. break;
  23434. case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
  23435. config_set_string(conf, key, "wd");
  23436. break;
  23437. case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
  23438. config_set_string(conf, key, "whu");
  23439. break;
  23440. case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
  23441. config_set_string(conf, key, "whd");
  23442. break;
  23443. default:
  23444. if (save_empty)
  23445. config_set_string(conf, key, "nul");
  23446. break;
  23447. }
  23448. }
  23449. /**
  23450. * input_config_save_keybind:
  23451. * @conf : pointer to config file object
  23452. * @prefix : prefix name of keybind
  23453. * @base : base name of keybind
  23454. * @bind : pointer to key binding object
  23455. * @kb : save keyboard binds
  23456. *
  23457. * Save a key binding to the config file.
  23458. */
  23459. void input_config_save_keybind(void *data, const char *prefix,
  23460. const char *base, const struct retro_keybind *bind,
  23461. bool save_empty)
  23462. {
  23463. config_file_t *conf = (config_file_t*)data;
  23464. save_keybind_joykey (conf, prefix, base, bind, save_empty);
  23465. save_keybind_axis (conf, prefix, base, bind, save_empty);
  23466. save_keybind_mbutton(conf, prefix, base, bind, save_empty);
  23467. }
  23468. /* MIDI */
  23469. static midi_driver_t *midi_driver_find_driver(const char *ident)
  23470. {
  23471. unsigned i;
  23472. for (i = 0; i < ARRAY_SIZE(midi_drivers); ++i)
  23473. {
  23474. if (string_is_equal(midi_drivers[i]->ident, ident))
  23475. return midi_drivers[i];
  23476. }
  23477. RARCH_ERR("[MIDI]: Unknown driver \"%s\", falling back to \"null\" driver.\n", ident);
  23478. return &midi_null;
  23479. }
  23480. static const void *midi_driver_find_handle(int index)
  23481. {
  23482. if (index < 0 || index >= ARRAY_SIZE(midi_drivers))
  23483. return NULL;
  23484. return midi_drivers[index];
  23485. }
  23486. struct string_list *midi_driver_get_avail_inputs(void)
  23487. {
  23488. struct rarch_state *p_rarch = &rarch_st;
  23489. return p_rarch->midi_drv_inputs;
  23490. }
  23491. struct string_list *midi_driver_get_avail_outputs(void)
  23492. {
  23493. struct rarch_state *p_rarch = &rarch_st;
  23494. return p_rarch->midi_drv_outputs;
  23495. }
  23496. static bool midi_driver_set_all_sounds_off(struct rarch_state *p_rarch)
  23497. {
  23498. midi_event_t event;
  23499. uint8_t i;
  23500. uint8_t data[3] = { 0xB0, 120, 0 };
  23501. bool result = true;
  23502. if (!p_rarch->midi_drv_data || !p_rarch->midi_drv_output_enabled)
  23503. return false;
  23504. event.data = data;
  23505. event.data_size = sizeof(data);
  23506. event.delta_time = 0;
  23507. for (i = 0; i < 16; ++i)
  23508. {
  23509. data[0] = 0xB0 | i;
  23510. if (!midi_drv->write(p_rarch->midi_drv_data, &event))
  23511. result = false;
  23512. }
  23513. if (!midi_drv->flush(p_rarch->midi_drv_data))
  23514. result = false;
  23515. if (!result)
  23516. RARCH_ERR("[MIDI]: All sounds off failed.\n");
  23517. return result;
  23518. }
  23519. bool midi_driver_set_volume(unsigned volume)
  23520. {
  23521. midi_event_t event;
  23522. struct rarch_state *p_rarch = &rarch_st;
  23523. uint8_t data[8] = {
  23524. 0xF0, 0x7F, 0x7F, 0x04, 0x01, 0, 0, 0xF7};
  23525. if (!p_rarch->midi_drv_data || !p_rarch->midi_drv_output_enabled)
  23526. return false;
  23527. volume = (unsigned)(163.83 * volume + 0.5);
  23528. if (volume > 16383)
  23529. volume = 16383;
  23530. data[5] = (uint8_t)(volume & 0x7F);
  23531. data[6] = (uint8_t)(volume >> 7);
  23532. event.data = data;
  23533. event.data_size = sizeof(data);
  23534. event.delta_time = 0;
  23535. if (!midi_drv->write(p_rarch->midi_drv_data, &event))
  23536. {
  23537. RARCH_ERR("[MIDI]: Volume change failed.\n");
  23538. return false;
  23539. }
  23540. return true;
  23541. }
  23542. static bool midi_driver_init_io_buffers(struct rarch_state *p_rarch)
  23543. {
  23544. uint8_t *midi_drv_input_buffer = (uint8_t*)malloc(MIDI_DRIVER_BUF_SIZE);
  23545. uint8_t *midi_drv_output_buffer = (uint8_t*)malloc(MIDI_DRIVER_BUF_SIZE);
  23546. if (!midi_drv_input_buffer || !midi_drv_output_buffer)
  23547. {
  23548. if (midi_drv_input_buffer)
  23549. free(midi_drv_input_buffer);
  23550. if (midi_drv_output_buffer)
  23551. free(midi_drv_output_buffer);
  23552. return false;
  23553. }
  23554. p_rarch->midi_drv_input_buffer = midi_drv_input_buffer;
  23555. p_rarch->midi_drv_output_buffer = midi_drv_output_buffer;
  23556. p_rarch->midi_drv_input_event.data = midi_drv_input_buffer;
  23557. p_rarch->midi_drv_input_event.data_size = 0;
  23558. p_rarch->midi_drv_output_event.data = midi_drv_output_buffer;
  23559. p_rarch->midi_drv_output_event.data_size = 0;
  23560. return true;
  23561. }
  23562. static void midi_driver_free(struct rarch_state *p_rarch)
  23563. {
  23564. if (p_rarch->midi_drv_data)
  23565. {
  23566. midi_drv->free(p_rarch->midi_drv_data);
  23567. p_rarch->midi_drv_data = NULL;
  23568. }
  23569. if (p_rarch->midi_drv_inputs)
  23570. {
  23571. string_list_free(p_rarch->midi_drv_inputs);
  23572. p_rarch->midi_drv_inputs = NULL;
  23573. }
  23574. if (p_rarch->midi_drv_outputs)
  23575. {
  23576. string_list_free(p_rarch->midi_drv_outputs);
  23577. p_rarch->midi_drv_outputs = NULL;
  23578. }
  23579. if (p_rarch->midi_drv_input_buffer)
  23580. {
  23581. free(p_rarch->midi_drv_input_buffer);
  23582. p_rarch->midi_drv_input_buffer = NULL;
  23583. }
  23584. if (p_rarch->midi_drv_output_buffer)
  23585. {
  23586. free(p_rarch->midi_drv_output_buffer);
  23587. p_rarch->midi_drv_output_buffer = NULL;
  23588. }
  23589. p_rarch->midi_drv_input_enabled = false;
  23590. p_rarch->midi_drv_output_enabled = false;
  23591. }
  23592. static bool midi_driver_init(struct rarch_state *p_rarch)
  23593. {
  23594. settings_t *settings = p_rarch->configuration_settings;
  23595. union string_list_elem_attr attr = {0};
  23596. const char *err_str = NULL;
  23597. p_rarch->midi_drv_inputs = string_list_new();
  23598. p_rarch->midi_drv_outputs = string_list_new();
  23599. if (!settings)
  23600. err_str = "settings unavailable";
  23601. else if (!p_rarch->midi_drv_inputs || !p_rarch->midi_drv_outputs)
  23602. err_str = "string_list_new failed";
  23603. else if (!string_list_append(p_rarch->midi_drv_inputs, "Off", attr) ||
  23604. !string_list_append(p_rarch->midi_drv_outputs, "Off", attr))
  23605. err_str = "string_list_append failed";
  23606. else
  23607. {
  23608. char * input = NULL;
  23609. char * output = NULL;
  23610. midi_drv = midi_driver_find_driver(
  23611. settings->arrays.midi_driver);
  23612. if (strcmp(midi_drv->ident, settings->arrays.midi_driver))
  23613. {
  23614. configuration_set_string(settings,
  23615. settings->arrays.midi_driver, midi_drv->ident);
  23616. }
  23617. if (!midi_drv->get_avail_inputs(p_rarch->midi_drv_inputs))
  23618. err_str = "list of input devices unavailable";
  23619. else if (!midi_drv->get_avail_outputs(p_rarch->midi_drv_outputs))
  23620. err_str = "list of output devices unavailable";
  23621. else
  23622. {
  23623. if (string_is_not_equal(settings->arrays.midi_input, "Off"))
  23624. {
  23625. if (string_list_find_elem(p_rarch->midi_drv_inputs, settings->arrays.midi_input))
  23626. input = settings->arrays.midi_input;
  23627. else
  23628. {
  23629. RARCH_WARN("[MIDI]: Input device \"%s\" unavailable.\n",
  23630. settings->arrays.midi_input);
  23631. configuration_set_string(settings,
  23632. settings->arrays.midi_input, "Off");
  23633. }
  23634. }
  23635. if (string_is_not_equal(settings->arrays.midi_output, "Off"))
  23636. {
  23637. if (string_list_find_elem(p_rarch->midi_drv_outputs, settings->arrays.midi_output))
  23638. output = settings->arrays.midi_output;
  23639. else
  23640. {
  23641. RARCH_WARN("[MIDI]: Output device \"%s\" unavailable.\n",
  23642. settings->arrays.midi_output);
  23643. configuration_set_string(settings,
  23644. settings->arrays.midi_output, "Off");
  23645. }
  23646. }
  23647. p_rarch->midi_drv_data = midi_drv->init(input, output);
  23648. if (!p_rarch->midi_drv_data)
  23649. err_str = "driver init failed";
  23650. else
  23651. {
  23652. p_rarch->midi_drv_input_enabled = (input != NULL);
  23653. p_rarch->midi_drv_output_enabled = (output != NULL);
  23654. if (!midi_driver_init_io_buffers(p_rarch))
  23655. err_str = "out of memory";
  23656. else
  23657. {
  23658. if (input)
  23659. RARCH_LOG("[MIDI]: Input device \"%s\".\n", input);
  23660. else
  23661. RARCH_LOG("[MIDI]: Input disabled.\n");
  23662. if (output)
  23663. {
  23664. RARCH_LOG("[MIDI]: Output device \"%s\".\n", output);
  23665. midi_driver_set_volume(settings->uints.midi_volume);
  23666. }
  23667. else
  23668. RARCH_LOG("[MIDI]: Output disabled.\n");
  23669. }
  23670. }
  23671. }
  23672. }
  23673. if (err_str)
  23674. {
  23675. midi_driver_free(p_rarch);
  23676. RARCH_ERR("[MIDI]: Initialization failed (%s).\n", err_str);
  23677. }
  23678. else
  23679. RARCH_LOG("[MIDI]: Initialized \"%s\" driver.\n", midi_drv->ident);
  23680. return err_str == NULL;
  23681. }
  23682. bool midi_driver_set_input(const char *input)
  23683. {
  23684. struct rarch_state *p_rarch = &rarch_st;
  23685. if (!p_rarch->midi_drv_data)
  23686. {
  23687. #ifdef DEBUG
  23688. RARCH_ERR("[MIDI]: midi_driver_set_input called on uninitialized driver.\n");
  23689. #endif
  23690. return false;
  23691. }
  23692. if (string_is_equal(input, "Off"))
  23693. input = NULL;
  23694. if (!midi_drv->set_input(p_rarch->midi_drv_data, input))
  23695. {
  23696. if (input)
  23697. RARCH_ERR("[MIDI]: Failed to change input device to \"%s\".\n", input);
  23698. else
  23699. RARCH_ERR("[MIDI]: Failed to disable input.\n");
  23700. return false;
  23701. }
  23702. if (input)
  23703. RARCH_LOG("[MIDI]: Input device changed to \"%s\".\n", input);
  23704. else
  23705. RARCH_LOG("[MIDI]: Input disabled.\n");
  23706. p_rarch->midi_drv_input_enabled = input != NULL;
  23707. return true;
  23708. }
  23709. bool midi_driver_set_output(const char *output)
  23710. {
  23711. struct rarch_state *p_rarch = &rarch_st;
  23712. if (!p_rarch->midi_drv_data)
  23713. {
  23714. #ifdef DEBUG
  23715. RARCH_ERR("[MIDI]: midi_driver_set_output called on uninitialized driver.\n");
  23716. #endif
  23717. return false;
  23718. }
  23719. if (string_is_equal(output, "Off"))
  23720. output = NULL;
  23721. if (!midi_drv->set_output(p_rarch->midi_drv_data, output))
  23722. {
  23723. if (output)
  23724. RARCH_ERR("[MIDI]: Failed to change output device to \"%s\".\n", output);
  23725. else
  23726. RARCH_ERR("[MIDI]: Failed to disable output.\n");
  23727. return false;
  23728. }
  23729. if (output)
  23730. {
  23731. settings_t *settings = p_rarch->configuration_settings;
  23732. p_rarch->midi_drv_output_enabled = true;
  23733. RARCH_LOG("[MIDI]: Output device changed to \"%s\".\n", output);
  23734. if (settings)
  23735. midi_driver_set_volume(settings->uints.midi_volume);
  23736. else
  23737. RARCH_ERR("[MIDI]: Volume change failed (settings unavailable).\n");
  23738. }
  23739. else
  23740. {
  23741. p_rarch->midi_drv_output_enabled = false;
  23742. RARCH_LOG("[MIDI]: Output disabled.\n");
  23743. }
  23744. return true;
  23745. }
  23746. static bool midi_driver_input_enabled(void)
  23747. {
  23748. struct rarch_state *p_rarch = &rarch_st;
  23749. return p_rarch->midi_drv_input_enabled;
  23750. }
  23751. static bool midi_driver_output_enabled(void)
  23752. {
  23753. struct rarch_state *p_rarch = &rarch_st;
  23754. return p_rarch->midi_drv_output_enabled;
  23755. }
  23756. static bool midi_driver_read(uint8_t *byte)
  23757. {
  23758. static int i;
  23759. struct rarch_state *p_rarch = &rarch_st;
  23760. if (!p_rarch->midi_drv_data || !p_rarch->midi_drv_input_enabled || !byte)
  23761. {
  23762. #ifdef DEBUG
  23763. if (!p_rarch->midi_drv_data)
  23764. RARCH_ERR("[MIDI]: midi_driver_read called on uninitialized driver.\n");
  23765. else if (!p_rarch->midi_drv_input_enabled)
  23766. RARCH_ERR("[MIDI]: midi_driver_read called when input is disabled.\n");
  23767. else
  23768. RARCH_ERR("[MIDI]: midi_driver_read called with null pointer.\n");
  23769. #endif
  23770. return false;
  23771. }
  23772. if (i == p_rarch->midi_drv_input_event.data_size)
  23773. {
  23774. p_rarch->midi_drv_input_event.data_size = MIDI_DRIVER_BUF_SIZE;
  23775. if (!midi_drv->read(p_rarch->midi_drv_data,
  23776. &p_rarch->midi_drv_input_event))
  23777. {
  23778. p_rarch->midi_drv_input_event.data_size = i;
  23779. return false;
  23780. }
  23781. i = 0;
  23782. #ifdef DEBUG
  23783. if (p_rarch->midi_drv_input_event.data_size == 1)
  23784. RARCH_LOG("[MIDI]: In [0x%02X].\n",
  23785. p_rarch->midi_drv_input_event.data[0]);
  23786. else if (p_rarch->midi_drv_input_event.data_size == 2)
  23787. RARCH_LOG("[MIDI]: In [0x%02X, 0x%02X].\n",
  23788. p_rarch->midi_drv_input_event.data[0],
  23789. p_rarch->midi_drv_input_event.data[1]);
  23790. else if (p_rarch->midi_drv_input_event.data_size == 3)
  23791. RARCH_LOG("[MIDI]: In [0x%02X, 0x%02X, 0x%02X].\n",
  23792. p_rarch->midi_drv_input_event.data[0],
  23793. p_rarch->midi_drv_input_event.data[1],
  23794. p_rarch->midi_drv_input_event.data[2]);
  23795. else
  23796. RARCH_LOG("[MIDI]: In [0x%02X, ...], size %u.\n",
  23797. p_rarch->midi_drv_input_event.data[0],
  23798. p_rarch->midi_drv_input_event.data_size);
  23799. #endif
  23800. }
  23801. *byte = p_rarch->midi_drv_input_event.data[i++];
  23802. return true;
  23803. }
  23804. static bool midi_driver_write(uint8_t byte, uint32_t delta_time)
  23805. {
  23806. static int event_size;
  23807. struct rarch_state *p_rarch = &rarch_st;
  23808. if (!p_rarch->midi_drv_data || !p_rarch->midi_drv_output_enabled)
  23809. {
  23810. #ifdef DEBUG
  23811. if (!p_rarch->midi_drv_data)
  23812. RARCH_ERR("[MIDI]: midi_driver_write called on uninitialized driver.\n");
  23813. else
  23814. RARCH_ERR("[MIDI]: midi_driver_write called when output is disabled.\n");
  23815. #endif
  23816. return false;
  23817. }
  23818. if (byte >= 0x80)
  23819. {
  23820. if (p_rarch->midi_drv_output_event.data_size &&
  23821. p_rarch->midi_drv_output_event.data[0] == 0xF0)
  23822. {
  23823. if (byte == 0xF7)
  23824. event_size = (int)p_rarch->midi_drv_output_event.data_size + 1;
  23825. else
  23826. {
  23827. if (!midi_drv->write(p_rarch->midi_drv_data,
  23828. &p_rarch->midi_drv_output_event))
  23829. return false;
  23830. #ifdef DEBUG
  23831. switch (p_rarch->midi_drv_output_event.data_size)
  23832. {
  23833. case 1:
  23834. RARCH_LOG("[MIDI]: Out [0x%02X].\n",
  23835. p_rarch->midi_drv_output_event.data[0]);
  23836. break;
  23837. case 2:
  23838. RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X].\n",
  23839. p_rarch->midi_drv_output_event.data[0],
  23840. p_rarch->midi_drv_output_event.data[1]);
  23841. break;
  23842. case 3:
  23843. RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X, 0x%02X].\n",
  23844. p_rarch->midi_drv_output_event.data[0],
  23845. p_rarch->midi_drv_output_event.data[1],
  23846. p_rarch->midi_drv_output_event.data[2]);
  23847. break;
  23848. default:
  23849. RARCH_LOG("[MIDI]: Out [0x%02X, ...], size %u.\n",
  23850. p_rarch->midi_drv_output_event.data[0],
  23851. p_rarch->midi_drv_output_event.data_size);
  23852. break;
  23853. }
  23854. #endif
  23855. p_rarch->midi_drv_output_pending = true;
  23856. event_size = (int)midi_driver_get_event_size(byte);
  23857. p_rarch->midi_drv_output_event.data_size = 0;
  23858. p_rarch->midi_drv_output_event.delta_time = 0;
  23859. }
  23860. }
  23861. else
  23862. {
  23863. event_size = (int)midi_driver_get_event_size(byte);
  23864. p_rarch->midi_drv_output_event.data_size = 0;
  23865. p_rarch->midi_drv_output_event.delta_time = 0;
  23866. }
  23867. }
  23868. if (p_rarch->midi_drv_output_event.data_size < MIDI_DRIVER_BUF_SIZE)
  23869. {
  23870. p_rarch->midi_drv_output_event.data[p_rarch->midi_drv_output_event.data_size] = byte;
  23871. ++p_rarch->midi_drv_output_event.data_size;
  23872. p_rarch->midi_drv_output_event.delta_time += delta_time;
  23873. }
  23874. else
  23875. {
  23876. #ifdef DEBUG
  23877. RARCH_ERR("[MIDI]: Output event dropped.\n");
  23878. #endif
  23879. return false;
  23880. }
  23881. if (p_rarch->midi_drv_output_event.data_size == event_size)
  23882. {
  23883. if (!midi_drv->write(p_rarch->midi_drv_data,
  23884. &p_rarch->midi_drv_output_event))
  23885. return false;
  23886. #ifdef DEBUG
  23887. switch (p_rarch->midi_drv_output_event.data_size)
  23888. {
  23889. case 1:
  23890. RARCH_LOG("[MIDI]: Out [0x%02X].\n",
  23891. p_rarch->midi_drv_output_event.data[0]);
  23892. break;
  23893. case 2:
  23894. RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X].\n",
  23895. p_rarch->midi_drv_output_event.data[0],
  23896. p_rarch->midi_drv_output_event.data[1]);
  23897. break;
  23898. case 3:
  23899. RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X, 0x%02X].\n",
  23900. p_rarch->midi_drv_output_event.data[0],
  23901. p_rarch->midi_drv_output_event.data[1],
  23902. p_rarch->midi_drv_output_event.data[2]);
  23903. break;
  23904. default:
  23905. RARCH_LOG("[MIDI]: Out [0x%02X, ...], size %u.\n",
  23906. p_rarch->midi_drv_output_event.data[0],
  23907. p_rarch->midi_drv_output_event.data_size);
  23908. break;
  23909. }
  23910. #endif
  23911. p_rarch->midi_drv_output_pending = true;
  23912. p_rarch->midi_drv_output_event.data_size = 0;
  23913. p_rarch->midi_drv_output_event.delta_time = 0;
  23914. }
  23915. return true;
  23916. }
  23917. static bool midi_driver_flush(void)
  23918. {
  23919. struct rarch_state *p_rarch = &rarch_st;
  23920. if (!p_rarch->midi_drv_data)
  23921. return false;
  23922. if (p_rarch->midi_drv_output_pending)
  23923. p_rarch->midi_drv_output_pending =
  23924. !midi_drv->flush(p_rarch->midi_drv_data);
  23925. return !p_rarch->midi_drv_output_pending;
  23926. }
  23927. size_t midi_driver_get_event_size(uint8_t status)
  23928. {
  23929. static const uint8_t midi_drv_ev_sizes[128] =
  23930. {
  23931. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  23932. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  23933. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  23934. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  23935. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  23936. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  23937. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  23938. 0, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
  23939. };
  23940. if (status < 0x80)
  23941. {
  23942. #ifdef DEBUG
  23943. RARCH_ERR("[MIDI]: midi_driver_get_event_size called with invalid status.\n");
  23944. #endif
  23945. return 0;
  23946. }
  23947. return midi_drv_ev_sizes[status - 0x80];
  23948. }
  23949. /* AUDIO */
  23950. static enum resampler_quality audio_driver_get_resampler_quality(
  23951. struct rarch_state *p_rarch)
  23952. {
  23953. settings_t *settings = p_rarch->configuration_settings;
  23954. if (!settings)
  23955. return RESAMPLER_QUALITY_DONTCARE;
  23956. return (enum resampler_quality)settings->uints.audio_resampler_quality;
  23957. }
  23958. #ifdef HAVE_AUDIOMIXER
  23959. audio_mixer_stream_t *audio_driver_mixer_get_stream(unsigned i)
  23960. {
  23961. struct rarch_state *p_rarch = &rarch_st;
  23962. if (i > (AUDIO_MIXER_MAX_SYSTEM_STREAMS-1))
  23963. return NULL;
  23964. return &p_rarch->audio_mixer_streams[i];
  23965. }
  23966. const char *audio_driver_mixer_get_stream_name(unsigned i)
  23967. {
  23968. struct rarch_state *p_rarch = &rarch_st;
  23969. if (i > (AUDIO_MIXER_MAX_SYSTEM_STREAMS-1))
  23970. return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE);
  23971. if (!string_is_empty(p_rarch->audio_mixer_streams[i].name))
  23972. return p_rarch->audio_mixer_streams[i].name;
  23973. return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE);
  23974. }
  23975. static void audio_driver_mixer_deinit(struct rarch_state *p_rarch)
  23976. {
  23977. unsigned i;
  23978. p_rarch->audio_mixer_active = false;
  23979. for (i = 0; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
  23980. {
  23981. audio_driver_mixer_stop_stream(i);
  23982. audio_driver_mixer_remove_stream(i);
  23983. }
  23984. audio_mixer_done();
  23985. }
  23986. #endif
  23987. /**
  23988. * audio_compute_buffer_statistics:
  23989. *
  23990. * Computes audio buffer statistics.
  23991. *
  23992. **/
  23993. static bool audio_compute_buffer_statistics(
  23994. struct rarch_state *p_rarch,
  23995. audio_statistics_t *stats)
  23996. {
  23997. unsigned i, low_water_size, high_water_size, avg, stddev;
  23998. uint64_t accum = 0;
  23999. uint64_t accum_var = 0;
  24000. unsigned low_water_count = 0;
  24001. unsigned high_water_count = 0;
  24002. unsigned samples = MIN(
  24003. (unsigned)p_rarch->audio_driver_free_samples_count,
  24004. AUDIO_BUFFER_FREE_SAMPLES_COUNT);
  24005. if (samples < 3)
  24006. return false;
  24007. stats->samples = (unsigned)
  24008. p_rarch->audio_driver_free_samples_count;
  24009. #ifdef WARPUP
  24010. /* uint64 to double not implemented, fair chance
  24011. * signed int64 to double doesn't exist either */
  24012. /* https://forums.libretro.com/t/unsupported-platform-help/13903/ */
  24013. (void)stddev;
  24014. #elif defined(_MSC_VER) && _MSC_VER <= 1200
  24015. /* FIXME: error C2520: conversion from unsigned __int64
  24016. * to double not implemented, use signed __int64 */
  24017. (void)stddev;
  24018. #else
  24019. for (i = 1; i < samples; i++)
  24020. accum += p_rarch->audio_driver_free_samples_buf[i];
  24021. avg = (unsigned)accum / (samples - 1);
  24022. for (i = 1; i < samples; i++)
  24023. {
  24024. int diff = avg - p_rarch->audio_driver_free_samples_buf[i];
  24025. accum_var += diff * diff;
  24026. }
  24027. stddev = (unsigned)
  24028. sqrt((double)accum_var / (samples - 2));
  24029. stats->average_buffer_saturation = (1.0f - (float)avg
  24030. / p_rarch->audio_driver_buffer_size) * 100.0;
  24031. stats->std_deviation_percentage = ((float)stddev
  24032. / p_rarch->audio_driver_buffer_size) * 100.0;
  24033. #endif
  24034. low_water_size = (unsigned)(p_rarch->audio_driver_buffer_size * 3 / 4);
  24035. high_water_size = (unsigned)(p_rarch->audio_driver_buffer_size / 4);
  24036. for (i = 1; i < samples; i++)
  24037. {
  24038. if (p_rarch->audio_driver_free_samples_buf[i] >= low_water_size)
  24039. low_water_count++;
  24040. else if (p_rarch->audio_driver_free_samples_buf[i] <= high_water_size)
  24041. high_water_count++;
  24042. }
  24043. stats->close_to_underrun = (100.0f * low_water_count) / (samples - 1);
  24044. stats->close_to_blocking = (100.0f * high_water_count) / (samples - 1);
  24045. return true;
  24046. }
  24047. #ifdef DEBUG
  24048. static void report_audio_buffer_statistics(struct rarch_state *p_rarch)
  24049. {
  24050. audio_statistics_t audio_stats;
  24051. audio_stats.samples = 0;
  24052. audio_stats.average_buffer_saturation = 0.0f;
  24053. audio_stats.std_deviation_percentage = 0.0f;
  24054. audio_stats.close_to_underrun = 0.0f;
  24055. audio_stats.close_to_blocking = 0.0f;
  24056. if (!audio_compute_buffer_statistics(p_rarch, &audio_stats))
  24057. return;
  24058. RARCH_LOG("[Audio]: Average audio buffer saturation: %.2f %%,"
  24059. " standard deviation (percentage points): %.2f %%.\n"
  24060. "[Audio]: Amount of time spent close to underrun: %.2f %%."
  24061. " Close to blocking: %.2f %%.\n",
  24062. audio_stats.average_buffer_saturation,
  24063. audio_stats.std_deviation_percentage,
  24064. audio_stats.close_to_underrun,
  24065. audio_stats.close_to_blocking);
  24066. }
  24067. #endif
  24068. /**
  24069. * config_get_audio_driver_options:
  24070. *
  24071. * Get an enumerated list of all audio driver names, separated by '|'.
  24072. *
  24073. * Returns: string listing of all audio driver names, separated by '|'.
  24074. **/
  24075. const char *config_get_audio_driver_options(void)
  24076. {
  24077. return char_list_new_special(STRING_LIST_AUDIO_DRIVERS, NULL);
  24078. }
  24079. static void audio_driver_deinit_resampler(struct rarch_state *p_rarch)
  24080. {
  24081. if (p_rarch->audio_driver_resampler && p_rarch->audio_driver_resampler_data)
  24082. p_rarch->audio_driver_resampler->free(p_rarch->audio_driver_resampler_data);
  24083. p_rarch->audio_driver_resampler = NULL;
  24084. p_rarch->audio_driver_resampler_data = NULL;
  24085. }
  24086. static bool audio_driver_deinit_internal(struct rarch_state *p_rarch)
  24087. {
  24088. settings_t *settings = p_rarch->configuration_settings;
  24089. bool audio_enable = settings->bools.audio_enable;
  24090. if (p_rarch->current_audio && p_rarch->current_audio->free)
  24091. {
  24092. if (p_rarch->audio_driver_context_audio_data)
  24093. p_rarch->current_audio->free(
  24094. p_rarch->audio_driver_context_audio_data);
  24095. p_rarch->audio_driver_context_audio_data = NULL;
  24096. }
  24097. if (p_rarch->audio_driver_output_samples_conv_buf)
  24098. memalign_free(p_rarch->audio_driver_output_samples_conv_buf);
  24099. p_rarch->audio_driver_output_samples_conv_buf = NULL;
  24100. if (p_rarch->audio_driver_input_data)
  24101. memalign_free(p_rarch->audio_driver_input_data);
  24102. p_rarch->audio_driver_input_data = NULL;
  24103. p_rarch->audio_driver_data_ptr = 0;
  24104. #ifdef HAVE_REWIND
  24105. if (p_rarch->audio_driver_rewind_buf)
  24106. memalign_free(p_rarch->audio_driver_rewind_buf);
  24107. p_rarch->audio_driver_rewind_buf = NULL;
  24108. p_rarch->audio_driver_rewind_size = 0;
  24109. #endif
  24110. if (!audio_enable)
  24111. {
  24112. p_rarch->audio_driver_active = false;
  24113. return false;
  24114. }
  24115. audio_driver_deinit_resampler(p_rarch);
  24116. if (p_rarch->audio_driver_output_samples_buf)
  24117. memalign_free(p_rarch->audio_driver_output_samples_buf);
  24118. p_rarch->audio_driver_output_samples_buf = NULL;
  24119. #ifdef HAVE_DSP_FILTER
  24120. audio_driver_dsp_filter_free();
  24121. #endif
  24122. #ifdef DEBUG
  24123. report_audio_buffer_statistics(p_rarch);
  24124. #endif
  24125. return true;
  24126. }
  24127. static bool audio_driver_free_devices_list(struct rarch_state *p_rarch)
  24128. {
  24129. if (!p_rarch->current_audio || !p_rarch->current_audio->device_list_free
  24130. || !p_rarch->audio_driver_context_audio_data)
  24131. return false;
  24132. p_rarch->current_audio->device_list_free(
  24133. p_rarch->audio_driver_context_audio_data,
  24134. p_rarch->audio_driver_devices_list);
  24135. p_rarch->audio_driver_devices_list = NULL;
  24136. return true;
  24137. }
  24138. static bool audio_driver_deinit(struct rarch_state *p_rarch)
  24139. {
  24140. #ifdef HAVE_AUDIOMIXER
  24141. audio_driver_mixer_deinit(p_rarch);
  24142. #endif
  24143. audio_driver_free_devices_list(p_rarch);
  24144. return audio_driver_deinit_internal(p_rarch);
  24145. }
  24146. static bool audio_driver_find_driver(struct rarch_state *p_rarch)
  24147. {
  24148. settings_t *settings = p_rarch->configuration_settings;
  24149. int i = (int)driver_find_index(
  24150. "audio_driver",
  24151. settings->arrays.audio_driver);
  24152. if (i >= 0)
  24153. p_rarch->current_audio = (const audio_driver_t*)
  24154. audio_drivers[i];
  24155. else
  24156. {
  24157. if (verbosity_is_enabled())
  24158. {
  24159. unsigned d;
  24160. RARCH_ERR("Couldn't find any audio driver named \"%s\"\n",
  24161. settings->arrays.audio_driver);
  24162. RARCH_LOG_OUTPUT("Available audio drivers are:\n");
  24163. for (d = 0; audio_drivers[d]; d++)
  24164. {
  24165. if (audio_drivers[d])
  24166. RARCH_LOG_OUTPUT("\t%s\n", audio_drivers[d]->ident);
  24167. }
  24168. RARCH_WARN("Going to default to first audio driver...\n");
  24169. }
  24170. p_rarch->current_audio = (const audio_driver_t*)
  24171. audio_drivers[0];
  24172. if (!p_rarch->current_audio)
  24173. retroarch_fail(1, "audio_driver_find()");
  24174. }
  24175. return true;
  24176. }
  24177. static bool audio_driver_init_internal(
  24178. struct rarch_state *p_rarch,
  24179. bool audio_cb_inited)
  24180. {
  24181. unsigned new_rate = 0;
  24182. float *samples_buf = NULL;
  24183. size_t max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2;
  24184. settings_t *settings = p_rarch->configuration_settings;
  24185. bool audio_enable = settings->bools.audio_enable;
  24186. bool audio_sync = settings->bools.audio_sync;
  24187. bool audio_rate_control = settings->bools.audio_rate_control;
  24188. float slowmotion_ratio = settings->floats.slowmotion_ratio;
  24189. unsigned audio_latency = (p_rarch->runloop_audio_latency > settings->uints.audio_latency) ?
  24190. p_rarch->runloop_audio_latency : settings->uints.audio_latency;
  24191. #ifdef HAVE_REWIND
  24192. int16_t *rewind_buf = NULL;
  24193. #endif
  24194. /* Accomodate rewind since at some point we might have two full buffers. */
  24195. size_t outsamples_max = AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * AUDIO_MAX_RATIO * slowmotion_ratio;
  24196. int16_t *conv_buf = (int16_t*)memalign_alloc(64, outsamples_max * sizeof(int16_t));
  24197. float *audio_buf = (float*)memalign_alloc(64, AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * sizeof(float));
  24198. convert_s16_to_float_init_simd();
  24199. convert_float_to_s16_init_simd();
  24200. /* Used for recording even if audio isn't enabled. */
  24201. retro_assert(conv_buf != NULL);
  24202. retro_assert(audio_buf != NULL);
  24203. if (!conv_buf || !audio_buf)
  24204. goto error;
  24205. memset(audio_buf, 0, AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * sizeof(float));
  24206. p_rarch->audio_driver_input_data = audio_buf;
  24207. p_rarch->audio_driver_output_samples_conv_buf = conv_buf;
  24208. p_rarch->audio_driver_chunk_block_size = AUDIO_CHUNK_SIZE_BLOCKING;
  24209. p_rarch->audio_driver_chunk_nonblock_size = AUDIO_CHUNK_SIZE_NONBLOCKING;
  24210. p_rarch->audio_driver_chunk_size = p_rarch->audio_driver_chunk_block_size;
  24211. #ifdef HAVE_REWIND
  24212. /* Needs to be able to hold full content of a full max_bufsamples
  24213. * in addition to its own. */
  24214. rewind_buf = (int16_t*)memalign_alloc(64, max_bufsamples * sizeof(int16_t));
  24215. retro_assert(rewind_buf != NULL);
  24216. if (!rewind_buf)
  24217. goto error;
  24218. p_rarch->audio_driver_rewind_buf = rewind_buf;
  24219. p_rarch->audio_driver_rewind_size = max_bufsamples;
  24220. #endif
  24221. if (!audio_enable)
  24222. {
  24223. p_rarch->audio_driver_active = false;
  24224. return false;
  24225. }
  24226. audio_driver_find_driver(p_rarch);
  24227. if (!p_rarch->current_audio || !p_rarch->current_audio->init)
  24228. {
  24229. RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n");
  24230. p_rarch->audio_driver_active = false;
  24231. return false;
  24232. }
  24233. #ifdef HAVE_THREADS
  24234. if (audio_cb_inited)
  24235. {
  24236. RARCH_LOG("[Audio]: Starting threaded audio driver ...\n");
  24237. if (!audio_init_thread(
  24238. &p_rarch->current_audio,
  24239. &p_rarch->audio_driver_context_audio_data,
  24240. *settings->arrays.audio_device
  24241. ? settings->arrays.audio_device : NULL,
  24242. settings->uints.audio_out_rate, &new_rate,
  24243. audio_latency,
  24244. settings->uints.audio_block_frames,
  24245. p_rarch->current_audio))
  24246. {
  24247. RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n");
  24248. retroarch_fail(1, "audio_driver_init_internal()");
  24249. }
  24250. }
  24251. else
  24252. #endif
  24253. {
  24254. p_rarch->audio_driver_context_audio_data =
  24255. p_rarch->current_audio->init(*settings->arrays.audio_device ?
  24256. settings->arrays.audio_device : NULL,
  24257. settings->uints.audio_out_rate,
  24258. audio_latency,
  24259. settings->uints.audio_block_frames,
  24260. &new_rate);
  24261. }
  24262. if (new_rate != 0)
  24263. configuration_set_int(settings, settings->uints.audio_out_rate, new_rate);
  24264. if (!p_rarch->audio_driver_context_audio_data)
  24265. {
  24266. RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n");
  24267. p_rarch->audio_driver_active = false;
  24268. }
  24269. p_rarch->audio_driver_use_float = false;
  24270. if ( p_rarch->audio_driver_active
  24271. && p_rarch->current_audio->use_float(
  24272. p_rarch->audio_driver_context_audio_data))
  24273. p_rarch->audio_driver_use_float = true;
  24274. if (!audio_sync && p_rarch->audio_driver_active)
  24275. {
  24276. if (p_rarch->audio_driver_active &&
  24277. p_rarch->audio_driver_context_audio_data)
  24278. p_rarch->current_audio->set_nonblock_state(
  24279. p_rarch->audio_driver_context_audio_data, true);
  24280. p_rarch->audio_driver_chunk_size =
  24281. p_rarch->audio_driver_chunk_nonblock_size;
  24282. }
  24283. if (p_rarch->audio_driver_input <= 0.0f)
  24284. {
  24285. /* Should never happen. */
  24286. RARCH_WARN("[Audio]: Input rate is invalid (%.3f Hz)."
  24287. " Using output rate (%u Hz).\n",
  24288. p_rarch->audio_driver_input, settings->uints.audio_out_rate);
  24289. p_rarch->audio_driver_input = settings->uints.audio_out_rate;
  24290. }
  24291. p_rarch->audio_source_ratio_original =
  24292. p_rarch->audio_source_ratio_current =
  24293. (double)settings->uints.audio_out_rate / p_rarch->audio_driver_input;
  24294. if (!retro_resampler_realloc(
  24295. &p_rarch->audio_driver_resampler_data,
  24296. &p_rarch->audio_driver_resampler,
  24297. settings->arrays.audio_resampler,
  24298. audio_driver_get_resampler_quality(p_rarch),
  24299. p_rarch->audio_source_ratio_original))
  24300. {
  24301. RARCH_ERR("Failed to initialize resampler \"%s\".\n",
  24302. settings->arrays.audio_resampler);
  24303. p_rarch->audio_driver_active = false;
  24304. }
  24305. p_rarch->audio_driver_data_ptr = 0;
  24306. retro_assert(settings->uints.audio_out_rate <
  24307. p_rarch->audio_driver_input * AUDIO_MAX_RATIO);
  24308. samples_buf = (float*)memalign_alloc(64, outsamples_max * sizeof(float));
  24309. retro_assert(samples_buf != NULL);
  24310. if (!samples_buf)
  24311. goto error;
  24312. p_rarch->audio_driver_output_samples_buf = (float*)samples_buf;
  24313. p_rarch->audio_driver_control = false;
  24314. if (
  24315. !audio_cb_inited
  24316. && p_rarch->audio_driver_active
  24317. && audio_rate_control
  24318. )
  24319. {
  24320. /* Audio rate control requires write_avail
  24321. * and buffer_size to be implemented. */
  24322. if (p_rarch->current_audio->buffer_size)
  24323. {
  24324. p_rarch->audio_driver_buffer_size =
  24325. p_rarch->current_audio->buffer_size(
  24326. p_rarch->audio_driver_context_audio_data);
  24327. p_rarch->audio_driver_control = true;
  24328. }
  24329. else
  24330. RARCH_WARN("[Audio]: Rate control was desired, but driver does not support needed features.\n");
  24331. }
  24332. command_event(CMD_EVENT_DSP_FILTER_INIT, NULL);
  24333. p_rarch->audio_driver_free_samples_count = 0;
  24334. #ifdef HAVE_AUDIOMIXER
  24335. audio_mixer_init(settings->uints.audio_out_rate);
  24336. #endif
  24337. /* Threaded driver is initially stopped. */
  24338. if (
  24339. p_rarch->audio_driver_active
  24340. && audio_cb_inited
  24341. )
  24342. audio_driver_start(p_rarch,
  24343. false);
  24344. return true;
  24345. error:
  24346. return audio_driver_deinit(p_rarch);
  24347. }
  24348. /**
  24349. * audio_driver_flush:
  24350. * @data : pointer to audio buffer.
  24351. * @right : amount of samples to write.
  24352. *
  24353. * Writes audio samples to audio driver. Will first
  24354. * perform DSP processing (if enabled) and resampling.
  24355. **/
  24356. static void audio_driver_flush(
  24357. struct rarch_state *p_rarch,
  24358. float slowmotion_ratio,
  24359. bool audio_fastforward_mute,
  24360. const int16_t *data, size_t samples,
  24361. bool is_slowmotion, bool is_fastmotion)
  24362. {
  24363. struct resampler_data src_data;
  24364. float audio_volume_gain = (p_rarch->audio_driver_mute_enable ||
  24365. (audio_fastforward_mute && is_fastmotion)) ?
  24366. 0.0f : p_rarch->audio_driver_volume_gain;
  24367. src_data.data_out = NULL;
  24368. src_data.output_frames = 0;
  24369. convert_s16_to_float(p_rarch->audio_driver_input_data, data, samples,
  24370. audio_volume_gain);
  24371. src_data.data_in = p_rarch->audio_driver_input_data;
  24372. src_data.input_frames = samples >> 1;
  24373. #ifdef HAVE_DSP_FILTER
  24374. if (p_rarch->audio_driver_dsp)
  24375. {
  24376. struct retro_dsp_data dsp_data;
  24377. dsp_data.input = NULL;
  24378. dsp_data.input_frames = 0;
  24379. dsp_data.output = NULL;
  24380. dsp_data.output_frames = 0;
  24381. dsp_data.input = p_rarch->audio_driver_input_data;
  24382. dsp_data.input_frames = (unsigned)(samples >> 1);
  24383. retro_dsp_filter_process(p_rarch->audio_driver_dsp, &dsp_data);
  24384. if (dsp_data.output)
  24385. {
  24386. src_data.data_in = dsp_data.output;
  24387. src_data.input_frames = dsp_data.output_frames;
  24388. }
  24389. }
  24390. #endif
  24391. src_data.data_out = p_rarch->audio_driver_output_samples_buf;
  24392. if (p_rarch->audio_driver_control)
  24393. {
  24394. /* Readjust the audio input rate. */
  24395. int half_size =
  24396. (int)(p_rarch->audio_driver_buffer_size / 2);
  24397. int avail =
  24398. (int)p_rarch->current_audio->write_avail(
  24399. p_rarch->audio_driver_context_audio_data);
  24400. int delta_mid = avail - half_size;
  24401. double direction = (double)delta_mid / half_size;
  24402. double adjust = 1.0 +
  24403. p_rarch->audio_driver_rate_control_delta * direction;
  24404. unsigned write_idx =
  24405. p_rarch->audio_driver_free_samples_count++ &
  24406. (AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1);
  24407. p_rarch->audio_driver_free_samples_buf
  24408. [write_idx] = avail;
  24409. p_rarch->audio_source_ratio_current =
  24410. p_rarch->audio_source_ratio_original * adjust;
  24411. #if 0
  24412. if (verbosity_is_enabled())
  24413. {
  24414. RARCH_LOG_OUTPUT("[Audio]: Audio buffer is %u%% full\n",
  24415. (unsigned)(100 - (avail * 100) /
  24416. p_rarch->audio_driver_buffer_size));
  24417. RARCH_LOG_OUTPUT("[Audio]: New rate: %lf, Orig rate: %lf\n",
  24418. p_rarch->audio_source_ratio_current,
  24419. p_rarch->audio_source_ratio_original);
  24420. }
  24421. #endif
  24422. }
  24423. src_data.ratio = p_rarch->audio_source_ratio_current;
  24424. if (is_slowmotion)
  24425. src_data.ratio *= slowmotion_ratio;
  24426. /* Note: Ideally we would divide by the user-configured
  24427. * 'fastforward_ratio' when fast forward is enabled,
  24428. * but in practice this doesn't work:
  24429. * - 'fastforward_ratio' is only a limit. If the host
  24430. * cannot push frames fast enough, the actual ratio
  24431. * will be lower - and crackling will ensue
  24432. * - Most of the time 'fastforward_ratio' will be
  24433. * zero (unlimited)
  24434. * So what we would need to do is measure the time since
  24435. * the last audio flush operation, and calculate a 'real'
  24436. * fast-forward ratio - but this doesn't work either.
  24437. * The measurement is inaccurate and the frame-by-frame
  24438. * fluctuations are too large, so crackling is unavoidable.
  24439. * Since it's going to crackle anyway, there's no point
  24440. * trying to do anything. Just leave the ratio as-is,
  24441. * and hope for the best... */
  24442. p_rarch->audio_driver_resampler->process(
  24443. p_rarch->audio_driver_resampler_data, &src_data);
  24444. #ifdef HAVE_AUDIOMIXER
  24445. if (p_rarch->audio_mixer_active)
  24446. {
  24447. bool override = true;
  24448. float mixer_gain = 0.0f;
  24449. bool audio_driver_mixer_mute_enable =
  24450. p_rarch->audio_driver_mixer_mute_enable;
  24451. if (!audio_driver_mixer_mute_enable)
  24452. {
  24453. if (p_rarch->audio_driver_mixer_volume_gain == 1.0f)
  24454. override = false;
  24455. mixer_gain =
  24456. p_rarch->audio_driver_mixer_volume_gain;
  24457. }
  24458. audio_mixer_mix(
  24459. p_rarch->audio_driver_output_samples_buf,
  24460. src_data.output_frames, mixer_gain, override);
  24461. }
  24462. #endif
  24463. {
  24464. const void *output_data = p_rarch->audio_driver_output_samples_buf;
  24465. unsigned output_frames = (unsigned)src_data.output_frames;
  24466. if (p_rarch->audio_driver_use_float)
  24467. output_frames *= sizeof(float);
  24468. else
  24469. {
  24470. convert_float_to_s16(p_rarch->audio_driver_output_samples_conv_buf,
  24471. (const float*)output_data, output_frames * 2);
  24472. output_data = p_rarch->audio_driver_output_samples_conv_buf;
  24473. output_frames *= sizeof(int16_t);
  24474. }
  24475. if (p_rarch->current_audio->write(
  24476. p_rarch->audio_driver_context_audio_data,
  24477. output_data, output_frames * 2) < 0)
  24478. p_rarch->audio_driver_active = false;
  24479. }
  24480. }
  24481. /**
  24482. * audio_driver_sample:
  24483. * @left : value of the left audio channel.
  24484. * @right : value of the right audio channel.
  24485. *
  24486. * Audio sample render callback function.
  24487. **/
  24488. static void audio_driver_sample(int16_t left, int16_t right)
  24489. {
  24490. struct rarch_state *p_rarch = &rarch_st;
  24491. if (p_rarch->audio_suspended)
  24492. return;
  24493. p_rarch->audio_driver_output_samples_conv_buf[p_rarch->audio_driver_data_ptr++] = left;
  24494. p_rarch->audio_driver_output_samples_conv_buf[p_rarch->audio_driver_data_ptr++] = right;
  24495. if (p_rarch->audio_driver_data_ptr < p_rarch->audio_driver_chunk_size)
  24496. return;
  24497. if ( p_rarch->recording_data &&
  24498. p_rarch->recording_driver &&
  24499. p_rarch->recording_driver->push_audio)
  24500. {
  24501. struct record_audio_data ffemu_data;
  24502. ffemu_data.data = p_rarch->audio_driver_output_samples_conv_buf;
  24503. ffemu_data.frames = p_rarch->audio_driver_data_ptr / 2;
  24504. p_rarch->recording_driver->push_audio(p_rarch->recording_data, &ffemu_data);
  24505. }
  24506. if (!(p_rarch->runloop_paused ||
  24507. !p_rarch->audio_driver_active ||
  24508. !p_rarch->audio_driver_output_samples_buf))
  24509. audio_driver_flush(
  24510. p_rarch,
  24511. p_rarch->configuration_settings->floats.slowmotion_ratio,
  24512. p_rarch->configuration_settings->bools.audio_fastforward_mute,
  24513. p_rarch->audio_driver_output_samples_conv_buf,
  24514. p_rarch->audio_driver_data_ptr,
  24515. p_rarch->runloop_slowmotion,
  24516. p_rarch->runloop_fastmotion);
  24517. p_rarch->audio_driver_data_ptr = 0;
  24518. }
  24519. #ifdef HAVE_MENU
  24520. static void audio_driver_menu_sample(void)
  24521. {
  24522. static int16_t samples_buf[1024] = {0};
  24523. struct rarch_state *p_rarch = &rarch_st;
  24524. struct retro_system_av_info *av_info = &p_rarch->video_driver_av_info;
  24525. const struct retro_system_timing *info =
  24526. (const struct retro_system_timing*)&av_info->timing;
  24527. unsigned sample_count = (info->sample_rate / info->fps) * 2;
  24528. bool check_flush = !(
  24529. p_rarch->runloop_paused ||
  24530. !p_rarch->audio_driver_active ||
  24531. !p_rarch->audio_driver_output_samples_buf);
  24532. while (sample_count > 1024)
  24533. {
  24534. if ( p_rarch->recording_data &&
  24535. p_rarch->recording_driver &&
  24536. p_rarch->recording_driver->push_audio)
  24537. {
  24538. struct record_audio_data ffemu_data;
  24539. ffemu_data.data = samples_buf;
  24540. ffemu_data.frames = 1024 / 2;
  24541. p_rarch->recording_driver->push_audio(
  24542. p_rarch->recording_data, &ffemu_data);
  24543. }
  24544. if (check_flush)
  24545. audio_driver_flush(
  24546. p_rarch,
  24547. p_rarch->configuration_settings->floats.slowmotion_ratio,
  24548. p_rarch->configuration_settings->bools.audio_fastforward_mute,
  24549. samples_buf,
  24550. 1024,
  24551. p_rarch->runloop_slowmotion,
  24552. p_rarch->runloop_fastmotion);
  24553. sample_count -= 1024;
  24554. }
  24555. if ( p_rarch->recording_data &&
  24556. p_rarch->recording_driver &&
  24557. p_rarch->recording_driver->push_audio)
  24558. {
  24559. struct record_audio_data ffemu_data;
  24560. ffemu_data.data = samples_buf;
  24561. ffemu_data.frames = sample_count / 2;
  24562. p_rarch->recording_driver->push_audio(
  24563. p_rarch->recording_data, &ffemu_data);
  24564. }
  24565. if (check_flush)
  24566. audio_driver_flush(
  24567. p_rarch,
  24568. p_rarch->configuration_settings->floats.slowmotion_ratio,
  24569. p_rarch->configuration_settings->bools.audio_fastforward_mute,
  24570. samples_buf,
  24571. sample_count,
  24572. p_rarch->runloop_slowmotion,
  24573. p_rarch->runloop_fastmotion);
  24574. }
  24575. #endif
  24576. /**
  24577. * audio_driver_sample_batch:
  24578. * @data : pointer to audio buffer.
  24579. * @frames : amount of audio frames to push.
  24580. *
  24581. * Batched audio sample render callback function.
  24582. *
  24583. * Returns: amount of frames sampled. Will be equal to @frames
  24584. * unless @frames exceeds (AUDIO_CHUNK_SIZE_NONBLOCKING / 2).
  24585. **/
  24586. static size_t audio_driver_sample_batch(const int16_t *data, size_t frames)
  24587. {
  24588. struct rarch_state *p_rarch = &rarch_st;
  24589. if (frames > (AUDIO_CHUNK_SIZE_NONBLOCKING >> 1))
  24590. frames = AUDIO_CHUNK_SIZE_NONBLOCKING >> 1;
  24591. if (p_rarch->audio_suspended)
  24592. return frames;
  24593. if ( p_rarch->recording_data &&
  24594. p_rarch->recording_driver &&
  24595. p_rarch->recording_driver->push_audio)
  24596. {
  24597. struct record_audio_data ffemu_data;
  24598. ffemu_data.data = data;
  24599. ffemu_data.frames = (frames << 1) / 2;
  24600. p_rarch->recording_driver->push_audio(
  24601. p_rarch->recording_data, &ffemu_data);
  24602. }
  24603. if (!(
  24604. p_rarch->runloop_paused ||
  24605. !p_rarch->audio_driver_active ||
  24606. !p_rarch->audio_driver_output_samples_buf))
  24607. audio_driver_flush(
  24608. p_rarch,
  24609. p_rarch->configuration_settings->floats.slowmotion_ratio,
  24610. p_rarch->configuration_settings->bools.audio_fastforward_mute,
  24611. data,
  24612. frames << 1,
  24613. p_rarch->runloop_slowmotion,
  24614. p_rarch->runloop_fastmotion);
  24615. return frames;
  24616. }
  24617. #ifdef HAVE_REWIND
  24618. /**
  24619. * audio_driver_sample_rewind:
  24620. * @left : value of the left audio channel.
  24621. * @right : value of the right audio channel.
  24622. *
  24623. * Audio sample render callback function (rewind version).
  24624. * This callback function will be used instead of
  24625. * audio_driver_sample when rewinding is activated.
  24626. **/
  24627. static void audio_driver_sample_rewind(int16_t left, int16_t right)
  24628. {
  24629. struct rarch_state *p_rarch = &rarch_st;
  24630. if (p_rarch->audio_driver_rewind_ptr == 0)
  24631. return;
  24632. p_rarch->audio_driver_rewind_buf[--p_rarch->audio_driver_rewind_ptr] = right;
  24633. p_rarch->audio_driver_rewind_buf[--p_rarch->audio_driver_rewind_ptr] = left;
  24634. }
  24635. /**
  24636. * audio_driver_sample_batch_rewind:
  24637. * @data : pointer to audio buffer.
  24638. * @frames : amount of audio frames to push.
  24639. *
  24640. * Batched audio sample render callback function (rewind version).
  24641. *
  24642. * This callback function will be used instead of
  24643. * audio_driver_sample_batch when rewinding is activated.
  24644. *
  24645. * Returns: amount of frames sampled. Will be equal to @frames
  24646. * unless @frames exceeds (AUDIO_CHUNK_SIZE_NONBLOCKING / 2).
  24647. **/
  24648. static size_t audio_driver_sample_batch_rewind(
  24649. const int16_t *data, size_t frames)
  24650. {
  24651. size_t i;
  24652. struct rarch_state *p_rarch = &rarch_st;
  24653. size_t samples = frames << 1;
  24654. for (i = 0; i < samples; i++)
  24655. {
  24656. if (p_rarch->audio_driver_rewind_ptr > 0)
  24657. p_rarch->audio_driver_rewind_buf[--p_rarch->audio_driver_rewind_ptr] = data[i];
  24658. }
  24659. return frames;
  24660. }
  24661. #endif
  24662. #ifdef HAVE_DSP_FILTER
  24663. void audio_driver_dsp_filter_free(void)
  24664. {
  24665. struct rarch_state *p_rarch = &rarch_st;
  24666. if (p_rarch->audio_driver_dsp)
  24667. retro_dsp_filter_free(p_rarch->audio_driver_dsp);
  24668. p_rarch->audio_driver_dsp = NULL;
  24669. }
  24670. bool audio_driver_dsp_filter_init(const char *device)
  24671. {
  24672. retro_dsp_filter_t *audio_driver_dsp = NULL;
  24673. struct rarch_state *p_rarch = &rarch_st;
  24674. struct string_list *plugs = NULL;
  24675. #if defined(HAVE_DYLIB) && !defined(HAVE_FILTERS_BUILTIN)
  24676. char basedir[PATH_MAX_LENGTH];
  24677. char ext_name[PATH_MAX_LENGTH];
  24678. basedir[0] = ext_name[0] = '\0';
  24679. fill_pathname_basedir(basedir, device, sizeof(basedir));
  24680. if (!frontend_driver_get_core_extension(ext_name, sizeof(ext_name)))
  24681. return false;
  24682. plugs = dir_list_new(basedir, ext_name, false, true, false, false);
  24683. if (!plugs)
  24684. return false;
  24685. #endif
  24686. audio_driver_dsp = retro_dsp_filter_new(
  24687. device, plugs, p_rarch->audio_driver_input);
  24688. if (!audio_driver_dsp)
  24689. return false;
  24690. p_rarch->audio_driver_dsp = audio_driver_dsp;
  24691. return true;
  24692. }
  24693. #endif
  24694. void audio_driver_set_buffer_size(size_t bufsize)
  24695. {
  24696. struct rarch_state *p_rarch = &rarch_st;
  24697. p_rarch->audio_driver_buffer_size = bufsize;
  24698. }
  24699. static float audio_driver_monitor_adjust_system_rates(
  24700. settings_t *settings,
  24701. struct retro_system_av_info *av_info)
  24702. {
  24703. bool vrr_runloop_enable = settings->bools.vrr_runloop_enable;
  24704. const float target_video_sync_rate =
  24705. settings->floats.video_refresh_rate / settings->uints.video_swap_interval;
  24706. float max_timing_skew = settings->floats.audio_max_timing_skew;
  24707. const struct retro_system_timing *info =
  24708. (const struct retro_system_timing*)&av_info->timing;
  24709. float timing_skew =
  24710. fabs(1.0f - info->fps / target_video_sync_rate);
  24711. float ret = info->sample_rate;
  24712. if (timing_skew <= max_timing_skew && !vrr_runloop_enable)
  24713. ret *= target_video_sync_rate / info->fps;
  24714. return ret;
  24715. }
  24716. #ifdef HAVE_REWIND
  24717. void audio_driver_setup_rewind(void)
  24718. {
  24719. unsigned i;
  24720. struct rarch_state *p_rarch = &rarch_st;
  24721. /* Push audio ready to be played. */
  24722. p_rarch->audio_driver_rewind_ptr = p_rarch->audio_driver_rewind_size;
  24723. for (i = 0; i < p_rarch->audio_driver_data_ptr; i += 2)
  24724. {
  24725. if (p_rarch->audio_driver_rewind_ptr > 0)
  24726. p_rarch->audio_driver_rewind_buf[
  24727. --p_rarch->audio_driver_rewind_ptr] =
  24728. p_rarch->audio_driver_output_samples_conv_buf[i + 1];
  24729. if (p_rarch->audio_driver_rewind_ptr > 0)
  24730. p_rarch->audio_driver_rewind_buf[--p_rarch->audio_driver_rewind_ptr] =
  24731. p_rarch->audio_driver_output_samples_conv_buf[i + 0];
  24732. }
  24733. p_rarch->audio_driver_data_ptr = 0;
  24734. }
  24735. #endif
  24736. bool audio_driver_get_devices_list(void **data)
  24737. {
  24738. struct rarch_state *p_rarch = &rarch_st;
  24739. struct string_list**ptr = (struct string_list**)data;
  24740. if (!ptr)
  24741. return false;
  24742. *ptr = p_rarch->audio_driver_devices_list;
  24743. return true;
  24744. }
  24745. #ifdef HAVE_AUDIOMIXER
  24746. bool audio_driver_mixer_extension_supported(const char *ext)
  24747. {
  24748. unsigned i;
  24749. struct string_list str_list;
  24750. union string_list_elem_attr attr;
  24751. bool ret = false;
  24752. attr.i = 0;
  24753. if (!string_list_initialize(&str_list))
  24754. return false;
  24755. #ifdef HAVE_STB_VORBIS
  24756. string_list_append(&str_list, "ogg", attr);
  24757. #endif
  24758. #ifdef HAVE_IBXM
  24759. string_list_append(&str_list, "mod", attr);
  24760. string_list_append(&str_list, "s3m", attr);
  24761. string_list_append(&str_list, "xm", attr);
  24762. #endif
  24763. #ifdef HAVE_DR_FLAC
  24764. string_list_append(&str_list, "flac", attr);
  24765. #endif
  24766. #ifdef HAVE_DR_MP3
  24767. string_list_append(&str_list, "mp3", attr);
  24768. #endif
  24769. string_list_append(&str_list, "wav", attr);
  24770. for (i = 0; i < str_list.size; i++)
  24771. {
  24772. const char *str_ext = str_list.elems[i].data;
  24773. if (string_is_equal_noncase(str_ext, ext))
  24774. {
  24775. ret = true;
  24776. break;
  24777. }
  24778. }
  24779. string_list_deinitialize(&str_list);
  24780. return ret;
  24781. }
  24782. static int audio_mixer_find_index(
  24783. struct rarch_state *p_rarch,
  24784. audio_mixer_sound_t *sound)
  24785. {
  24786. unsigned i;
  24787. for (i = 0; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
  24788. {
  24789. audio_mixer_sound_t *handle = p_rarch->audio_mixer_streams[i].handle;
  24790. if (handle == sound)
  24791. return i;
  24792. }
  24793. return -1;
  24794. }
  24795. static void audio_mixer_play_stop_cb(
  24796. audio_mixer_sound_t *sound, unsigned reason)
  24797. {
  24798. struct rarch_state *p_rarch = &rarch_st;
  24799. int idx = audio_mixer_find_index(p_rarch, sound);
  24800. switch (reason)
  24801. {
  24802. case AUDIO_MIXER_SOUND_FINISHED:
  24803. audio_mixer_destroy(sound);
  24804. if (idx >= 0)
  24805. {
  24806. unsigned i = (unsigned)idx;
  24807. if (!string_is_empty(p_rarch->audio_mixer_streams[i].name))
  24808. free(p_rarch->audio_mixer_streams[i].name);
  24809. p_rarch->audio_mixer_streams[i].name = NULL;
  24810. p_rarch->audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
  24811. p_rarch->audio_mixer_streams[i].volume = 0.0f;
  24812. p_rarch->audio_mixer_streams[i].buf = NULL;
  24813. p_rarch->audio_mixer_streams[i].stop_cb = NULL;
  24814. p_rarch->audio_mixer_streams[i].handle = NULL;
  24815. p_rarch->audio_mixer_streams[i].voice = NULL;
  24816. }
  24817. break;
  24818. case AUDIO_MIXER_SOUND_STOPPED:
  24819. break;
  24820. case AUDIO_MIXER_SOUND_REPEATED:
  24821. break;
  24822. }
  24823. }
  24824. static void audio_mixer_menu_stop_cb(
  24825. audio_mixer_sound_t *sound, unsigned reason)
  24826. {
  24827. struct rarch_state *p_rarch = &rarch_st;
  24828. int idx = audio_mixer_find_index(p_rarch, sound);
  24829. switch (reason)
  24830. {
  24831. case AUDIO_MIXER_SOUND_FINISHED:
  24832. if (idx >= 0)
  24833. {
  24834. unsigned i = (unsigned)idx;
  24835. p_rarch->audio_mixer_streams[i].state = AUDIO_STREAM_STATE_STOPPED;
  24836. p_rarch->audio_mixer_streams[i].volume = 0.0f;
  24837. }
  24838. break;
  24839. case AUDIO_MIXER_SOUND_STOPPED:
  24840. break;
  24841. case AUDIO_MIXER_SOUND_REPEATED:
  24842. break;
  24843. }
  24844. }
  24845. static void audio_mixer_play_stop_sequential_cb(
  24846. audio_mixer_sound_t *sound, unsigned reason)
  24847. {
  24848. struct rarch_state *p_rarch = &rarch_st;
  24849. int idx = audio_mixer_find_index(p_rarch, sound);
  24850. switch (reason)
  24851. {
  24852. case AUDIO_MIXER_SOUND_FINISHED:
  24853. audio_mixer_destroy(sound);
  24854. if (idx >= 0)
  24855. {
  24856. unsigned i = (unsigned)idx;
  24857. if (!string_is_empty(p_rarch->audio_mixer_streams[i].name))
  24858. free(p_rarch->audio_mixer_streams[i].name);
  24859. if (i < AUDIO_MIXER_MAX_STREAMS)
  24860. p_rarch->audio_mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_USER;
  24861. else
  24862. p_rarch->audio_mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_SYSTEM;
  24863. p_rarch->audio_mixer_streams[i].name = NULL;
  24864. p_rarch->audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
  24865. p_rarch->audio_mixer_streams[i].volume = 0.0f;
  24866. p_rarch->audio_mixer_streams[i].buf = NULL;
  24867. p_rarch->audio_mixer_streams[i].stop_cb = NULL;
  24868. p_rarch->audio_mixer_streams[i].handle = NULL;
  24869. p_rarch->audio_mixer_streams[i].voice = NULL;
  24870. i++;
  24871. for (; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
  24872. {
  24873. if (p_rarch->audio_mixer_streams[i].state
  24874. == AUDIO_STREAM_STATE_STOPPED)
  24875. {
  24876. audio_driver_mixer_play_stream_sequential(i);
  24877. break;
  24878. }
  24879. }
  24880. }
  24881. break;
  24882. case AUDIO_MIXER_SOUND_STOPPED:
  24883. break;
  24884. case AUDIO_MIXER_SOUND_REPEATED:
  24885. break;
  24886. }
  24887. }
  24888. static bool audio_driver_mixer_get_free_stream_slot(
  24889. unsigned *id, enum audio_mixer_stream_type type)
  24890. {
  24891. unsigned i = AUDIO_MIXER_MAX_STREAMS;
  24892. unsigned count = AUDIO_MIXER_MAX_SYSTEM_STREAMS;
  24893. struct rarch_state *p_rarch = &rarch_st;
  24894. if (type == AUDIO_STREAM_TYPE_USER)
  24895. {
  24896. i = 0;
  24897. count = AUDIO_MIXER_MAX_STREAMS;
  24898. }
  24899. for (; i < count; i++)
  24900. {
  24901. if (p_rarch->audio_mixer_streams[i].state == AUDIO_STREAM_STATE_NONE)
  24902. {
  24903. *id = i;
  24904. return true;
  24905. }
  24906. }
  24907. return false;
  24908. }
  24909. bool audio_driver_mixer_add_stream(audio_mixer_stream_params_t *params)
  24910. {
  24911. struct rarch_state *p_rarch = &rarch_st;
  24912. unsigned free_slot = 0;
  24913. audio_mixer_voice_t *voice = NULL;
  24914. audio_mixer_sound_t *handle = NULL;
  24915. audio_mixer_stop_cb_t stop_cb = audio_mixer_play_stop_cb;
  24916. bool looped = false;
  24917. void *buf = NULL;
  24918. if (params->stream_type == AUDIO_STREAM_TYPE_NONE)
  24919. return false;
  24920. switch (params->slot_selection_type)
  24921. {
  24922. case AUDIO_MIXER_SLOT_SELECTION_MANUAL:
  24923. free_slot = params->slot_selection_idx;
  24924. break;
  24925. case AUDIO_MIXER_SLOT_SELECTION_AUTOMATIC:
  24926. default:
  24927. if (!audio_driver_mixer_get_free_stream_slot(
  24928. &free_slot, params->stream_type))
  24929. return false;
  24930. break;
  24931. }
  24932. if (params->state == AUDIO_STREAM_STATE_NONE)
  24933. return false;
  24934. buf = malloc(params->bufsize);
  24935. if (!buf)
  24936. return false;
  24937. memcpy(buf, params->buf, params->bufsize);
  24938. switch (params->type)
  24939. {
  24940. case AUDIO_MIXER_TYPE_WAV:
  24941. handle = audio_mixer_load_wav(buf, (int32_t)params->bufsize);
  24942. /* WAV is a special case - input buffer is not
  24943. * free()'d when sound playback is complete (it is
  24944. * converted to a PCM buffer, which is free()'d instead),
  24945. * so have to do it here */
  24946. free(buf);
  24947. buf = NULL;
  24948. break;
  24949. case AUDIO_MIXER_TYPE_OGG:
  24950. handle = audio_mixer_load_ogg(buf, (int32_t)params->bufsize);
  24951. break;
  24952. case AUDIO_MIXER_TYPE_MOD:
  24953. handle = audio_mixer_load_mod(buf, (int32_t)params->bufsize);
  24954. break;
  24955. case AUDIO_MIXER_TYPE_FLAC:
  24956. #ifdef HAVE_DR_FLAC
  24957. handle = audio_mixer_load_flac(buf, (int32_t)params->bufsize);
  24958. #endif
  24959. break;
  24960. case AUDIO_MIXER_TYPE_MP3:
  24961. #ifdef HAVE_DR_MP3
  24962. handle = audio_mixer_load_mp3(buf, (int32_t)params->bufsize);
  24963. #endif
  24964. break;
  24965. case AUDIO_MIXER_TYPE_NONE:
  24966. break;
  24967. }
  24968. if (!handle)
  24969. {
  24970. free(buf);
  24971. return false;
  24972. }
  24973. switch (params->state)
  24974. {
  24975. case AUDIO_STREAM_STATE_PLAYING_LOOPED:
  24976. looped = true;
  24977. voice = audio_mixer_play(handle, looped, params->volume, stop_cb);
  24978. break;
  24979. case AUDIO_STREAM_STATE_PLAYING:
  24980. voice = audio_mixer_play(handle, looped, params->volume, stop_cb);
  24981. break;
  24982. case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
  24983. stop_cb = audio_mixer_play_stop_sequential_cb;
  24984. voice = audio_mixer_play(handle, looped, params->volume, stop_cb);
  24985. break;
  24986. default:
  24987. break;
  24988. }
  24989. p_rarch->audio_mixer_active = true;
  24990. p_rarch->audio_mixer_streams[free_slot].name =
  24991. !string_is_empty(params->basename) ? strdup(params->basename) : NULL;
  24992. p_rarch->audio_mixer_streams[free_slot].buf = buf;
  24993. p_rarch->audio_mixer_streams[free_slot].handle = handle;
  24994. p_rarch->audio_mixer_streams[free_slot].voice = voice;
  24995. p_rarch->audio_mixer_streams[free_slot].stream_type = params->stream_type;
  24996. p_rarch->audio_mixer_streams[free_slot].type = params->type;
  24997. p_rarch->audio_mixer_streams[free_slot].state = params->state;
  24998. p_rarch->audio_mixer_streams[free_slot].volume = params->volume;
  24999. p_rarch->audio_mixer_streams[free_slot].stop_cb = stop_cb;
  25000. return true;
  25001. }
  25002. enum audio_mixer_state audio_driver_mixer_get_stream_state(unsigned i)
  25003. {
  25004. struct rarch_state *p_rarch = &rarch_st;
  25005. if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
  25006. return AUDIO_STREAM_STATE_NONE;
  25007. return p_rarch->audio_mixer_streams[i].state;
  25008. }
  25009. static void audio_driver_mixer_play_stream_internal(
  25010. struct rarch_state *p_rarch,
  25011. unsigned i, unsigned type)
  25012. {
  25013. if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
  25014. return;
  25015. switch (p_rarch->audio_mixer_streams[i].state)
  25016. {
  25017. case AUDIO_STREAM_STATE_STOPPED:
  25018. p_rarch->audio_mixer_streams[i].voice =
  25019. audio_mixer_play(p_rarch->audio_mixer_streams[i].handle,
  25020. (type == AUDIO_STREAM_STATE_PLAYING_LOOPED) ? true : false,
  25021. 1.0f, p_rarch->audio_mixer_streams[i].stop_cb);
  25022. p_rarch->audio_mixer_streams[i].state = (enum audio_mixer_state)type;
  25023. break;
  25024. case AUDIO_STREAM_STATE_PLAYING:
  25025. case AUDIO_STREAM_STATE_PLAYING_LOOPED:
  25026. case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
  25027. case AUDIO_STREAM_STATE_NONE:
  25028. break;
  25029. }
  25030. }
  25031. static void audio_driver_load_menu_bgm_callback(retro_task_t *task,
  25032. void *task_data, void *user_data, const char *error)
  25033. {
  25034. bool contentless = false;
  25035. bool is_inited = false;
  25036. content_get_status(&contentless, &is_inited);
  25037. if (!is_inited)
  25038. audio_driver_mixer_play_menu_sound_looped(AUDIO_MIXER_SYSTEM_SLOT_BGM);
  25039. }
  25040. void audio_driver_load_system_sounds(void)
  25041. {
  25042. char sounds_path[PATH_MAX_LENGTH];
  25043. char sounds_fallback_path[PATH_MAX_LENGTH];
  25044. char basename_noext[PATH_MAX_LENGTH];
  25045. struct rarch_state *p_rarch = &rarch_st;
  25046. settings_t *settings = p_rarch->configuration_settings;
  25047. const char *dir_assets = settings->paths.directory_assets;
  25048. const bool audio_enable_menu = settings->bools.audio_enable_menu;
  25049. const bool audio_enable_menu_ok = audio_enable_menu && settings->bools.audio_enable_menu_ok;
  25050. const bool audio_enable_menu_cancel = audio_enable_menu && settings->bools.audio_enable_menu_cancel;
  25051. const bool audio_enable_menu_notice = audio_enable_menu && settings->bools.audio_enable_menu_notice;
  25052. const bool audio_enable_menu_bgm = audio_enable_menu && settings->bools.audio_enable_menu_bgm;
  25053. const bool audio_enable_cheevo_unlock = settings->bools.cheevos_unlock_sound_enable;
  25054. const char *path_ok = NULL;
  25055. const char *path_cancel = NULL;
  25056. const char *path_notice = NULL;
  25057. const char *path_bgm = NULL;
  25058. const char *path_cheevo_unlock = NULL;
  25059. struct string_list *list = NULL;
  25060. struct string_list *list_fallback = NULL;
  25061. unsigned i = 0;
  25062. if (!audio_enable_menu && !audio_enable_cheevo_unlock)
  25063. goto end;
  25064. sounds_path[0] = sounds_fallback_path[0] =
  25065. basename_noext[0] ='\0';
  25066. fill_pathname_join(
  25067. sounds_fallback_path,
  25068. dir_assets,
  25069. "sounds",
  25070. sizeof(sounds_fallback_path));
  25071. fill_pathname_application_special(
  25072. sounds_path,
  25073. sizeof(sounds_path),
  25074. APPLICATION_SPECIAL_DIRECTORY_ASSETS_SOUNDS);
  25075. list = dir_list_new(sounds_path, MENU_SOUND_FORMATS, false, false, false, false);
  25076. list_fallback = dir_list_new(sounds_fallback_path, MENU_SOUND_FORMATS, false, false, false, false);
  25077. if (!list)
  25078. {
  25079. list = list_fallback;
  25080. list_fallback = NULL;
  25081. }
  25082. if (!list || list->size == 0)
  25083. goto end;
  25084. if (list_fallback && list_fallback->size > 0)
  25085. {
  25086. for (i = 0; i < list_fallback->size; i++)
  25087. {
  25088. if (list->size == 0 || !string_list_find_elem(list, list_fallback->elems[i].data))
  25089. {
  25090. union string_list_elem_attr attr = {0};
  25091. string_list_append(list, list_fallback->elems[i].data, attr);
  25092. }
  25093. }
  25094. }
  25095. for (i = 0; i < list->size; i++)
  25096. {
  25097. const char *path = list->elems[i].data;
  25098. const char *ext = path_get_extension(path);
  25099. if (audio_driver_mixer_extension_supported(ext))
  25100. {
  25101. basename_noext[0] = '\0';
  25102. fill_pathname_base_noext(basename_noext, path, sizeof(basename_noext));
  25103. if (string_is_equal_noncase(basename_noext, "ok"))
  25104. path_ok = path;
  25105. else if (string_is_equal_noncase(basename_noext, "cancel"))
  25106. path_cancel = path;
  25107. else if (string_is_equal_noncase(basename_noext, "notice"))
  25108. path_notice = path;
  25109. else if (string_is_equal_noncase(basename_noext, "bgm"))
  25110. path_bgm = path;
  25111. else if (string_is_equal_noncase(basename_noext, "unlock"))
  25112. path_cheevo_unlock = path;
  25113. }
  25114. }
  25115. if (path_ok && audio_enable_menu_ok)
  25116. task_push_audio_mixer_load(path_ok, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_OK);
  25117. if (path_cancel && audio_enable_menu_cancel)
  25118. task_push_audio_mixer_load(path_cancel, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_CANCEL);
  25119. if (path_notice && audio_enable_menu_notice)
  25120. task_push_audio_mixer_load(path_notice, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_NOTICE);
  25121. if (path_bgm && audio_enable_menu_bgm)
  25122. task_push_audio_mixer_load(path_bgm, audio_driver_load_menu_bgm_callback, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_BGM);
  25123. if (path_cheevo_unlock && audio_enable_cheevo_unlock)
  25124. task_push_audio_mixer_load(path_cheevo_unlock, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_ACHIEVEMENT_UNLOCK);
  25125. end:
  25126. if (list)
  25127. string_list_free(list);
  25128. if (list_fallback)
  25129. string_list_free(list_fallback);
  25130. }
  25131. void audio_driver_mixer_play_stream(unsigned i)
  25132. {
  25133. struct rarch_state *p_rarch = &rarch_st;
  25134. p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_play_stop_cb;
  25135. audio_driver_mixer_play_stream_internal(p_rarch,
  25136. i, AUDIO_STREAM_STATE_PLAYING);
  25137. }
  25138. void audio_driver_mixer_play_menu_sound_looped(unsigned i)
  25139. {
  25140. struct rarch_state *p_rarch = &rarch_st;
  25141. p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_menu_stop_cb;
  25142. audio_driver_mixer_play_stream_internal(p_rarch,
  25143. i, AUDIO_STREAM_STATE_PLAYING_LOOPED);
  25144. }
  25145. void audio_driver_mixer_play_menu_sound(unsigned i)
  25146. {
  25147. struct rarch_state *p_rarch = &rarch_st;
  25148. p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_menu_stop_cb;
  25149. audio_driver_mixer_play_stream_internal(p_rarch,
  25150. i, AUDIO_STREAM_STATE_PLAYING);
  25151. }
  25152. void audio_driver_mixer_play_stream_looped(unsigned i)
  25153. {
  25154. struct rarch_state *p_rarch = &rarch_st;
  25155. p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_play_stop_cb;
  25156. audio_driver_mixer_play_stream_internal(p_rarch,
  25157. i, AUDIO_STREAM_STATE_PLAYING_LOOPED);
  25158. }
  25159. void audio_driver_mixer_play_stream_sequential(unsigned i)
  25160. {
  25161. struct rarch_state *p_rarch = &rarch_st;
  25162. p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_play_stop_sequential_cb;
  25163. audio_driver_mixer_play_stream_internal(p_rarch,
  25164. i, AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL);
  25165. }
  25166. float audio_driver_mixer_get_stream_volume(unsigned i)
  25167. {
  25168. struct rarch_state *p_rarch = &rarch_st;
  25169. if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
  25170. return 0.0f;
  25171. return p_rarch->audio_mixer_streams[i].volume;
  25172. }
  25173. void audio_driver_mixer_set_stream_volume(unsigned i, float vol)
  25174. {
  25175. audio_mixer_voice_t *voice = NULL;
  25176. struct rarch_state *p_rarch = &rarch_st;
  25177. if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
  25178. return;
  25179. p_rarch->audio_mixer_streams[i].volume = vol;
  25180. voice =
  25181. p_rarch->audio_mixer_streams[i].voice;
  25182. if (voice)
  25183. audio_mixer_voice_set_volume(voice, DB_TO_GAIN(vol));
  25184. }
  25185. void audio_driver_mixer_stop_stream(unsigned i)
  25186. {
  25187. bool set_state = false;
  25188. struct rarch_state *p_rarch = &rarch_st;
  25189. if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
  25190. return;
  25191. switch (p_rarch->audio_mixer_streams[i].state)
  25192. {
  25193. case AUDIO_STREAM_STATE_PLAYING:
  25194. case AUDIO_STREAM_STATE_PLAYING_LOOPED:
  25195. case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
  25196. set_state = true;
  25197. break;
  25198. case AUDIO_STREAM_STATE_STOPPED:
  25199. case AUDIO_STREAM_STATE_NONE:
  25200. break;
  25201. }
  25202. if (set_state)
  25203. {
  25204. audio_mixer_voice_t *voice = p_rarch->audio_mixer_streams[i].voice;
  25205. if (voice)
  25206. audio_mixer_stop(voice);
  25207. p_rarch->audio_mixer_streams[i].state = AUDIO_STREAM_STATE_STOPPED;
  25208. p_rarch->audio_mixer_streams[i].volume = 1.0f;
  25209. }
  25210. }
  25211. void audio_driver_mixer_remove_stream(unsigned i)
  25212. {
  25213. bool destroy = false;
  25214. struct rarch_state *p_rarch = &rarch_st;
  25215. if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
  25216. return;
  25217. switch (p_rarch->audio_mixer_streams[i].state)
  25218. {
  25219. case AUDIO_STREAM_STATE_PLAYING:
  25220. case AUDIO_STREAM_STATE_PLAYING_LOOPED:
  25221. case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
  25222. audio_driver_mixer_stop_stream(i);
  25223. destroy = true;
  25224. break;
  25225. case AUDIO_STREAM_STATE_STOPPED:
  25226. destroy = true;
  25227. break;
  25228. case AUDIO_STREAM_STATE_NONE:
  25229. break;
  25230. }
  25231. if (destroy)
  25232. {
  25233. audio_mixer_sound_t *handle = p_rarch->audio_mixer_streams[i].handle;
  25234. if (handle)
  25235. audio_mixer_destroy(handle);
  25236. if (!string_is_empty(p_rarch->audio_mixer_streams[i].name))
  25237. free(p_rarch->audio_mixer_streams[i].name);
  25238. p_rarch->audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
  25239. p_rarch->audio_mixer_streams[i].stop_cb = NULL;
  25240. p_rarch->audio_mixer_streams[i].volume = 0.0f;
  25241. p_rarch->audio_mixer_streams[i].handle = NULL;
  25242. p_rarch->audio_mixer_streams[i].voice = NULL;
  25243. p_rarch->audio_mixer_streams[i].name = NULL;
  25244. }
  25245. }
  25246. #endif
  25247. bool audio_driver_enable_callback(void)
  25248. {
  25249. struct rarch_state *p_rarch = &rarch_st;
  25250. if (!p_rarch->audio_callback.callback)
  25251. return false;
  25252. if (p_rarch->audio_callback.set_state)
  25253. p_rarch->audio_callback.set_state(true);
  25254. return true;
  25255. }
  25256. bool audio_driver_disable_callback(void)
  25257. {
  25258. struct rarch_state *p_rarch = &rarch_st;
  25259. if (!p_rarch->audio_callback.callback)
  25260. return false;
  25261. if (p_rarch->audio_callback.set_state)
  25262. p_rarch->audio_callback.set_state(false);
  25263. return true;
  25264. }
  25265. bool audio_driver_callback(void)
  25266. {
  25267. struct rarch_state *p_rarch = &rarch_st;
  25268. settings_t *settings = p_rarch->configuration_settings;
  25269. bool core_paused = p_rarch->runloop_paused || (settings->bools.menu_pause_libretro && p_rarch->menu_driver_alive);
  25270. if (!p_rarch->audio_callback.callback)
  25271. return false;
  25272. if (!core_paused && p_rarch->audio_callback.callback)
  25273. p_rarch->audio_callback.callback();
  25274. return true;
  25275. }
  25276. bool audio_driver_has_callback(void)
  25277. {
  25278. struct rarch_state *p_rarch = &rarch_st;
  25279. if (p_rarch->audio_callback.callback)
  25280. return true;
  25281. return false;
  25282. }
  25283. #ifdef HAVE_AUDIOMIXER
  25284. bool audio_driver_mixer_toggle_mute(void)
  25285. {
  25286. struct rarch_state *p_rarch = &rarch_st;
  25287. p_rarch->audio_driver_mixer_mute_enable =
  25288. !p_rarch->audio_driver_mixer_mute_enable;
  25289. return true;
  25290. }
  25291. #endif
  25292. static INLINE bool audio_driver_alive(struct rarch_state *p_rarch)
  25293. {
  25294. if ( p_rarch->current_audio
  25295. && p_rarch->current_audio->alive
  25296. && p_rarch->audio_driver_context_audio_data)
  25297. return p_rarch->current_audio->alive(p_rarch->audio_driver_context_audio_data);
  25298. return false;
  25299. }
  25300. static bool audio_driver_start(struct rarch_state *p_rarch,
  25301. bool is_shutdown)
  25302. {
  25303. if (!p_rarch->current_audio || !p_rarch->current_audio->start
  25304. || !p_rarch->audio_driver_context_audio_data)
  25305. goto error;
  25306. if (!p_rarch->current_audio->start(
  25307. p_rarch->audio_driver_context_audio_data, is_shutdown))
  25308. goto error;
  25309. return true;
  25310. error:
  25311. RARCH_ERR("%s\n",
  25312. msg_hash_to_str(MSG_FAILED_TO_START_AUDIO_DRIVER));
  25313. p_rarch->audio_driver_active = false;
  25314. return false;
  25315. }
  25316. static bool audio_driver_stop(struct rarch_state *p_rarch)
  25317. {
  25318. if ( !p_rarch->current_audio
  25319. || !p_rarch->current_audio->stop
  25320. || !p_rarch->audio_driver_context_audio_data
  25321. || !audio_driver_alive(p_rarch)
  25322. )
  25323. return false;
  25324. return p_rarch->current_audio->stop(
  25325. p_rarch->audio_driver_context_audio_data);
  25326. }
  25327. #ifdef HAVE_REWIND
  25328. void audio_driver_frame_is_reverse(void)
  25329. {
  25330. struct rarch_state *p_rarch = &rarch_st;
  25331. /* We just rewound. Flush rewind audio buffer. */
  25332. if ( p_rarch->recording_data &&
  25333. p_rarch->recording_driver &&
  25334. p_rarch->recording_driver->push_audio)
  25335. {
  25336. struct record_audio_data ffemu_data;
  25337. ffemu_data.data = p_rarch->audio_driver_rewind_buf +
  25338. p_rarch->audio_driver_rewind_ptr;
  25339. ffemu_data.frames = (p_rarch->audio_driver_rewind_size -
  25340. p_rarch->audio_driver_rewind_ptr) / 2;
  25341. p_rarch->recording_driver->push_audio(p_rarch->recording_data, &ffemu_data);
  25342. }
  25343. if (!(
  25344. p_rarch->runloop_paused ||
  25345. !p_rarch->audio_driver_active ||
  25346. !p_rarch->audio_driver_output_samples_buf))
  25347. audio_driver_flush(
  25348. p_rarch,
  25349. p_rarch->configuration_settings->floats.slowmotion_ratio,
  25350. p_rarch->configuration_settings->bools.audio_fastforward_mute,
  25351. p_rarch->audio_driver_rewind_buf +
  25352. p_rarch->audio_driver_rewind_ptr,
  25353. p_rarch->audio_driver_rewind_size -
  25354. p_rarch->audio_driver_rewind_ptr,
  25355. p_rarch->runloop_slowmotion,
  25356. p_rarch->runloop_fastmotion);
  25357. }
  25358. #endif
  25359. void audio_set_float(enum audio_action action, float val)
  25360. {
  25361. struct rarch_state *p_rarch = &rarch_st;
  25362. switch (action)
  25363. {
  25364. case AUDIO_ACTION_VOLUME_GAIN:
  25365. p_rarch->audio_driver_volume_gain = DB_TO_GAIN(val);
  25366. break;
  25367. case AUDIO_ACTION_MIXER_VOLUME_GAIN:
  25368. #ifdef HAVE_AUDIOMIXER
  25369. p_rarch->audio_driver_mixer_volume_gain = DB_TO_GAIN(val);
  25370. #endif
  25371. break;
  25372. case AUDIO_ACTION_RATE_CONTROL_DELTA:
  25373. p_rarch->audio_driver_rate_control_delta = val;
  25374. break;
  25375. case AUDIO_ACTION_NONE:
  25376. default:
  25377. break;
  25378. }
  25379. }
  25380. float *audio_get_float_ptr(enum audio_action action)
  25381. {
  25382. struct rarch_state *p_rarch = &rarch_st;
  25383. switch (action)
  25384. {
  25385. case AUDIO_ACTION_RATE_CONTROL_DELTA:
  25386. return &p_rarch->audio_driver_rate_control_delta;
  25387. case AUDIO_ACTION_NONE:
  25388. default:
  25389. break;
  25390. }
  25391. return NULL;
  25392. }
  25393. bool *audio_get_bool_ptr(enum audio_action action)
  25394. {
  25395. struct rarch_state *p_rarch = &rarch_st;
  25396. switch (action)
  25397. {
  25398. case AUDIO_ACTION_MIXER_MUTE_ENABLE:
  25399. #ifdef HAVE_AUDIOMIXER
  25400. return &p_rarch->audio_driver_mixer_mute_enable;
  25401. #else
  25402. break;
  25403. #endif
  25404. case AUDIO_ACTION_MUTE_ENABLE:
  25405. return &p_rarch->audio_driver_mute_enable;
  25406. case AUDIO_ACTION_NONE:
  25407. default:
  25408. break;
  25409. }
  25410. return NULL;
  25411. }
  25412. /* VIDEO */
  25413. const char *video_display_server_get_ident(void)
  25414. {
  25415. if (!current_display_server)
  25416. return FILE_PATH_UNKNOWN;
  25417. return current_display_server->ident;
  25418. }
  25419. void* video_display_server_init(enum rarch_display_type type)
  25420. {
  25421. struct rarch_state *p_rarch = &rarch_st;
  25422. video_display_server_destroy();
  25423. switch (type)
  25424. {
  25425. case RARCH_DISPLAY_WIN32:
  25426. #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
  25427. current_display_server = &dispserv_win32;
  25428. #endif
  25429. break;
  25430. case RARCH_DISPLAY_X11:
  25431. #if defined(HAVE_X11)
  25432. current_display_server = &dispserv_x11;
  25433. #endif
  25434. break;
  25435. default:
  25436. #if defined(ANDROID)
  25437. current_display_server = &dispserv_android;
  25438. #else
  25439. current_display_server = &dispserv_null;
  25440. #endif
  25441. break;
  25442. }
  25443. if (current_display_server)
  25444. {
  25445. if (current_display_server->init)
  25446. p_rarch->current_display_server_data = current_display_server->init();
  25447. if (!string_is_empty(current_display_server->ident))
  25448. {
  25449. RARCH_LOG("[Video]: Found display server: %s\n",
  25450. current_display_server->ident);
  25451. }
  25452. }
  25453. p_rarch->initial_screen_orientation =
  25454. video_display_server_get_screen_orientation();
  25455. p_rarch->current_screen_orientation =
  25456. p_rarch->initial_screen_orientation;
  25457. return p_rarch->current_display_server_data;
  25458. }
  25459. void video_display_server_destroy(void)
  25460. {
  25461. struct rarch_state *p_rarch = &rarch_st;
  25462. const enum rotation initial_screen_orientation = p_rarch->initial_screen_orientation;
  25463. const enum rotation current_screen_orientation = p_rarch->current_screen_orientation;
  25464. if (initial_screen_orientation != current_screen_orientation)
  25465. video_display_server_set_screen_orientation(initial_screen_orientation);
  25466. if (current_display_server)
  25467. if (p_rarch->current_display_server_data)
  25468. current_display_server->destroy(p_rarch->current_display_server_data);
  25469. }
  25470. bool video_display_server_set_window_opacity(unsigned opacity)
  25471. {
  25472. struct rarch_state *p_rarch = &rarch_st;
  25473. if (current_display_server && current_display_server->set_window_opacity)
  25474. return current_display_server->set_window_opacity(
  25475. p_rarch->current_display_server_data, opacity);
  25476. return false;
  25477. }
  25478. bool video_display_server_set_window_progress(int progress, bool finished)
  25479. {
  25480. struct rarch_state *p_rarch = &rarch_st;
  25481. if (current_display_server && current_display_server->set_window_progress)
  25482. return current_display_server->set_window_progress(
  25483. p_rarch->current_display_server_data, progress, finished);
  25484. return false;
  25485. }
  25486. bool video_display_server_set_window_decorations(bool on)
  25487. {
  25488. struct rarch_state *p_rarch = &rarch_st;
  25489. if (current_display_server && current_display_server->set_window_decorations)
  25490. return current_display_server->set_window_decorations(
  25491. p_rarch->current_display_server_data, on);
  25492. return false;
  25493. }
  25494. bool video_display_server_set_resolution(unsigned width, unsigned height,
  25495. int int_hz, float hz, int center, int monitor_index, int xoffset, int padjust)
  25496. {
  25497. struct rarch_state *p_rarch = &rarch_st;
  25498. if (current_display_server && current_display_server->set_resolution)
  25499. return current_display_server->set_resolution(
  25500. p_rarch->current_display_server_data, width, height, int_hz,
  25501. hz, center, monitor_index, xoffset, padjust);
  25502. return false;
  25503. }
  25504. bool video_display_server_has_resolution_list(void)
  25505. {
  25506. return (current_display_server
  25507. && current_display_server->get_resolution_list);
  25508. }
  25509. void *video_display_server_get_resolution_list(unsigned *size)
  25510. {
  25511. struct rarch_state *p_rarch = &rarch_st;
  25512. if (video_display_server_has_resolution_list())
  25513. return current_display_server->get_resolution_list(
  25514. p_rarch->current_display_server_data, size);
  25515. return NULL;
  25516. }
  25517. const char *video_display_server_get_output_options(void)
  25518. {
  25519. struct rarch_state *p_rarch = &rarch_st;
  25520. if (current_display_server && current_display_server->get_output_options)
  25521. return current_display_server->get_output_options(p_rarch->current_display_server_data);
  25522. return NULL;
  25523. }
  25524. void video_display_server_set_screen_orientation(enum rotation rotation)
  25525. {
  25526. if (current_display_server && current_display_server->set_screen_orientation)
  25527. {
  25528. struct rarch_state *p_rarch = &rarch_st;
  25529. RARCH_LOG("[Video]: Setting screen orientation to %d.\n", rotation);
  25530. p_rarch->current_screen_orientation = rotation;
  25531. current_display_server->set_screen_orientation(p_rarch->current_display_server_data, rotation);
  25532. }
  25533. }
  25534. bool video_display_server_can_set_screen_orientation(void)
  25535. {
  25536. return (current_display_server && current_display_server->set_screen_orientation);
  25537. }
  25538. enum rotation video_display_server_get_screen_orientation(void)
  25539. {
  25540. struct rarch_state *p_rarch = &rarch_st;
  25541. if (current_display_server && current_display_server->get_screen_orientation)
  25542. return current_display_server->get_screen_orientation(p_rarch->current_display_server_data);
  25543. return ORIENTATION_NORMAL;
  25544. }
  25545. bool video_display_server_get_flags(gfx_ctx_flags_t *flags)
  25546. {
  25547. struct rarch_state *p_rarch = &rarch_st;
  25548. if (!flags || !current_display_server || !current_display_server->get_flags)
  25549. return false;
  25550. flags->flags = current_display_server->get_flags(
  25551. p_rarch->current_display_server_data);
  25552. return true;
  25553. }
  25554. bool video_driver_started_fullscreen(void)
  25555. {
  25556. struct rarch_state *p_rarch = &rarch_st;
  25557. return p_rarch->video_started_fullscreen;
  25558. }
  25559. /* Stub functions */
  25560. static bool get_metrics_null(void *data, enum display_metric_types type,
  25561. float *value) { return false; }
  25562. /**
  25563. * config_get_video_driver_options:
  25564. *
  25565. * Get an enumerated list of all video driver names, separated by '|'.
  25566. *
  25567. * Returns: string listing of all video driver names, separated by '|'.
  25568. **/
  25569. const char* config_get_video_driver_options(void)
  25570. {
  25571. return char_list_new_special(STRING_LIST_VIDEO_DRIVERS, NULL);
  25572. }
  25573. bool video_driver_is_threaded(void)
  25574. {
  25575. #ifdef HAVE_THREADS
  25576. struct rarch_state *p_rarch = &rarch_st;
  25577. #endif
  25578. return VIDEO_DRIVER_IS_THREADED_INTERNAL();
  25579. }
  25580. bool *video_driver_get_threaded(void)
  25581. {
  25582. struct rarch_state *p_rarch = &rarch_st;
  25583. #if defined(__MACH__) && defined(__APPLE__)
  25584. /* TODO/FIXME - force threaded video to disabled on Apple for now
  25585. * until NSWindow/UIWindow concurrency issues are taken care of */
  25586. p_rarch->video_driver_threaded = false;
  25587. #endif
  25588. return &p_rarch->video_driver_threaded;
  25589. }
  25590. void video_driver_set_threaded(bool val)
  25591. {
  25592. struct rarch_state *p_rarch = &rarch_st;
  25593. #if defined(__MACH__) && defined(__APPLE__)
  25594. /* TODO/FIXME - force threaded video to disabled on Apple for now
  25595. * until NSWindow/UIWindow concurrency issues are taken care of */
  25596. p_rarch->video_driver_threaded = false;
  25597. #else
  25598. p_rarch->video_driver_threaded = val;
  25599. #endif
  25600. }
  25601. const char *video_driver_get_ident(void)
  25602. {
  25603. struct rarch_state *p_rarch = &rarch_st;
  25604. if (!p_rarch->current_video)
  25605. return NULL;
  25606. #ifdef HAVE_THREADS
  25607. if (VIDEO_DRIVER_IS_THREADED_INTERNAL())
  25608. {
  25609. const thread_video_t *thr = (const thread_video_t*)VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch, true);
  25610. if (!thr || !thr->driver)
  25611. return NULL;
  25612. return thr->driver->ident;
  25613. }
  25614. #endif
  25615. return p_rarch->current_video->ident;
  25616. }
  25617. static void video_context_driver_reset(void)
  25618. {
  25619. struct rarch_state *p_rarch = &rarch_st;
  25620. if (!p_rarch->current_video_context.get_metrics)
  25621. p_rarch->current_video_context.get_metrics = get_metrics_null;
  25622. }
  25623. bool video_context_driver_set(const gfx_ctx_driver_t *data)
  25624. {
  25625. struct rarch_state *p_rarch = &rarch_st;
  25626. if (!data)
  25627. return false;
  25628. p_rarch->current_video_context = *data;
  25629. video_context_driver_reset();
  25630. return true;
  25631. }
  25632. static void video_context_driver_destroy_internal(
  25633. gfx_ctx_driver_t *ctx_driver)
  25634. {
  25635. if (!ctx_driver)
  25636. return;
  25637. ctx_driver->init = NULL;
  25638. ctx_driver->bind_api = NULL;
  25639. ctx_driver->swap_interval = NULL;
  25640. ctx_driver->set_video_mode = NULL;
  25641. ctx_driver->get_video_size = NULL;
  25642. ctx_driver->get_video_output_size = NULL;
  25643. ctx_driver->get_video_output_prev = NULL;
  25644. ctx_driver->get_video_output_next = NULL;
  25645. ctx_driver->get_metrics = get_metrics_null;
  25646. ctx_driver->translate_aspect = NULL;
  25647. ctx_driver->update_window_title = NULL;
  25648. ctx_driver->check_window = NULL;
  25649. ctx_driver->set_resize = NULL;
  25650. ctx_driver->suppress_screensaver = NULL;
  25651. ctx_driver->swap_buffers = NULL;
  25652. ctx_driver->input_driver = NULL;
  25653. ctx_driver->get_proc_address = NULL;
  25654. ctx_driver->image_buffer_init = NULL;
  25655. ctx_driver->image_buffer_write = NULL;
  25656. ctx_driver->show_mouse = NULL;
  25657. ctx_driver->ident = NULL;
  25658. ctx_driver->get_flags = NULL;
  25659. ctx_driver->set_flags = NULL;
  25660. ctx_driver->bind_hw_render = NULL;
  25661. ctx_driver->get_context_data = NULL;
  25662. ctx_driver->make_current = NULL;
  25663. }
  25664. void video_context_driver_destroy(void)
  25665. {
  25666. struct rarch_state *p_rarch = &rarch_st;
  25667. video_context_driver_destroy_internal(&p_rarch->current_video_context);
  25668. }
  25669. /**
  25670. * video_driver_get_current_framebuffer:
  25671. *
  25672. * Gets pointer to current hardware renderer framebuffer object.
  25673. * Used by RETRO_ENVIRONMENT_SET_HW_RENDER.
  25674. *
  25675. * Returns: pointer to hardware framebuffer object, otherwise 0.
  25676. **/
  25677. static uintptr_t video_driver_get_current_framebuffer(void)
  25678. {
  25679. struct rarch_state *p_rarch = &rarch_st;
  25680. if ( p_rarch->video_driver_poke
  25681. && p_rarch->video_driver_poke->get_current_framebuffer)
  25682. return p_rarch->video_driver_poke->get_current_framebuffer(
  25683. p_rarch->video_driver_data);
  25684. return 0;
  25685. }
  25686. static retro_proc_address_t video_driver_get_proc_address(const char *sym)
  25687. {
  25688. struct rarch_state *p_rarch = &rarch_st;
  25689. if ( p_rarch->video_driver_poke
  25690. && p_rarch->video_driver_poke->get_proc_address)
  25691. return p_rarch->video_driver_poke->get_proc_address(
  25692. p_rarch->video_driver_data, sym);
  25693. return NULL;
  25694. }
  25695. #ifdef HAVE_VIDEO_FILTER
  25696. static void video_driver_filter_free(void)
  25697. {
  25698. struct rarch_state *p_rarch = &rarch_st;
  25699. if (p_rarch->video_driver_state_filter)
  25700. rarch_softfilter_free(p_rarch->video_driver_state_filter);
  25701. p_rarch->video_driver_state_filter = NULL;
  25702. if (p_rarch->video_driver_state_buffer)
  25703. {
  25704. #ifdef _3DS
  25705. linearFree(p_rarch->video_driver_state_buffer);
  25706. #else
  25707. free(p_rarch->video_driver_state_buffer);
  25708. #endif
  25709. }
  25710. p_rarch->video_driver_state_buffer = NULL;
  25711. p_rarch->video_driver_state_scale = 0;
  25712. p_rarch->video_driver_state_out_bpp = 0;
  25713. p_rarch->video_driver_state_out_rgb32 = false;
  25714. }
  25715. #endif
  25716. #ifdef HAVE_VIDEO_FILTER
  25717. static void video_driver_init_filter(enum retro_pixel_format colfmt_int)
  25718. {
  25719. unsigned pow2_x, pow2_y, maxsize;
  25720. void *buf = NULL;
  25721. struct rarch_state *p_rarch = &rarch_st;
  25722. settings_t *settings = p_rarch->configuration_settings;
  25723. struct retro_game_geometry *geom = &p_rarch->video_driver_av_info.geometry;
  25724. unsigned width = geom->max_width;
  25725. unsigned height = geom->max_height;
  25726. /* Deprecated format. Gets pre-converted. */
  25727. enum retro_pixel_format colfmt =
  25728. (colfmt_int == RETRO_PIXEL_FORMAT_0RGB1555) ?
  25729. RETRO_PIXEL_FORMAT_RGB565 : colfmt_int;
  25730. if (video_driver_is_hw_context())
  25731. {
  25732. RARCH_WARN("[Video]: Cannot use CPU filters when hardware rendering is used.\n");
  25733. return;
  25734. }
  25735. p_rarch->video_driver_state_filter = rarch_softfilter_new(
  25736. settings->paths.path_softfilter_plugin,
  25737. RARCH_SOFTFILTER_THREADS_AUTO, colfmt, width, height);
  25738. if (!p_rarch->video_driver_state_filter)
  25739. {
  25740. RARCH_ERR("[Video]: Failed to load filter.\n");
  25741. return;
  25742. }
  25743. rarch_softfilter_get_max_output_size(
  25744. p_rarch->video_driver_state_filter,
  25745. &width, &height);
  25746. pow2_x = next_pow2(width);
  25747. pow2_y = next_pow2(height);
  25748. maxsize = MAX(pow2_x, pow2_y);
  25749. #ifdef _3DS
  25750. /* On 3DS, video is disabled if the output resolution
  25751. * exceeds 2048x2048. To avoid the user being presented
  25752. * with a black screen, we therefore have to check that
  25753. * the filter upscaling buffer fits within this limit. */
  25754. if (maxsize >= 2048)
  25755. {
  25756. RARCH_ERR("[Video]: Softfilter initialization failed."
  25757. " Upscaling buffer exceeds hardware limitations.\n");
  25758. video_driver_filter_free();
  25759. return;
  25760. }
  25761. #endif
  25762. p_rarch->video_driver_state_scale = maxsize / RARCH_SCALE_BASE;
  25763. p_rarch->video_driver_state_out_rgb32 = rarch_softfilter_get_output_format(
  25764. p_rarch->video_driver_state_filter) == RETRO_PIXEL_FORMAT_XRGB8888;
  25765. p_rarch->video_driver_state_out_bpp =
  25766. p_rarch->video_driver_state_out_rgb32 ?
  25767. sizeof(uint32_t) :
  25768. sizeof(uint16_t);
  25769. /* TODO: Aligned output. */
  25770. #ifdef _3DS
  25771. buf = linearMemAlign(
  25772. width * height * p_rarch->video_driver_state_out_bpp, 0x80);
  25773. #else
  25774. buf = malloc(
  25775. width * height * p_rarch->video_driver_state_out_bpp);
  25776. #endif
  25777. if (!buf)
  25778. {
  25779. RARCH_ERR("[Video]: Softfilter initialization failed.\n");
  25780. video_driver_filter_free();
  25781. return;
  25782. }
  25783. p_rarch->video_driver_state_buffer = buf;
  25784. }
  25785. #endif
  25786. static void video_driver_init_input(input_driver_t *tmp)
  25787. {
  25788. struct rarch_state *p_rarch = &rarch_st;
  25789. input_driver_t **input = &p_rarch->current_input;
  25790. if (*input)
  25791. return;
  25792. /* Video driver didn't provide an input driver,
  25793. * so we use configured one. */
  25794. RARCH_LOG("[Video]: Graphics driver did not initialize an input driver."
  25795. " Attempting to pick a suitable driver.\n");
  25796. if (tmp)
  25797. *input = tmp;
  25798. else
  25799. input_driver_find_driver(p_rarch);
  25800. /* This should never really happen as tmp (driver.input) is always
  25801. * found before this in find_driver_input(), or we have aborted
  25802. * in a similar fashion anyways. */
  25803. if (!p_rarch->current_input || !input_driver_init(p_rarch))
  25804. {
  25805. RARCH_ERR("[Video]: Cannot initialize input driver. Exiting ...\n");
  25806. retroarch_fail(1, "video_driver_init_input()");
  25807. }
  25808. }
  25809. /**
  25810. * video_driver_monitor_compute_fps_statistics:
  25811. *
  25812. * Computes monitor FPS statistics.
  25813. **/
  25814. static void video_driver_monitor_compute_fps_statistics(void)
  25815. {
  25816. double avg_fps = 0.0;
  25817. double stddev = 0.0;
  25818. unsigned samples = 0;
  25819. struct rarch_state *p_rarch = &rarch_st;
  25820. if (p_rarch->video_driver_frame_time_count <
  25821. (2 * MEASURE_FRAME_TIME_SAMPLES_COUNT))
  25822. {
  25823. RARCH_LOG(
  25824. "[Video]: Does not have enough samples for monitor refresh rate"
  25825. " estimation. Requires to run for at least %u frames.\n",
  25826. 2 * MEASURE_FRAME_TIME_SAMPLES_COUNT);
  25827. return;
  25828. }
  25829. if (video_monitor_fps_statistics(&avg_fps, &stddev, &samples))
  25830. {
  25831. RARCH_LOG("[Video]: Average monitor Hz: %.6f Hz. (%.3f %% frame time"
  25832. " deviation, based on %u last samples).\n",
  25833. avg_fps, 100.0f * stddev, samples);
  25834. }
  25835. }
  25836. static void video_driver_pixel_converter_free(
  25837. video_pixel_scaler_t *scalr)
  25838. {
  25839. if (!scalr)
  25840. return;
  25841. if (scalr->scaler)
  25842. {
  25843. scaler_ctx_gen_reset(scalr->scaler);
  25844. free(scalr->scaler);
  25845. }
  25846. if (scalr->scaler_out)
  25847. free(scalr->scaler_out);
  25848. scalr->scaler = NULL;
  25849. scalr->scaler_out = NULL;
  25850. free(scalr);
  25851. }
  25852. static void video_driver_free_hw_context(struct rarch_state *p_rarch)
  25853. {
  25854. VIDEO_DRIVER_CONTEXT_LOCK();
  25855. if (p_rarch->hw_render.context_destroy)
  25856. p_rarch->hw_render.context_destroy();
  25857. memset(&p_rarch->hw_render, 0, sizeof(p_rarch->hw_render));
  25858. VIDEO_DRIVER_CONTEXT_UNLOCK();
  25859. p_rarch->hw_render_context_negotiation = NULL;
  25860. }
  25861. static void video_driver_free_internal(struct rarch_state *p_rarch)
  25862. {
  25863. #ifdef HAVE_THREADS
  25864. bool is_threaded = VIDEO_DRIVER_IS_THREADED_INTERNAL();
  25865. #endif
  25866. #ifdef HAVE_VIDEO_LAYOUT
  25867. video_layout_deinit();
  25868. #endif
  25869. command_event(CMD_EVENT_OVERLAY_DEINIT, NULL);
  25870. if (!video_driver_is_video_cache_context())
  25871. video_driver_free_hw_context(p_rarch);
  25872. if (!(p_rarch->current_input_data == p_rarch->video_driver_data))
  25873. {
  25874. if (p_rarch->current_input)
  25875. if (p_rarch->current_input->free)
  25876. p_rarch->current_input->free(p_rarch->current_input_data);
  25877. if (p_rarch->joypad)
  25878. p_rarch->joypad->destroy();
  25879. p_rarch->joypad = NULL;
  25880. #ifdef HAVE_MFI
  25881. if (p_rarch->sec_joypad)
  25882. p_rarch->sec_joypad->destroy();
  25883. p_rarch->sec_joypad = NULL;
  25884. #endif
  25885. p_rarch->keyboard_mapping_blocked = false;
  25886. p_rarch->current_input_data = NULL;
  25887. }
  25888. if (p_rarch->video_driver_data
  25889. && p_rarch->current_video
  25890. && p_rarch->current_video->free)
  25891. p_rarch->current_video->free(p_rarch->video_driver_data);
  25892. if (p_rarch->video_driver_scaler_ptr)
  25893. video_driver_pixel_converter_free(p_rarch->video_driver_scaler_ptr);
  25894. p_rarch->video_driver_scaler_ptr = NULL;
  25895. #ifdef HAVE_VIDEO_FILTER
  25896. video_driver_filter_free();
  25897. #endif
  25898. dir_free_shader(p_rarch);
  25899. #ifdef HAVE_THREADS
  25900. if (is_threaded)
  25901. return;
  25902. #endif
  25903. video_driver_monitor_compute_fps_statistics();
  25904. }
  25905. static video_pixel_scaler_t *video_driver_pixel_converter_init(
  25906. const enum retro_pixel_format video_driver_pix_fmt,
  25907. struct retro_hw_render_callback *hwr,
  25908. unsigned size)
  25909. {
  25910. void *scalr_out = NULL;
  25911. video_pixel_scaler_t *scalr = NULL;
  25912. struct scaler_ctx *scalr_ctx = NULL;
  25913. /* If pixel format is not 0RGB1555, we don't need to do
  25914. * any internal pixel conversion. */
  25915. if (video_driver_pix_fmt != RETRO_PIXEL_FORMAT_0RGB1555)
  25916. return NULL;
  25917. /* No need to perform pixel conversion for HW rendering contexts. */
  25918. if (hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE)
  25919. return NULL;
  25920. RARCH_WARN("[Video]: 0RGB1555 pixel format is deprecated,"
  25921. " and will be slower. For 15/16-bit, RGB565"
  25922. " format is preferred.\n");
  25923. if (!(scalr = (video_pixel_scaler_t*)malloc(sizeof(*scalr))))
  25924. goto error;
  25925. scalr->scaler = NULL;
  25926. scalr->scaler_out = NULL;
  25927. if (!(scalr_ctx = (struct scaler_ctx*)calloc(1, sizeof(*scalr_ctx))))
  25928. goto error;
  25929. scalr->scaler = scalr_ctx;
  25930. scalr->scaler->scaler_type = SCALER_TYPE_POINT;
  25931. scalr->scaler->in_fmt = SCALER_FMT_0RGB1555;
  25932. /* TODO/FIXME: Pick either ARGB8888 or RGB565 depending on driver. */
  25933. scalr->scaler->out_fmt = SCALER_FMT_RGB565;
  25934. if (!scaler_ctx_gen_filter(scalr_ctx))
  25935. goto error;
  25936. if (!(scalr_out = calloc(sizeof(uint16_t), size * size)))
  25937. goto error;
  25938. scalr->scaler_out = scalr_out;
  25939. return scalr;
  25940. error:
  25941. video_driver_pixel_converter_free(scalr);
  25942. #ifdef HAVE_VIDEO_FILTER
  25943. video_driver_filter_free();
  25944. #endif
  25945. return NULL;
  25946. }
  25947. static void video_driver_set_viewport_config(struct retro_game_geometry *geom,
  25948. settings_t *settings)
  25949. {
  25950. float video_aspect_ratio = settings->floats.video_aspect_ratio;
  25951. if (video_aspect_ratio < 0.0f)
  25952. {
  25953. if (geom->aspect_ratio > 0.0f &&
  25954. settings->bools.video_aspect_ratio_auto)
  25955. aspectratio_lut[ASPECT_RATIO_CONFIG].value = geom->aspect_ratio;
  25956. else
  25957. {
  25958. unsigned base_width = geom->base_width;
  25959. unsigned base_height = geom->base_height;
  25960. /* Get around division by zero errors */
  25961. if (base_width == 0)
  25962. base_width = 1;
  25963. if (base_height == 0)
  25964. base_height = 1;
  25965. aspectratio_lut[ASPECT_RATIO_CONFIG].value =
  25966. (float)base_width / base_height; /* 1:1 PAR. */
  25967. }
  25968. }
  25969. else
  25970. aspectratio_lut[ASPECT_RATIO_CONFIG].value = video_aspect_ratio;
  25971. }
  25972. static void video_driver_set_viewport_square_pixel(struct retro_game_geometry *geom)
  25973. {
  25974. unsigned len, highest, i, aspect_x, aspect_y;
  25975. unsigned width = geom->base_width;
  25976. unsigned height = geom->base_height;
  25977. unsigned int rotation = retroarch_get_rotation();
  25978. if (width == 0 || height == 0)
  25979. return;
  25980. len = MIN(width, height);
  25981. highest = 1;
  25982. for (i = 1; i < len; i++)
  25983. {
  25984. if ((width % i) == 0 && (height % i) == 0)
  25985. highest = i;
  25986. }
  25987. if (rotation % 2)
  25988. {
  25989. aspect_x = height / highest;
  25990. aspect_y = width / highest;
  25991. }
  25992. else
  25993. {
  25994. aspect_x = width / highest;
  25995. aspect_y = height / highest;
  25996. }
  25997. snprintf(aspectratio_lut[ASPECT_RATIO_SQUARE].name,
  25998. sizeof(aspectratio_lut[ASPECT_RATIO_SQUARE].name),
  25999. "1:1 PAR (%u:%u DAR)", aspect_x, aspect_y);
  26000. aspectratio_lut[ASPECT_RATIO_SQUARE].value = (float)aspect_x / aspect_y;
  26001. }
  26002. static bool video_driver_init_internal(bool *video_is_threaded)
  26003. {
  26004. video_info_t video;
  26005. unsigned max_dim, scale, width, height;
  26006. video_viewport_t *custom_vp = NULL;
  26007. input_driver_t *tmp = NULL;
  26008. static uint16_t dummy_pixels[32] = {0};
  26009. struct rarch_state *p_rarch = &rarch_st;
  26010. settings_t *settings = p_rarch->configuration_settings;
  26011. struct retro_game_geometry *geom = &p_rarch->video_driver_av_info.geometry;
  26012. const enum retro_pixel_format
  26013. video_driver_pix_fmt = p_rarch->video_driver_pix_fmt;
  26014. #ifdef HAVE_VIDEO_FILTER
  26015. const char *path_softfilter_plugin = settings->paths.path_softfilter_plugin;
  26016. if (!string_is_empty(path_softfilter_plugin))
  26017. video_driver_init_filter(video_driver_pix_fmt);
  26018. #endif
  26019. max_dim = MAX(geom->max_width, geom->max_height);
  26020. scale = next_pow2(max_dim) / RARCH_SCALE_BASE;
  26021. scale = MAX(scale, 1);
  26022. #ifdef HAVE_VIDEO_FILTER
  26023. if (p_rarch->video_driver_state_filter)
  26024. scale = p_rarch->video_driver_state_scale;
  26025. #endif
  26026. /* Update core-dependent aspect ratio values. */
  26027. video_driver_set_viewport_square_pixel(geom);
  26028. video_driver_set_viewport_core();
  26029. video_driver_set_viewport_config(geom, settings);
  26030. /* Update CUSTOM viewport. */
  26031. custom_vp = video_viewport_get_custom();
  26032. if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
  26033. {
  26034. float default_aspect = aspectratio_lut[ASPECT_RATIO_CORE].value;
  26035. aspectratio_lut[ASPECT_RATIO_CUSTOM].value =
  26036. (custom_vp->width && custom_vp->height) ?
  26037. (float)custom_vp->width / custom_vp->height : default_aspect;
  26038. }
  26039. {
  26040. /* Guard against aspect ratio index possibly being out of bounds */
  26041. unsigned new_aspect_idx = settings->uints.video_aspect_ratio_idx;
  26042. if (new_aspect_idx > ASPECT_RATIO_END)
  26043. new_aspect_idx = settings->uints.video_aspect_ratio_idx = 0;
  26044. video_driver_set_aspect_ratio_value(
  26045. aspectratio_lut[new_aspect_idx].value);
  26046. }
  26047. if (settings->bools.video_fullscreen|| p_rarch->rarch_force_fullscreen)
  26048. {
  26049. width = settings->uints.video_fullscreen_x;
  26050. height = settings->uints.video_fullscreen_y;
  26051. }
  26052. else
  26053. {
  26054. /* TODO: remove when the new window resizing core is hooked */
  26055. if (settings->bools.video_window_save_positions &&
  26056. (settings->uints.window_position_width ||
  26057. settings->uints.window_position_height))
  26058. {
  26059. width = settings->uints.window_position_width;
  26060. height = settings->uints.window_position_height;
  26061. }
  26062. else
  26063. {
  26064. float video_scale = settings->floats.video_scale;
  26065. if (settings->bools.video_force_aspect)
  26066. {
  26067. /* Do rounding here to simplify integer scale correctness. */
  26068. unsigned base_width =
  26069. roundf(geom->base_height * p_rarch->video_driver_aspect_ratio);
  26070. width = roundf(base_width * video_scale);
  26071. }
  26072. else
  26073. width = roundf(geom->base_width * video_scale);
  26074. height = roundf(geom->base_height * video_scale);
  26075. }
  26076. }
  26077. if (width && height)
  26078. RARCH_LOG("[Video]: Video @ %ux%u\n", width, height);
  26079. else
  26080. RARCH_LOG("[Video]: Video @ fullscreen\n");
  26081. video_driver_display_type_set(RARCH_DISPLAY_NONE);
  26082. video_driver_display_set(0);
  26083. video_driver_display_userdata_set(0);
  26084. video_driver_window_set(0);
  26085. p_rarch->video_driver_scaler_ptr = video_driver_pixel_converter_init(
  26086. p_rarch->video_driver_pix_fmt,
  26087. VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch),
  26088. RARCH_SCALE_BASE * scale);
  26089. video.width = width;
  26090. video.height = height;
  26091. video.fullscreen = settings->bools.video_fullscreen ||
  26092. p_rarch->rarch_force_fullscreen;
  26093. video.vsync = settings->bools.video_vsync &&
  26094. !p_rarch->runloop_force_nonblock;
  26095. video.force_aspect = settings->bools.video_force_aspect;
  26096. video.font_enable = settings->bools.video_font_enable;
  26097. video.swap_interval = settings->uints.video_swap_interval;
  26098. video.adaptive_vsync = settings->bools.video_adaptive_vsync;
  26099. #ifdef GEKKO
  26100. video.viwidth = settings->uints.video_viwidth;
  26101. video.vfilter = settings->bools.video_vfilter;
  26102. #endif
  26103. video.smooth = settings->bools.video_smooth;
  26104. video.ctx_scaling = settings->bools.video_ctx_scaling;
  26105. video.input_scale = scale;
  26106. video.font_size = settings->floats.video_font_size;
  26107. video.path_font = settings->paths.path_font;
  26108. #ifdef HAVE_VIDEO_FILTER
  26109. video.rgb32 =
  26110. p_rarch->video_driver_state_filter ?
  26111. p_rarch->video_driver_state_out_rgb32 :
  26112. (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888);
  26113. #else
  26114. video.rgb32 =
  26115. (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888);
  26116. #endif
  26117. video.parent = 0;
  26118. p_rarch->video_started_fullscreen = video.fullscreen;
  26119. /* Reset video frame count */
  26120. p_rarch->video_driver_frame_count = 0;
  26121. tmp = p_rarch->current_input;
  26122. /* Need to grab the "real" video driver interface on a reinit. */
  26123. video_driver_find_driver(p_rarch);
  26124. #ifdef HAVE_THREADS
  26125. video.is_threaded = VIDEO_DRIVER_IS_THREADED_INTERNAL();
  26126. *video_is_threaded = video.is_threaded;
  26127. if (video.is_threaded)
  26128. {
  26129. bool ret;
  26130. /* Can't do hardware rendering with threaded driver currently. */
  26131. RARCH_LOG("[Video]: Starting threaded video driver ...\n");
  26132. ret = video_init_thread((const video_driver_t**)&p_rarch->current_video,
  26133. &p_rarch->video_driver_data,
  26134. &p_rarch->current_input,
  26135. (void**)&p_rarch->current_input_data,
  26136. p_rarch->current_video,
  26137. video);
  26138. if (!ret)
  26139. {
  26140. RARCH_ERR("[Video]: Cannot open threaded video driver ... Exiting ...\n");
  26141. goto error;
  26142. }
  26143. }
  26144. else
  26145. #endif
  26146. p_rarch->video_driver_data = p_rarch->current_video->init(
  26147. &video,
  26148. &p_rarch->current_input,
  26149. (void**)&p_rarch->current_input_data);
  26150. if (!p_rarch->video_driver_data)
  26151. {
  26152. RARCH_ERR("[Video]: Cannot open video driver ... Exiting ...\n");
  26153. goto error;
  26154. }
  26155. p_rarch->video_driver_poke = NULL;
  26156. if (p_rarch->current_video->poke_interface)
  26157. p_rarch->current_video->poke_interface(
  26158. p_rarch->video_driver_data, &p_rarch->video_driver_poke);
  26159. if (p_rarch->current_video->viewport_info &&
  26160. (!custom_vp->width ||
  26161. !custom_vp->height))
  26162. {
  26163. /* Force custom viewport to have sane parameters. */
  26164. custom_vp->width = width;
  26165. custom_vp->height = height;
  26166. video_driver_get_viewport_info(custom_vp);
  26167. }
  26168. video_driver_set_rotation(retroarch_get_rotation() % 4);
  26169. p_rarch->current_video->suppress_screensaver(p_rarch->video_driver_data,
  26170. settings->bools.ui_suspend_screensaver_enable);
  26171. video_driver_init_input(tmp);
  26172. #ifdef HAVE_OVERLAY
  26173. retroarch_overlay_deinit(p_rarch);
  26174. retroarch_overlay_init(p_rarch);
  26175. #endif
  26176. #ifdef HAVE_VIDEO_LAYOUT
  26177. if (settings->bools.video_layout_enable)
  26178. {
  26179. video_layout_init(p_rarch->video_driver_data,
  26180. video_driver_layout_render_interface());
  26181. video_layout_load(settings->paths.path_video_layout);
  26182. video_layout_view_select(settings->uints.video_layout_selected_view);
  26183. }
  26184. #endif
  26185. if (!p_rarch->current_core.game_loaded)
  26186. video_driver_cached_frame_set(&dummy_pixels, 4, 4, 8);
  26187. #if defined(PSP)
  26188. video_driver_set_texture_frame(&dummy_pixels, false, 1, 1, 1.0f);
  26189. #endif
  26190. video_context_driver_reset();
  26191. video_display_server_init(p_rarch->video_driver_display_type);
  26192. if ((enum rotation)settings->uints.screen_orientation != ORIENTATION_NORMAL)
  26193. video_display_server_set_screen_orientation((enum rotation)settings->uints.screen_orientation);
  26194. /* Ensure that we preserve the 'grab mouse'
  26195. * state if it was enabled prior to driver
  26196. * (re-)initialisation */
  26197. if (p_rarch->input_driver_grab_mouse_state)
  26198. {
  26199. video_driver_hide_mouse();
  26200. input_driver_grab_mouse(p_rarch);
  26201. }
  26202. else if (video.fullscreen)
  26203. {
  26204. video_driver_hide_mouse();
  26205. if (!settings->bools.video_windowed_fullscreen)
  26206. input_driver_grab_mouse(p_rarch);
  26207. }
  26208. return true;
  26209. error:
  26210. retroarch_fail(1, "init_video()");
  26211. return false;
  26212. }
  26213. void video_driver_set_viewport(unsigned width, unsigned height,
  26214. bool force_fullscreen, bool allow_rotate)
  26215. {
  26216. struct rarch_state *p_rarch = &rarch_st;
  26217. if (p_rarch->current_video && p_rarch->current_video->set_viewport)
  26218. p_rarch->current_video->set_viewport(
  26219. p_rarch->video_driver_data, width, height,
  26220. force_fullscreen, allow_rotate);
  26221. }
  26222. bool video_driver_set_rotation(unsigned rotation)
  26223. {
  26224. struct rarch_state *p_rarch = &rarch_st;
  26225. if (!p_rarch->current_video || !p_rarch->current_video->set_rotation)
  26226. return false;
  26227. p_rarch->current_video->set_rotation(p_rarch->video_driver_data, rotation);
  26228. return true;
  26229. }
  26230. bool video_driver_set_video_mode(unsigned width,
  26231. unsigned height, bool fullscreen)
  26232. {
  26233. struct rarch_state *p_rarch = &rarch_st;
  26234. if ( p_rarch->video_driver_poke &&
  26235. p_rarch->video_driver_poke->set_video_mode)
  26236. {
  26237. p_rarch->video_driver_poke->set_video_mode(p_rarch->video_driver_data,
  26238. width, height, fullscreen);
  26239. return true;
  26240. }
  26241. return false;
  26242. }
  26243. bool video_driver_get_video_output_size(unsigned *width, unsigned *height)
  26244. {
  26245. struct rarch_state *p_rarch = &rarch_st;
  26246. if (!p_rarch->video_driver_poke || !p_rarch->video_driver_poke->get_video_output_size)
  26247. return false;
  26248. p_rarch->video_driver_poke->get_video_output_size(p_rarch->video_driver_data,
  26249. width, height);
  26250. return true;
  26251. }
  26252. /* Draw text on top of the screen */
  26253. void gfx_display_draw_text(
  26254. const font_data_t *font, const char *text,
  26255. float x, float y, int width, int height,
  26256. uint32_t color, enum text_alignment text_align,
  26257. float scale, bool shadows_enable, float shadow_offset,
  26258. bool draw_outside)
  26259. {
  26260. struct font_params params;
  26261. struct rarch_state *p_rarch = &rarch_st;
  26262. if ((color & 0x000000FF) == 0)
  26263. return;
  26264. /* Don't draw outside of the screen */
  26265. if (!draw_outside &&
  26266. ((x < -64 || x > width + 64)
  26267. || (y < -64 || y > height + 64))
  26268. )
  26269. return;
  26270. params.x = x / width;
  26271. params.y = 1.0f - y / height;
  26272. params.scale = scale;
  26273. params.drop_mod = 0.0f;
  26274. params.drop_x = 0.0f;
  26275. params.drop_y = 0.0f;
  26276. params.color = color;
  26277. params.full_screen = true;
  26278. params.text_align = text_align;
  26279. if (shadows_enable)
  26280. {
  26281. params.drop_x = shadow_offset;
  26282. params.drop_y = -shadow_offset;
  26283. params.drop_alpha = 0.35f;
  26284. }
  26285. if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->set_osd_msg)
  26286. p_rarch->video_driver_poke->set_osd_msg(p_rarch->video_driver_data,
  26287. text, &params, (void*)font);
  26288. }
  26289. void video_driver_set_texture_enable(bool enable, bool fullscreen)
  26290. {
  26291. struct rarch_state *p_rarch = &rarch_st;
  26292. if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->set_texture_enable)
  26293. p_rarch->video_driver_poke->set_texture_enable(p_rarch->video_driver_data,
  26294. enable, fullscreen);
  26295. }
  26296. void video_driver_set_texture_frame(const void *frame, bool rgb32,
  26297. unsigned width, unsigned height, float alpha)
  26298. {
  26299. struct rarch_state *p_rarch = &rarch_st;
  26300. if (p_rarch->video_driver_poke &&
  26301. p_rarch->video_driver_poke->set_texture_frame)
  26302. p_rarch->video_driver_poke->set_texture_frame(p_rarch->video_driver_data,
  26303. frame, rgb32, width, height, alpha);
  26304. }
  26305. #ifdef HAVE_OVERLAY
  26306. static bool video_driver_overlay_interface(
  26307. const video_overlay_interface_t **iface)
  26308. {
  26309. struct rarch_state *p_rarch = &rarch_st;
  26310. if (!p_rarch->current_video || !p_rarch->current_video->overlay_interface)
  26311. return false;
  26312. p_rarch->current_video->overlay_interface(p_rarch->video_driver_data, iface);
  26313. return true;
  26314. }
  26315. #endif
  26316. #ifdef HAVE_VIDEO_LAYOUT
  26317. const video_layout_render_interface_t *video_driver_layout_render_interface(void)
  26318. {
  26319. struct rarch_state *p_rarch = &rarch_st;
  26320. if ( !p_rarch->current_video ||
  26321. !p_rarch->current_video->video_layout_render_interface)
  26322. return NULL;
  26323. return p_rarch->current_video->video_layout_render_interface(
  26324. p_rarch->video_driver_data);
  26325. }
  26326. #endif
  26327. void *video_driver_read_frame_raw(unsigned *width,
  26328. unsigned *height, size_t *pitch)
  26329. {
  26330. struct rarch_state *p_rarch = &rarch_st;
  26331. if (!p_rarch->current_video || !p_rarch->current_video->read_frame_raw)
  26332. return NULL;
  26333. return p_rarch->current_video->read_frame_raw(
  26334. p_rarch->video_driver_data, width,
  26335. height, pitch);
  26336. }
  26337. void video_driver_set_filtering(unsigned index, bool smooth, bool ctx_scaling)
  26338. {
  26339. struct rarch_state *p_rarch = &rarch_st;
  26340. if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->set_filtering)
  26341. p_rarch->video_driver_poke->set_filtering(p_rarch->video_driver_data,
  26342. index, smooth, ctx_scaling);
  26343. }
  26344. void video_driver_cached_frame_set(const void *data, unsigned width,
  26345. unsigned height, size_t pitch)
  26346. {
  26347. struct rarch_state *p_rarch = &rarch_st;
  26348. if (data)
  26349. p_rarch->frame_cache_data = data;
  26350. p_rarch->frame_cache_width = width;
  26351. p_rarch->frame_cache_height = height;
  26352. p_rarch->frame_cache_pitch = pitch;
  26353. }
  26354. void video_driver_cached_frame_get(const void **data, unsigned *width,
  26355. unsigned *height, size_t *pitch)
  26356. {
  26357. struct rarch_state *p_rarch = &rarch_st;
  26358. if (data)
  26359. *data = p_rarch->frame_cache_data;
  26360. if (width)
  26361. *width = p_rarch->frame_cache_width;
  26362. if (height)
  26363. *height = p_rarch->frame_cache_height;
  26364. if (pitch)
  26365. *pitch = p_rarch->frame_cache_pitch;
  26366. }
  26367. void video_driver_get_size(unsigned *width, unsigned *height)
  26368. {
  26369. struct rarch_state *p_rarch = &rarch_st;
  26370. #ifdef HAVE_THREADS
  26371. bool is_threaded = VIDEO_DRIVER_IS_THREADED_INTERNAL();
  26372. VIDEO_DRIVER_THREADED_LOCK(is_threaded);
  26373. #endif
  26374. if (width)
  26375. *width = p_rarch->video_driver_width;
  26376. if (height)
  26377. *height = p_rarch->video_driver_height;
  26378. #ifdef HAVE_THREADS
  26379. VIDEO_DRIVER_THREADED_UNLOCK(is_threaded);
  26380. #endif
  26381. }
  26382. void video_driver_set_size(unsigned width, unsigned height)
  26383. {
  26384. struct rarch_state *p_rarch = &rarch_st;
  26385. #ifdef HAVE_THREADS
  26386. bool is_threaded = VIDEO_DRIVER_IS_THREADED_INTERNAL();
  26387. VIDEO_DRIVER_THREADED_LOCK(is_threaded);
  26388. #endif
  26389. p_rarch->video_driver_width = width;
  26390. p_rarch->video_driver_height = height;
  26391. #ifdef HAVE_THREADS
  26392. VIDEO_DRIVER_THREADED_UNLOCK(is_threaded);
  26393. #endif
  26394. }
  26395. /**
  26396. * video_monitor_set_refresh_rate:
  26397. * @hz : New refresh rate for monitor.
  26398. *
  26399. * Sets monitor refresh rate to new value.
  26400. **/
  26401. void video_monitor_set_refresh_rate(float hz)
  26402. {
  26403. char msg[128];
  26404. struct rarch_state *p_rarch = &rarch_st;
  26405. settings_t *settings = p_rarch->configuration_settings;
  26406. snprintf(msg, sizeof(msg),
  26407. "[Video]: Setting refresh rate to: %.3f Hz.", hz);
  26408. if (settings->bools.notification_show_refresh_rate)
  26409. runloop_msg_queue_push(msg, 1, 180, false, NULL,
  26410. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  26411. RARCH_LOG("%s\n", msg);
  26412. configuration_set_float(settings,
  26413. settings->floats.video_refresh_rate,
  26414. hz);
  26415. /* Without CMD_EVENT_REINIT vulkan will not switch rate properly,
  26416. * and with other drivers it prevents switching properly.. */
  26417. if (string_is_equal(settings->arrays.video_driver, "vulkan"))
  26418. command_event(CMD_EVENT_REINIT, NULL);
  26419. }
  26420. /**
  26421. * video_monitor_fps_statistics
  26422. * @refresh_rate : Monitor refresh rate.
  26423. * @deviation : Deviation from measured refresh rate.
  26424. * @sample_points : Amount of sampled points.
  26425. *
  26426. * Gets the monitor FPS statistics based on the current
  26427. * runtime.
  26428. *
  26429. * Returns: true (1) on success.
  26430. * false (0) if:
  26431. * a) threaded video mode is enabled
  26432. * b) less than 2 frame time samples.
  26433. * c) FPS monitor enable is off.
  26434. **/
  26435. bool video_monitor_fps_statistics(double *refresh_rate,
  26436. double *deviation, unsigned *sample_points)
  26437. {
  26438. unsigned i;
  26439. retro_time_t accum = 0;
  26440. retro_time_t avg = 0;
  26441. retro_time_t accum_var = 0;
  26442. unsigned samples = 0;
  26443. struct rarch_state *p_rarch = &rarch_st;
  26444. #ifdef HAVE_THREADS
  26445. if (VIDEO_DRIVER_IS_THREADED_INTERNAL())
  26446. return false;
  26447. #endif
  26448. samples = MIN(MEASURE_FRAME_TIME_SAMPLES_COUNT,
  26449. (unsigned)p_rarch->video_driver_frame_time_count);
  26450. if (samples < 2)
  26451. return false;
  26452. /* Measure statistics on frame time (microsecs), *not* FPS. */
  26453. for (i = 0; i < samples; i++)
  26454. {
  26455. accum += p_rarch->video_driver_frame_time_samples[i];
  26456. #if 0
  26457. RARCH_LOG("[Video]: Interval #%u: %d usec / frame.\n",
  26458. i, (int)frame_time_samples[i]);
  26459. #endif
  26460. }
  26461. avg = accum / samples;
  26462. /* Drop first measurement. It is likely to be bad. */
  26463. for (i = 0; i < samples; i++)
  26464. {
  26465. retro_time_t diff = p_rarch->video_driver_frame_time_samples[i] - avg;
  26466. accum_var += diff * diff;
  26467. }
  26468. *deviation = sqrt((double)accum_var / (samples - 1)) / avg;
  26469. if (refresh_rate)
  26470. *refresh_rate = 1000000.0 / avg;
  26471. if (sample_points)
  26472. *sample_points = samples;
  26473. return true;
  26474. }
  26475. float video_driver_get_aspect_ratio(void)
  26476. {
  26477. struct rarch_state *p_rarch = &rarch_st;
  26478. return p_rarch->video_driver_aspect_ratio;
  26479. }
  26480. void video_driver_set_aspect_ratio_value(float value)
  26481. {
  26482. struct rarch_state *p_rarch = &rarch_st;
  26483. p_rarch->video_driver_aspect_ratio = value;
  26484. }
  26485. enum retro_pixel_format video_driver_get_pixel_format(void)
  26486. {
  26487. struct rarch_state *p_rarch = &rarch_st;
  26488. return p_rarch->video_driver_pix_fmt;
  26489. }
  26490. /**
  26491. * video_driver_cached_frame:
  26492. *
  26493. * Renders the current video frame.
  26494. **/
  26495. void video_driver_cached_frame(void)
  26496. {
  26497. struct rarch_state *p_rarch = &rarch_st;
  26498. void *recording = p_rarch->recording_data;
  26499. struct retro_callbacks *cbs = &p_rarch->retro_ctx;
  26500. /* Cannot allow recording when pushing duped frames. */
  26501. p_rarch->recording_data = NULL;
  26502. if (p_rarch->current_core.inited)
  26503. cbs->frame_cb(
  26504. (p_rarch->frame_cache_data != RETRO_HW_FRAME_BUFFER_VALID)
  26505. ? p_rarch->frame_cache_data : NULL,
  26506. p_rarch->frame_cache_width,
  26507. p_rarch->frame_cache_height,
  26508. p_rarch->frame_cache_pitch);
  26509. p_rarch->recording_data = recording;
  26510. }
  26511. static void video_driver_monitor_adjust_system_rates(
  26512. struct rarch_state *p_rarch)
  26513. {
  26514. float timing_skew = 0.0f;
  26515. settings_t *settings = p_rarch->configuration_settings;
  26516. const struct retro_system_timing *info = (const struct retro_system_timing*)
  26517. &p_rarch->video_driver_av_info.timing;
  26518. float video_refresh_rate = settings->floats.video_refresh_rate;
  26519. bool vrr_runloop_enable = settings->bools.vrr_runloop_enable;
  26520. float audio_max_timing_skew = settings->floats.audio_max_timing_skew;
  26521. float timing_skew_hz = video_refresh_rate;
  26522. if (!info || info->fps <= 0.0)
  26523. return;
  26524. p_rarch->video_driver_core_hz = info->fps;
  26525. if (p_rarch->video_driver_crt_switching_active)
  26526. timing_skew_hz = p_rarch->video_driver_core_hz;
  26527. timing_skew = fabs(
  26528. 1.0f - info->fps / timing_skew_hz);
  26529. if (!vrr_runloop_enable)
  26530. {
  26531. /* We don't want to adjust pitch too much. If we have extreme cases,
  26532. * just don't readjust at all. */
  26533. if (timing_skew <= audio_max_timing_skew)
  26534. return;
  26535. RARCH_LOG("[Video]: Timings deviate too much. Will not adjust."
  26536. " (Display = %.2f Hz, Game = %.2f Hz)\n",
  26537. video_refresh_rate,
  26538. (float)info->fps);
  26539. }
  26540. if (info->fps <= timing_skew_hz)
  26541. return;
  26542. /* We won't be able to do VSync reliably when game FPS > monitor FPS. */
  26543. p_rarch->runloop_force_nonblock = true;
  26544. RARCH_LOG("[Video]: Game FPS > Monitor FPS. Cannot rely on VSync.\n");
  26545. }
  26546. static void video_driver_lock_new(void)
  26547. {
  26548. #ifdef HAVE_THREADS
  26549. struct rarch_state *p_rarch = &rarch_st;
  26550. #endif
  26551. VIDEO_DRIVER_LOCK_FREE();
  26552. #ifdef HAVE_THREADS
  26553. if (!p_rarch->display_lock)
  26554. p_rarch->display_lock = slock_new();
  26555. retro_assert(p_rarch->display_lock);
  26556. if (!p_rarch->context_lock)
  26557. p_rarch->context_lock = slock_new();
  26558. retro_assert(p_rarch->context_lock);
  26559. #endif
  26560. }
  26561. void video_driver_set_cached_frame_ptr(const void *data)
  26562. {
  26563. struct rarch_state *p_rarch = &rarch_st;
  26564. if (data)
  26565. p_rarch->frame_cache_data = data;
  26566. }
  26567. void video_driver_set_stub_frame(void)
  26568. {
  26569. struct rarch_state *p_rarch = &rarch_st;
  26570. p_rarch->frame_bak = p_rarch->current_video->frame;
  26571. p_rarch->current_video->frame = video_null.frame;
  26572. }
  26573. void video_driver_unset_stub_frame(void)
  26574. {
  26575. struct rarch_state *p_rarch = &rarch_st;
  26576. if (p_rarch->frame_bak)
  26577. p_rarch->current_video->frame = p_rarch->frame_bak;
  26578. p_rarch->frame_bak = NULL;
  26579. }
  26580. bool video_driver_supports_viewport_read(void)
  26581. {
  26582. struct rarch_state *p_rarch = &rarch_st;
  26583. return p_rarch->current_video->read_viewport
  26584. && p_rarch->current_video->viewport_info;
  26585. }
  26586. bool video_driver_prefer_viewport_read(void)
  26587. {
  26588. struct rarch_state *p_rarch = &rarch_st;
  26589. settings_t *settings = p_rarch->configuration_settings;
  26590. #ifdef HAVE_SCREENSHOTS
  26591. bool video_gpu_screenshot = settings->bools.video_gpu_screenshot;
  26592. if (video_gpu_screenshot)
  26593. return true;
  26594. #endif
  26595. return (video_driver_is_hw_context() &&
  26596. !p_rarch->current_video->read_frame_raw);
  26597. }
  26598. bool video_driver_supports_read_frame_raw(void)
  26599. {
  26600. struct rarch_state *p_rarch = &rarch_st;
  26601. if (p_rarch->current_video->read_frame_raw)
  26602. return true;
  26603. return false;
  26604. }
  26605. void video_driver_set_viewport_core(void)
  26606. {
  26607. struct rarch_state *p_rarch = &rarch_st;
  26608. struct retro_game_geometry *geom = &p_rarch->video_driver_av_info.geometry;
  26609. if (!geom || geom->base_width <= 0.0f || geom->base_height <= 0.0f)
  26610. return;
  26611. /* Fallback to 1:1 pixel ratio if none provided */
  26612. if (geom->aspect_ratio > 0.0f)
  26613. aspectratio_lut[ASPECT_RATIO_CORE].value = geom->aspect_ratio;
  26614. else
  26615. aspectratio_lut[ASPECT_RATIO_CORE].value =
  26616. (float)geom->base_width / geom->base_height;
  26617. }
  26618. void video_driver_reset_custom_viewport(void)
  26619. {
  26620. struct video_viewport *custom_vp = video_viewport_get_custom();
  26621. custom_vp->width = 0;
  26622. custom_vp->height = 0;
  26623. custom_vp->x = 0;
  26624. custom_vp->y = 0;
  26625. }
  26626. void video_driver_set_rgba(void)
  26627. {
  26628. struct rarch_state *p_rarch = &rarch_st;
  26629. VIDEO_DRIVER_LOCK();
  26630. p_rarch->video_driver_use_rgba = true;
  26631. VIDEO_DRIVER_UNLOCK();
  26632. }
  26633. void video_driver_unset_rgba(void)
  26634. {
  26635. struct rarch_state *p_rarch = &rarch_st;
  26636. VIDEO_DRIVER_LOCK();
  26637. p_rarch->video_driver_use_rgba = false;
  26638. VIDEO_DRIVER_UNLOCK();
  26639. }
  26640. bool video_driver_supports_rgba(void)
  26641. {
  26642. bool tmp;
  26643. struct rarch_state *p_rarch = &rarch_st;
  26644. VIDEO_DRIVER_LOCK();
  26645. tmp = p_rarch->video_driver_use_rgba;
  26646. VIDEO_DRIVER_UNLOCK();
  26647. return tmp;
  26648. }
  26649. bool video_driver_get_next_video_out(void)
  26650. {
  26651. struct rarch_state *p_rarch = &rarch_st;
  26652. if ( !p_rarch->video_driver_poke
  26653. || !p_rarch->video_driver_poke->get_video_output_next
  26654. )
  26655. return false;
  26656. p_rarch->video_driver_poke->get_video_output_next(
  26657. p_rarch->video_driver_data);
  26658. return true;
  26659. }
  26660. bool video_driver_get_prev_video_out(void)
  26661. {
  26662. struct rarch_state *p_rarch = &rarch_st;
  26663. if (
  26664. !p_rarch->video_driver_poke
  26665. || !p_rarch->video_driver_poke->get_video_output_prev
  26666. )
  26667. return false;
  26668. p_rarch->video_driver_poke->get_video_output_prev(
  26669. p_rarch->video_driver_data);
  26670. return true;
  26671. }
  26672. void video_driver_monitor_reset(void)
  26673. {
  26674. struct rarch_state *p_rarch = &rarch_st;
  26675. p_rarch->video_driver_frame_time_count = 0;
  26676. }
  26677. void video_driver_set_aspect_ratio(void)
  26678. {
  26679. struct rarch_state *p_rarch = &rarch_st;
  26680. settings_t *settings = p_rarch->configuration_settings;
  26681. unsigned aspect_ratio_idx = settings->uints.video_aspect_ratio_idx;
  26682. switch (aspect_ratio_idx)
  26683. {
  26684. case ASPECT_RATIO_SQUARE:
  26685. video_driver_set_viewport_square_pixel(&p_rarch->video_driver_av_info.geometry);
  26686. break;
  26687. case ASPECT_RATIO_CORE:
  26688. video_driver_set_viewport_core();
  26689. break;
  26690. case ASPECT_RATIO_CONFIG:
  26691. video_driver_set_viewport_config(&p_rarch->video_driver_av_info.geometry, settings);
  26692. break;
  26693. default:
  26694. break;
  26695. }
  26696. video_driver_set_aspect_ratio_value(
  26697. aspectratio_lut[aspect_ratio_idx].value);
  26698. if ( p_rarch->video_driver_poke &&
  26699. p_rarch->video_driver_poke->set_aspect_ratio)
  26700. p_rarch->video_driver_poke->set_aspect_ratio(
  26701. p_rarch->video_driver_data, aspect_ratio_idx);
  26702. }
  26703. void video_driver_update_viewport(
  26704. struct video_viewport* vp, bool force_full, bool keep_aspect)
  26705. {
  26706. struct rarch_state *p_rarch = &rarch_st;
  26707. float device_aspect = (float)vp->full_width / vp->full_height;
  26708. settings_t *settings = p_rarch->configuration_settings;
  26709. bool video_scale_integer = settings->bools.video_scale_integer;
  26710. unsigned video_aspect_ratio_idx = settings->uints.video_aspect_ratio_idx;
  26711. float video_driver_aspect_ratio = p_rarch->video_driver_aspect_ratio;
  26712. vp->x = 0;
  26713. vp->y = 0;
  26714. vp->width = vp->full_width;
  26715. vp->height = vp->full_height;
  26716. if (video_scale_integer && !force_full)
  26717. video_viewport_get_scaled_integer(
  26718. vp,
  26719. vp->full_width,
  26720. vp->full_height,
  26721. video_driver_aspect_ratio, keep_aspect);
  26722. else if (keep_aspect && !force_full)
  26723. {
  26724. float desired_aspect = video_driver_aspect_ratio;
  26725. #if defined(HAVE_MENU)
  26726. if (video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
  26727. {
  26728. const struct video_viewport* custom = video_viewport_get_custom();
  26729. vp->x = custom->x;
  26730. vp->y = custom->y;
  26731. vp->width = custom->width;
  26732. vp->height = custom->height;
  26733. }
  26734. else
  26735. #endif
  26736. {
  26737. float delta;
  26738. if (fabsf(device_aspect - desired_aspect) < 0.0001f)
  26739. {
  26740. /* If the aspect ratios of screen and desired aspect
  26741. * ratio are sufficiently equal (floating point stuff),
  26742. * assume they are actually equal.
  26743. */
  26744. }
  26745. else if (device_aspect > desired_aspect)
  26746. {
  26747. delta = (desired_aspect / device_aspect - 1.0f)
  26748. / 2.0f + 0.5f;
  26749. vp->x = (int)roundf(vp->full_width * (0.5f - delta));
  26750. vp->width = (unsigned)roundf(2.0f * vp->full_width * delta);
  26751. vp->y = 0;
  26752. vp->height = vp->full_height;
  26753. }
  26754. else
  26755. {
  26756. vp->x = 0;
  26757. vp->width = vp->full_width;
  26758. delta = (device_aspect / desired_aspect - 1.0f)
  26759. / 2.0f + 0.5f;
  26760. vp->y = (int)roundf(vp->full_height * (0.5f - delta));
  26761. vp->height = (unsigned)roundf(2.0f * vp->full_height * delta);
  26762. }
  26763. }
  26764. }
  26765. #if defined(RARCH_MOBILE)
  26766. /* In portrait mode, we want viewport to gravitate to top of screen. */
  26767. if (device_aspect < 1.0f)
  26768. vp->y = 0;
  26769. #endif
  26770. }
  26771. void video_driver_show_mouse(void)
  26772. {
  26773. struct rarch_state *p_rarch = &rarch_st;
  26774. if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->show_mouse)
  26775. p_rarch->video_driver_poke->show_mouse(p_rarch->video_driver_data, true);
  26776. }
  26777. void video_driver_hide_mouse(void)
  26778. {
  26779. struct rarch_state *p_rarch = &rarch_st;
  26780. if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->show_mouse)
  26781. p_rarch->video_driver_poke->show_mouse(p_rarch->video_driver_data, false);
  26782. }
  26783. static void video_driver_save_as_cached(struct rarch_state *p_rarch,
  26784. settings_t *settings, const char *rdr_context_name)
  26785. {
  26786. RARCH_LOG("[Video]: \"%s\" saved as cached driver.\n",
  26787. settings->arrays.video_driver);
  26788. strlcpy(p_rarch->cached_video_driver,
  26789. settings->arrays.video_driver,
  26790. sizeof(p_rarch->cached_video_driver));
  26791. configuration_set_string(settings,
  26792. settings->arrays.video_driver,
  26793. rdr_context_name);
  26794. }
  26795. static void video_driver_restore_cached(struct rarch_state *p_rarch,
  26796. settings_t *settings)
  26797. {
  26798. if (p_rarch->cached_video_driver[0])
  26799. {
  26800. configuration_set_string(settings,
  26801. settings->arrays.video_driver, p_rarch->cached_video_driver);
  26802. p_rarch->cached_video_driver[0] = 0;
  26803. RARCH_LOG("[Video]: Restored video driver to \"%s\".\n",
  26804. settings->arrays.video_driver);
  26805. }
  26806. }
  26807. static bool video_driver_find_driver(struct rarch_state *p_rarch)
  26808. {
  26809. int i;
  26810. settings_t *settings = p_rarch->configuration_settings;
  26811. if (video_driver_is_hw_context())
  26812. {
  26813. struct retro_hw_render_callback *hwr =
  26814. VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
  26815. int rdr_major = hwr->version_major;
  26816. int rdr_minor = hwr->version_minor;
  26817. const char *rdr_context_name = hw_render_context_name(hwr->context_type, rdr_major, rdr_minor);
  26818. enum retro_hw_context_type rdr_type = hw_render_context_type(rdr_context_name);
  26819. p_rarch->current_video = NULL;
  26820. if (hwr)
  26821. {
  26822. switch (rdr_type)
  26823. {
  26824. case RETRO_HW_CONTEXT_OPENGL_CORE:
  26825. case RETRO_HW_CONTEXT_VULKAN:
  26826. case RETRO_HW_CONTEXT_DIRECT3D:
  26827. #if defined(HAVE_VULKAN) || defined(HAVE_D3D11) || defined(HAVE_D3D9) || defined(HAVE_OPENGL_CORE)
  26828. RARCH_LOG("[Video]: Using HW render, %s driver forced.\n",
  26829. rdr_context_name);
  26830. if (!string_is_equal(settings->arrays.video_driver,
  26831. rdr_context_name))
  26832. video_driver_save_as_cached(p_rarch, settings, rdr_context_name);
  26833. p_rarch->current_video = hw_render_context_driver(rdr_type, rdr_major, rdr_minor);
  26834. return true;
  26835. #else
  26836. break;
  26837. #endif
  26838. case RETRO_HW_CONTEXT_OPENGL:
  26839. #if defined(HAVE_OPENGL)
  26840. RARCH_LOG("[Video]: Using HW render, OpenGL driver forced.\n");
  26841. /* If we have configured one of the HW render
  26842. * capable GL drivers, go with that. */
  26843. #if defined(HAVE_OPENGL_CORE)
  26844. if ( !string_is_equal(settings->arrays.video_driver, "gl") &&
  26845. !string_is_equal(settings->arrays.video_driver, "glcore"))
  26846. {
  26847. video_driver_save_as_cached(p_rarch, settings, "glcore");
  26848. p_rarch->current_video = &video_gl_core;
  26849. return true;
  26850. }
  26851. #else
  26852. if ( !string_is_equal(settings->arrays.video_driver, "gl"))
  26853. {
  26854. video_driver_save_as_cached(p_rarch, settings, "gl");
  26855. p_rarch->current_video = &video_gl2;
  26856. return true;
  26857. }
  26858. #endif
  26859. RARCH_LOG("[Video]: Using configured \"%s\""
  26860. " driver for GL HW render.\n",
  26861. settings->arrays.video_driver);
  26862. break;
  26863. #endif
  26864. default:
  26865. case RETRO_HW_CONTEXT_NONE:
  26866. break;
  26867. }
  26868. }
  26869. }
  26870. if (frontend_driver_has_get_video_driver_func())
  26871. {
  26872. if ((p_rarch->current_video = (video_driver_t*)
  26873. frontend_driver_get_video_driver()))
  26874. return true;
  26875. RARCH_WARN("[Video]: Frontend supports get_video_driver() but did not specify one.\n");
  26876. }
  26877. i = (int)driver_find_index(
  26878. "video_driver",
  26879. settings->arrays.video_driver);
  26880. if (i >= 0)
  26881. p_rarch->current_video = (video_driver_t*)video_drivers[i];
  26882. else
  26883. {
  26884. if (verbosity_is_enabled())
  26885. {
  26886. unsigned d;
  26887. RARCH_ERR("Couldn't find any video driver named \"%s\"\n",
  26888. settings->arrays.video_driver);
  26889. RARCH_LOG_OUTPUT("Available video drivers are:\n");
  26890. for (d = 0; video_drivers[d]; d++)
  26891. RARCH_LOG_OUTPUT("\t%s\n", video_drivers[d]->ident);
  26892. RARCH_WARN("Going to default to first video driver...\n");
  26893. }
  26894. if (!(p_rarch->current_video = (video_driver_t*)video_drivers[0]))
  26895. retroarch_fail(1, "find_video_driver()");
  26896. }
  26897. return true;
  26898. }
  26899. void video_driver_apply_state_changes(void)
  26900. {
  26901. struct rarch_state *p_rarch = &rarch_st;
  26902. if ( p_rarch->video_driver_poke &&
  26903. p_rarch->video_driver_poke->apply_state_changes)
  26904. p_rarch->video_driver_poke->apply_state_changes(
  26905. p_rarch->video_driver_data);
  26906. }
  26907. bool video_driver_read_viewport(uint8_t *buffer, bool is_idle)
  26908. {
  26909. struct rarch_state *p_rarch = &rarch_st;
  26910. if ( p_rarch->current_video->read_viewport
  26911. && p_rarch->current_video->read_viewport(
  26912. p_rarch->video_driver_data, buffer, is_idle))
  26913. return true;
  26914. return false;
  26915. }
  26916. static void video_driver_reinit_context(struct rarch_state *p_rarch,
  26917. int flags)
  26918. {
  26919. /* RARCH_DRIVER_CTL_UNINIT clears the callback struct so we
  26920. * need to make sure to keep a copy */
  26921. struct retro_hw_render_callback hwr_copy;
  26922. struct retro_hw_render_callback *hwr =
  26923. VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
  26924. const struct retro_hw_render_context_negotiation_interface *iface =
  26925. p_rarch->hw_render_context_negotiation;
  26926. memcpy(&hwr_copy, hwr, sizeof(hwr_copy));
  26927. driver_uninit(p_rarch, flags);
  26928. memcpy(hwr, &hwr_copy, sizeof(*hwr));
  26929. p_rarch->hw_render_context_negotiation = iface;
  26930. drivers_init(p_rarch, flags);
  26931. }
  26932. void video_driver_reinit(int flags)
  26933. {
  26934. struct rarch_state *p_rarch = &rarch_st;
  26935. struct retro_hw_render_callback *hwr =
  26936. VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
  26937. p_rarch->video_driver_cache_context = (hwr->cache_context != false);
  26938. p_rarch->video_driver_cache_context_ack = false;
  26939. video_driver_reinit_context(p_rarch, flags);
  26940. p_rarch->video_driver_cache_context = false;
  26941. }
  26942. bool video_driver_is_hw_context(void)
  26943. {
  26944. bool is_hw_context = false;
  26945. struct rarch_state *p_rarch = &rarch_st;
  26946. VIDEO_DRIVER_CONTEXT_LOCK();
  26947. is_hw_context = (p_rarch->hw_render.context_type
  26948. != RETRO_HW_CONTEXT_NONE);
  26949. VIDEO_DRIVER_CONTEXT_UNLOCK();
  26950. return is_hw_context;
  26951. }
  26952. const struct retro_hw_render_context_negotiation_interface *
  26953. video_driver_get_context_negotiation_interface(void)
  26954. {
  26955. struct rarch_state *p_rarch = &rarch_st;
  26956. return p_rarch->hw_render_context_negotiation;
  26957. }
  26958. bool video_driver_is_video_cache_context(void)
  26959. {
  26960. struct rarch_state *p_rarch = &rarch_st;
  26961. return p_rarch->video_driver_cache_context;
  26962. }
  26963. void video_driver_set_video_cache_context_ack(void)
  26964. {
  26965. struct rarch_state *p_rarch = &rarch_st;
  26966. p_rarch->video_driver_cache_context_ack = true;
  26967. }
  26968. bool video_driver_get_viewport_info(struct video_viewport *viewport)
  26969. {
  26970. struct rarch_state *p_rarch = &rarch_st;
  26971. if (!p_rarch->current_video || !p_rarch->current_video->viewport_info)
  26972. return false;
  26973. p_rarch->current_video->viewport_info(
  26974. p_rarch->video_driver_data, viewport);
  26975. return true;
  26976. }
  26977. /**
  26978. * video_viewport_get_scaled_integer:
  26979. * @vp : Viewport handle
  26980. * @width : Width.
  26981. * @height : Height.
  26982. * @aspect_ratio : Aspect ratio (in float).
  26983. * @keep_aspect : Preserve aspect ratio?
  26984. *
  26985. * Gets viewport scaling dimensions based on
  26986. * scaled integer aspect ratio.
  26987. **/
  26988. void video_viewport_get_scaled_integer(struct video_viewport *vp,
  26989. unsigned width, unsigned height,
  26990. float aspect_ratio, bool keep_aspect)
  26991. {
  26992. int padding_x = 0;
  26993. int padding_y = 0;
  26994. struct rarch_state *p_rarch = &rarch_st;
  26995. settings_t *settings = p_rarch->configuration_settings;
  26996. unsigned video_aspect_ratio_idx = settings->uints.video_aspect_ratio_idx;
  26997. if (video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
  26998. {
  26999. struct video_viewport *custom = video_viewport_get_custom();
  27000. if (custom)
  27001. {
  27002. padding_x = width - custom->width;
  27003. padding_y = height - custom->height;
  27004. width = custom->width;
  27005. height = custom->height;
  27006. }
  27007. }
  27008. else
  27009. {
  27010. unsigned base_width;
  27011. /* Use system reported sizes as these define the
  27012. * geometry for the "normal" case. */
  27013. unsigned base_height =
  27014. p_rarch->video_driver_av_info.geometry.base_height;
  27015. unsigned int rotation = retroarch_get_rotation();
  27016. if (rotation % 2)
  27017. base_height = p_rarch->video_driver_av_info.geometry.base_width;
  27018. if (base_height == 0)
  27019. base_height = 1;
  27020. /* Account for non-square pixels.
  27021. * This is sort of contradictory with the goal of integer scale,
  27022. * but it is desirable in some cases.
  27023. *
  27024. * If square pixels are used, base_height will be equal to
  27025. * system->av_info.base_height. */
  27026. base_width = (unsigned)roundf(base_height * aspect_ratio);
  27027. /* Make sure that we don't get 0x scale ... */
  27028. if (width >= base_width && height >= base_height)
  27029. {
  27030. if (keep_aspect)
  27031. {
  27032. /* X/Y scale must be same. */
  27033. unsigned max_scale = MIN(width / base_width,
  27034. height / base_height);
  27035. padding_x = width - base_width * max_scale;
  27036. padding_y = height - base_height * max_scale;
  27037. }
  27038. else
  27039. {
  27040. /* X/Y can be independent, each scaled as much as possible. */
  27041. padding_x = width % base_width;
  27042. padding_y = height % base_height;
  27043. }
  27044. }
  27045. width -= padding_x;
  27046. height -= padding_y;
  27047. }
  27048. vp->width = width;
  27049. vp->height = height;
  27050. vp->x = padding_x / 2;
  27051. vp->y = padding_y / 2;
  27052. }
  27053. struct video_viewport *video_viewport_get_custom(void)
  27054. {
  27055. struct rarch_state *p_rarch = &rarch_st;
  27056. settings_t *settings = p_rarch->configuration_settings;
  27057. return &settings->video_viewport_custom;
  27058. }
  27059. /**
  27060. * video_driver_frame:
  27061. * @data : pointer to data of the video frame.
  27062. * @width : width of the video frame.
  27063. * @height : height of the video frame.
  27064. * @pitch : pitch of the video frame.
  27065. *
  27066. * Video frame render callback function.
  27067. **/
  27068. static void video_driver_frame(const void *data, unsigned width,
  27069. unsigned height, size_t pitch)
  27070. {
  27071. char status_text[128];
  27072. static char video_driver_msg[256];
  27073. static retro_time_t curr_time;
  27074. static retro_time_t fps_time;
  27075. static float last_fps, frame_time;
  27076. static uint64_t last_used_memory, last_total_memory;
  27077. retro_time_t new_time;
  27078. video_frame_info_t video_info;
  27079. struct rarch_state *p_rarch = &rarch_st;
  27080. const enum retro_pixel_format
  27081. video_driver_pix_fmt = p_rarch->video_driver_pix_fmt;
  27082. bool runloop_idle = p_rarch->runloop_idle;
  27083. bool video_driver_active = p_rarch->video_driver_active;
  27084. settings_t *settings = p_rarch->configuration_settings;
  27085. #if defined(HAVE_GFX_WIDGETS)
  27086. bool widgets_active = p_rarch->widgets_active;
  27087. #endif
  27088. status_text[0] = '\0';
  27089. video_driver_msg[0] = '\0';
  27090. if (!video_driver_active)
  27091. return;
  27092. new_time = cpu_features_get_time_usec();
  27093. if (data)
  27094. p_rarch->frame_cache_data = data;
  27095. p_rarch->frame_cache_width = width;
  27096. p_rarch->frame_cache_height = height;
  27097. p_rarch->frame_cache_pitch = pitch;
  27098. if (
  27099. p_rarch->video_driver_scaler_ptr
  27100. && data
  27101. && (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_0RGB1555)
  27102. && (data != RETRO_HW_FRAME_BUFFER_VALID)
  27103. && video_pixel_frame_scale(
  27104. p_rarch->video_driver_scaler_ptr->scaler,
  27105. p_rarch->video_driver_scaler_ptr->scaler_out,
  27106. data, width, height, pitch)
  27107. )
  27108. {
  27109. data = p_rarch->video_driver_scaler_ptr->scaler_out;
  27110. pitch = p_rarch->video_driver_scaler_ptr->scaler->out_stride;
  27111. }
  27112. video_driver_build_info(&video_info);
  27113. /* Get the amount of frames per seconds. */
  27114. if (p_rarch->video_driver_frame_count)
  27115. {
  27116. unsigned fps_update_interval =
  27117. settings->uints.fps_update_interval;
  27118. unsigned memory_update_interval =
  27119. settings->uints.memory_update_interval;
  27120. size_t buf_pos = 1;
  27121. /* set this to 1 to avoid an offset issue */
  27122. unsigned write_index =
  27123. p_rarch->video_driver_frame_time_count++ &
  27124. (MEASURE_FRAME_TIME_SAMPLES_COUNT - 1);
  27125. frame_time = new_time - fps_time;
  27126. p_rarch->video_driver_frame_time_samples
  27127. [write_index] = frame_time;
  27128. fps_time = new_time;
  27129. if (video_info.fps_show)
  27130. buf_pos = snprintf(
  27131. status_text, sizeof(status_text),
  27132. "FPS: %6.2f", last_fps);
  27133. if (video_info.framecount_show)
  27134. {
  27135. char frames_text[64];
  27136. if (status_text[buf_pos-1] != '\0')
  27137. strlcat(status_text, " || ", sizeof(status_text));
  27138. snprintf(frames_text,
  27139. sizeof(frames_text),
  27140. "%s: %" PRIu64, msg_hash_to_str(MSG_FRAMES),
  27141. (uint64_t)p_rarch->video_driver_frame_count);
  27142. buf_pos = strlcat(status_text, frames_text, sizeof(status_text));
  27143. }
  27144. if (video_info.memory_show)
  27145. {
  27146. char mem[128];
  27147. if ((p_rarch->video_driver_frame_count % memory_update_interval) == 0)
  27148. {
  27149. last_total_memory = frontend_driver_get_total_memory();
  27150. last_used_memory = last_total_memory - frontend_driver_get_free_memory();
  27151. }
  27152. mem[0] = '\0';
  27153. snprintf(
  27154. mem, sizeof(mem), "MEM: %.2f/%.2fMB", last_used_memory / (1024.0f * 1024.0f),
  27155. last_total_memory / (1024.0f * 1024.0f));
  27156. if (status_text[buf_pos-1] != '\0')
  27157. strlcat(status_text, " || ", sizeof(status_text));
  27158. strlcat(status_text, mem, sizeof(status_text));
  27159. }
  27160. if ((p_rarch->video_driver_frame_count % fps_update_interval) == 0)
  27161. {
  27162. last_fps = TIME_TO_FPS(curr_time, new_time,
  27163. fps_update_interval);
  27164. strlcpy(p_rarch->video_driver_window_title,
  27165. p_rarch->video_driver_title_buf,
  27166. sizeof(p_rarch->video_driver_window_title));
  27167. if (!string_is_empty(status_text))
  27168. {
  27169. strlcat(p_rarch->video_driver_window_title,
  27170. " || ", sizeof(p_rarch->video_driver_window_title));
  27171. strlcat(p_rarch->video_driver_window_title,
  27172. status_text, sizeof(p_rarch->video_driver_window_title));
  27173. }
  27174. curr_time = new_time;
  27175. p_rarch->video_driver_window_title_update = true;
  27176. }
  27177. }
  27178. else
  27179. {
  27180. curr_time = fps_time = new_time;
  27181. strlcpy(p_rarch->video_driver_window_title,
  27182. p_rarch->video_driver_title_buf,
  27183. sizeof(p_rarch->video_driver_window_title));
  27184. if (video_info.fps_show)
  27185. strlcpy(status_text,
  27186. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
  27187. sizeof(status_text));
  27188. p_rarch->video_driver_window_title_update = true;
  27189. }
  27190. /* Add core status message to status text */
  27191. if (video_info.core_status_msg_show)
  27192. {
  27193. /* Note: We need to lock a mutex here. Strictly
  27194. * speaking, runloop_core_status_msg is not part
  27195. * of the message queue, but:
  27196. * - It may be implemented as a queue in the future
  27197. * - It seems unnecessary to create a new slock_t
  27198. * object for this type of message when
  27199. * _runloop_msg_queue_lock is already available
  27200. * We therefore just call runloop_msg_queue_lock()/
  27201. * runloop_msg_queue_unlock() in this case */
  27202. RUNLOOP_MSG_QUEUE_LOCK(p_rarch);
  27203. /* Check whether duration timer has elapsed */
  27204. runloop_core_status_msg.duration -= p_rarch->anim.delta_time;
  27205. if (runloop_core_status_msg.duration < 0.0f)
  27206. {
  27207. runloop_core_status_msg.str[0] = '\0';
  27208. runloop_core_status_msg.priority = 0;
  27209. runloop_core_status_msg.duration = 0.0f;
  27210. runloop_core_status_msg.set = false;
  27211. }
  27212. else
  27213. {
  27214. /* If status text is already set, add status
  27215. * message at the end */
  27216. if (!string_is_empty(status_text))
  27217. {
  27218. strlcat(status_text,
  27219. " || ", sizeof(status_text));
  27220. strlcat(status_text,
  27221. runloop_core_status_msg.str, sizeof(status_text));
  27222. }
  27223. else
  27224. strlcpy(status_text, runloop_core_status_msg.str,
  27225. sizeof(status_text));
  27226. }
  27227. RUNLOOP_MSG_QUEUE_UNLOCK(p_rarch);
  27228. }
  27229. /* Slightly messy code,
  27230. * but we really need to do processing before blocking on VSync
  27231. * for best possible scheduling.
  27232. */
  27233. if (
  27234. (
  27235. #ifdef HAVE_VIDEO_FILTER
  27236. !p_rarch->video_driver_state_filter ||
  27237. #endif
  27238. !video_info.post_filter_record
  27239. || !data
  27240. || p_rarch->video_driver_record_gpu_buffer
  27241. ) && p_rarch->recording_data
  27242. && p_rarch->recording_driver
  27243. && p_rarch->recording_driver->push_video)
  27244. recording_dump_frame(p_rarch,
  27245. data, width, height,
  27246. pitch, runloop_idle);
  27247. #ifdef HAVE_VIDEO_FILTER
  27248. if (data && p_rarch->video_driver_state_filter)
  27249. {
  27250. unsigned output_width = 0;
  27251. unsigned output_height = 0;
  27252. unsigned output_pitch = 0;
  27253. rarch_softfilter_get_output_size(p_rarch->video_driver_state_filter,
  27254. &output_width, &output_height, width, height);
  27255. output_pitch = (output_width) * p_rarch->video_driver_state_out_bpp;
  27256. rarch_softfilter_process(p_rarch->video_driver_state_filter,
  27257. p_rarch->video_driver_state_buffer, output_pitch,
  27258. data, width, height, pitch);
  27259. if (video_info.post_filter_record
  27260. && p_rarch->recording_data
  27261. && p_rarch->recording_driver
  27262. && p_rarch->recording_driver->push_video)
  27263. recording_dump_frame(p_rarch,
  27264. p_rarch->video_driver_state_buffer,
  27265. output_width, output_height, output_pitch,
  27266. runloop_idle);
  27267. data = p_rarch->video_driver_state_buffer;
  27268. width = output_width;
  27269. height = output_height;
  27270. pitch = output_pitch;
  27271. }
  27272. #endif
  27273. if (p_rarch->runloop_msg_queue_size > 0)
  27274. {
  27275. /* If widgets are currently enabled, then
  27276. * messages were pushed to the queue before
  27277. * widgets were initialised - in this case, the
  27278. * first item in the message queue should be
  27279. * extracted and pushed to the widget message
  27280. * queue instead */
  27281. #if defined(HAVE_GFX_WIDGETS)
  27282. if (widgets_active)
  27283. {
  27284. msg_queue_entry_t msg_entry;
  27285. bool msg_found = false;
  27286. RUNLOOP_MSG_QUEUE_LOCK(p_rarch);
  27287. msg_found = msg_queue_extract(
  27288. &p_rarch->runloop_msg_queue, &msg_entry);
  27289. p_rarch->runloop_msg_queue_size = msg_queue_size(
  27290. &p_rarch->runloop_msg_queue);
  27291. RUNLOOP_MSG_QUEUE_UNLOCK(p_rarch);
  27292. if (msg_found)
  27293. gfx_widgets_msg_queue_push(
  27294. &p_rarch->dispwidget_st,
  27295. NULL,
  27296. msg_entry.msg,
  27297. roundf((float)msg_entry.duration / 60.0f * 1000.0f),
  27298. msg_entry.title,
  27299. msg_entry.icon,
  27300. msg_entry.category,
  27301. msg_entry.prio,
  27302. false,
  27303. #ifdef HAVE_MENU
  27304. p_rarch->menu_driver_alive
  27305. #else
  27306. false
  27307. #endif
  27308. );
  27309. }
  27310. /* ...otherwise, just output message via
  27311. * regular OSD notification text (if enabled) */
  27312. else if (video_info.font_enable)
  27313. #else
  27314. if (video_info.font_enable)
  27315. #endif
  27316. {
  27317. const char *msg = NULL;
  27318. RUNLOOP_MSG_QUEUE_LOCK(p_rarch);
  27319. msg = msg_queue_pull(&p_rarch->runloop_msg_queue);
  27320. p_rarch->runloop_msg_queue_size = msg_queue_size(&p_rarch->runloop_msg_queue);
  27321. if (msg)
  27322. strlcpy(video_driver_msg, msg, sizeof(video_driver_msg));
  27323. RUNLOOP_MSG_QUEUE_UNLOCK(p_rarch);
  27324. }
  27325. }
  27326. if (video_info.statistics_show)
  27327. {
  27328. audio_statistics_t audio_stats;
  27329. double stddev = 0.0;
  27330. struct retro_system_av_info *av_info = &p_rarch->video_driver_av_info;
  27331. unsigned red = 255;
  27332. unsigned green = 255;
  27333. unsigned blue = 255;
  27334. unsigned alpha = 255;
  27335. audio_stats.samples = 0;
  27336. audio_stats.average_buffer_saturation = 0.0f;
  27337. audio_stats.std_deviation_percentage = 0.0f;
  27338. audio_stats.close_to_underrun = 0.0f;
  27339. audio_stats.close_to_blocking = 0.0f;
  27340. video_monitor_fps_statistics(NULL, &stddev, NULL);
  27341. video_info.osd_stat_params.x = 0.010f;
  27342. video_info.osd_stat_params.y = 0.950f;
  27343. video_info.osd_stat_params.scale = 1.0f;
  27344. video_info.osd_stat_params.full_screen = true;
  27345. video_info.osd_stat_params.drop_x = -2;
  27346. video_info.osd_stat_params.drop_y = -2;
  27347. video_info.osd_stat_params.drop_mod = 0.3f;
  27348. video_info.osd_stat_params.drop_alpha = 1.0f;
  27349. video_info.osd_stat_params.color = COLOR_ABGR(
  27350. red, green, blue, alpha);
  27351. audio_compute_buffer_statistics(p_rarch, &audio_stats);
  27352. snprintf(video_info.stat_text,
  27353. sizeof(video_info.stat_text),
  27354. "Video Statistics:\n -Frame rate: %6.2f fps\n -Frame time: %6.2f ms\n -Frame time deviation: %.3f %%\n"
  27355. " -Frame count: %" PRIu64"\n -Viewport: %d x %d x %3.2f\n"
  27356. "Audio Statistics:\n -Average buffer saturation: %.2f %%\n -Standard deviation: %.2f %%\n -Time spent close to underrun: %.2f %%\n -Time spent close to blocking: %.2f %%\n -Sample count: %d\n"
  27357. "Core Geometry:\n -Size: %u x %u\n -Max Size: %u x %u\n -Aspect: %3.2f\nCore Timing:\n -FPS: %3.2f\n -Sample Rate: %6.2f\n",
  27358. last_fps,
  27359. frame_time / 1000.0f,
  27360. 100.0f * stddev,
  27361. p_rarch->video_driver_frame_count,
  27362. video_info.width,
  27363. video_info.height,
  27364. video_info.refresh_rate,
  27365. audio_stats.average_buffer_saturation,
  27366. audio_stats.std_deviation_percentage,
  27367. audio_stats.close_to_underrun,
  27368. audio_stats.close_to_blocking,
  27369. audio_stats.samples,
  27370. av_info->geometry.base_width,
  27371. av_info->geometry.base_height,
  27372. av_info->geometry.max_width,
  27373. av_info->geometry.max_height,
  27374. av_info->geometry.aspect_ratio,
  27375. av_info->timing.fps,
  27376. av_info->timing.sample_rate);
  27377. /* TODO/FIXME - add OSD chat text here */
  27378. }
  27379. if (p_rarch->current_video && p_rarch->current_video->frame)
  27380. p_rarch->video_driver_active = p_rarch->current_video->frame(
  27381. p_rarch->video_driver_data, data, width, height,
  27382. p_rarch->video_driver_frame_count,
  27383. (unsigned)pitch, video_driver_msg, &video_info);
  27384. p_rarch->video_driver_frame_count++;
  27385. /* Display the status text, with a higher priority. */
  27386. if ( video_info.fps_show
  27387. || video_info.framecount_show
  27388. || video_info.memory_show
  27389. || video_info.core_status_msg_show
  27390. )
  27391. {
  27392. #if defined(HAVE_GFX_WIDGETS)
  27393. if (widgets_active)
  27394. strlcpy(
  27395. p_rarch->dispwidget_st.gfx_widgets_status_text,
  27396. status_text,
  27397. sizeof(p_rarch->dispwidget_st.gfx_widgets_status_text)
  27398. );
  27399. else
  27400. #endif
  27401. {
  27402. runloop_msg_queue_push(status_text, 2, 1, true, NULL,
  27403. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  27404. }
  27405. }
  27406. /* trigger set resolution*/
  27407. if (video_info.crt_switch_resolution)
  27408. {
  27409. p_rarch->video_driver_crt_switching_active = true;
  27410. switch (video_info.crt_switch_resolution_super)
  27411. {
  27412. case 2560:
  27413. case 3840:
  27414. case 1920:
  27415. width =
  27416. video_info.crt_switch_resolution_super;
  27417. p_rarch->video_driver_crt_dynamic_super_width = false;
  27418. break;
  27419. case 1:
  27420. p_rarch->video_driver_crt_dynamic_super_width = true;
  27421. break;
  27422. default:
  27423. p_rarch->video_driver_crt_dynamic_super_width = false;
  27424. break;
  27425. }
  27426. crt_switch_res_core(
  27427. &p_rarch->crt_switch_st,
  27428. width,
  27429. height,
  27430. p_rarch->video_driver_core_hz,
  27431. video_info.crt_switch_resolution,
  27432. video_info.crt_switch_center_adjust,
  27433. video_info.crt_switch_porch_adjust,
  27434. video_info.monitor_index,
  27435. p_rarch->video_driver_crt_dynamic_super_width);
  27436. }
  27437. else if (!video_info.crt_switch_resolution)
  27438. p_rarch->video_driver_crt_switching_active = false;
  27439. }
  27440. void crt_switch_driver_reinit(void)
  27441. {
  27442. video_driver_reinit(DRIVERS_CMD_ALL);
  27443. }
  27444. void video_driver_display_type_set(enum rarch_display_type type)
  27445. {
  27446. struct rarch_state *p_rarch = &rarch_st;
  27447. p_rarch->video_driver_display_type = type;
  27448. }
  27449. uintptr_t video_driver_display_get(void)
  27450. {
  27451. struct rarch_state *p_rarch = &rarch_st;
  27452. return p_rarch->video_driver_display;
  27453. }
  27454. uintptr_t video_driver_display_userdata_get(void)
  27455. {
  27456. struct rarch_state *p_rarch = &rarch_st;
  27457. return p_rarch->video_driver_display_userdata;
  27458. }
  27459. void video_driver_display_userdata_set(uintptr_t idx)
  27460. {
  27461. struct rarch_state *p_rarch = &rarch_st;
  27462. p_rarch->video_driver_display_userdata = idx;
  27463. }
  27464. void video_driver_display_set(uintptr_t idx)
  27465. {
  27466. struct rarch_state *p_rarch = &rarch_st;
  27467. p_rarch->video_driver_display = idx;
  27468. }
  27469. enum rarch_display_type video_driver_display_type_get(void)
  27470. {
  27471. struct rarch_state *p_rarch = &rarch_st;
  27472. return p_rarch->video_driver_display_type;
  27473. }
  27474. void video_driver_window_set(uintptr_t idx)
  27475. {
  27476. struct rarch_state *p_rarch = &rarch_st;
  27477. p_rarch->video_driver_window = idx;
  27478. }
  27479. uintptr_t video_driver_window_get(void)
  27480. {
  27481. struct rarch_state *p_rarch = &rarch_st;
  27482. return p_rarch->video_driver_window;
  27483. }
  27484. bool video_driver_texture_load(void *data,
  27485. enum texture_filter_type filter_type,
  27486. uintptr_t *id)
  27487. {
  27488. struct rarch_state *p_rarch = &rarch_st;
  27489. if ( !id
  27490. || !p_rarch->video_driver_poke
  27491. || !p_rarch->video_driver_poke->load_texture)
  27492. return false;
  27493. *id = p_rarch->video_driver_poke->load_texture(
  27494. p_rarch->video_driver_data, data,
  27495. VIDEO_DRIVER_IS_THREADED_INTERNAL(),
  27496. filter_type);
  27497. return true;
  27498. }
  27499. bool video_driver_texture_unload(uintptr_t *id)
  27500. {
  27501. struct rarch_state *p_rarch = &rarch_st;
  27502. if ( !p_rarch->video_driver_poke
  27503. || !p_rarch->video_driver_poke->unload_texture)
  27504. return false;
  27505. p_rarch->video_driver_poke->unload_texture(
  27506. p_rarch->video_driver_data,
  27507. VIDEO_DRIVER_IS_THREADED_INTERNAL(),
  27508. *id);
  27509. *id = 0;
  27510. return true;
  27511. }
  27512. void video_driver_build_info(video_frame_info_t *video_info)
  27513. {
  27514. video_viewport_t *custom_vp = NULL;
  27515. struct rarch_state *p_rarch = &rarch_st;
  27516. settings_t *settings = p_rarch->configuration_settings;
  27517. #ifdef HAVE_THREADS
  27518. bool is_threaded =
  27519. VIDEO_DRIVER_IS_THREADED_INTERNAL();
  27520. VIDEO_DRIVER_THREADED_LOCK(is_threaded);
  27521. #endif
  27522. custom_vp = &settings->video_viewport_custom;
  27523. #ifdef HAVE_GFX_WIDGETS
  27524. video_info->widgets_active = p_rarch->widgets_active;
  27525. #else
  27526. video_info->widgets_active = false;
  27527. #endif
  27528. video_info->refresh_rate = settings->floats.video_refresh_rate;
  27529. video_info->crt_switch_resolution = settings->uints.crt_switch_resolution;
  27530. video_info->crt_switch_resolution_super = settings->uints.crt_switch_resolution_super;
  27531. video_info->crt_switch_center_adjust = settings->ints.crt_switch_center_adjust;
  27532. video_info->crt_switch_porch_adjust = settings->ints.crt_switch_porch_adjust;
  27533. video_info->black_frame_insertion = settings->uints.video_black_frame_insertion;
  27534. video_info->hard_sync = settings->bools.video_hard_sync;
  27535. video_info->hard_sync_frames = settings->uints.video_hard_sync_frames;
  27536. video_info->fps_show = settings->bools.video_fps_show;
  27537. video_info->memory_show = settings->bools.video_memory_show;
  27538. video_info->statistics_show = settings->bools.video_statistics_show;
  27539. video_info->framecount_show = settings->bools.video_framecount_show;
  27540. video_info->core_status_msg_show = runloop_core_status_msg.set;
  27541. video_info->aspect_ratio_idx = settings->uints.video_aspect_ratio_idx;
  27542. video_info->post_filter_record = settings->bools.video_post_filter_record;
  27543. video_info->input_menu_swap_ok_cancel_buttons = settings->bools.input_menu_swap_ok_cancel_buttons;
  27544. video_info->max_swapchain_images = settings->uints.video_max_swapchain_images;
  27545. video_info->windowed_fullscreen = settings->bools.video_windowed_fullscreen;
  27546. video_info->fullscreen = settings->bools.video_fullscreen
  27547. || p_rarch->rarch_force_fullscreen;
  27548. video_info->menu_mouse_enable = settings->bools.menu_mouse_enable;
  27549. video_info->monitor_index = settings->uints.video_monitor_index;
  27550. video_info->font_enable = settings->bools.video_font_enable;
  27551. video_info->font_msg_pos_x = settings->floats.video_msg_pos_x;
  27552. video_info->font_msg_pos_y = settings->floats.video_msg_pos_y;
  27553. video_info->font_msg_color_r = settings->floats.video_msg_color_r;
  27554. video_info->font_msg_color_g = settings->floats.video_msg_color_g;
  27555. video_info->font_msg_color_b = settings->floats.video_msg_color_b;
  27556. video_info->custom_vp_x = custom_vp->x;
  27557. video_info->custom_vp_y = custom_vp->y;
  27558. video_info->custom_vp_width = custom_vp->width;
  27559. video_info->custom_vp_height = custom_vp->height;
  27560. video_info->custom_vp_full_width = custom_vp->full_width;
  27561. video_info->custom_vp_full_height = custom_vp->full_height;
  27562. #if defined(HAVE_GFX_WIDGETS)
  27563. video_info->widgets_is_paused = p_rarch->gfx_widgets_paused;
  27564. video_info->widgets_is_fast_forwarding = p_rarch->gfx_widgets_fast_forward;
  27565. video_info->widgets_is_rewinding = p_rarch->gfx_widgets_rewinding;
  27566. #else
  27567. video_info->widgets_is_paused = false;
  27568. video_info->widgets_is_fast_forwarding = false;
  27569. video_info->widgets_is_rewinding = false;
  27570. #endif
  27571. video_info->width = p_rarch->video_driver_width;
  27572. video_info->height = p_rarch->video_driver_height;
  27573. video_info->use_rgba = p_rarch->video_driver_use_rgba;
  27574. video_info->libretro_running = false;
  27575. video_info->msg_bgcolor_enable =
  27576. settings->bools.video_msg_bgcolor_enable;
  27577. #ifdef HAVE_MENU
  27578. video_info->menu_is_alive = p_rarch->menu_driver_alive;
  27579. video_info->menu_footer_opacity = settings->floats.menu_footer_opacity;
  27580. video_info->menu_header_opacity = settings->floats.menu_header_opacity;
  27581. video_info->materialui_color_theme = settings->uints.menu_materialui_color_theme;
  27582. video_info->ozone_color_theme = settings->uints.menu_ozone_color_theme;
  27583. video_info->menu_shader_pipeline = settings->uints.menu_xmb_shader_pipeline;
  27584. video_info->xmb_theme = settings->uints.menu_xmb_theme;
  27585. video_info->xmb_color_theme = settings->uints.menu_xmb_color_theme;
  27586. video_info->timedate_enable = settings->bools.menu_timedate_enable;
  27587. video_info->battery_level_enable = settings->bools.menu_battery_level_enable;
  27588. video_info->xmb_shadows_enable =
  27589. settings->bools.menu_xmb_shadows_enable;
  27590. video_info->xmb_alpha_factor =
  27591. settings->uints.menu_xmb_alpha_factor;
  27592. video_info->menu_wallpaper_opacity =
  27593. settings->floats.menu_wallpaper_opacity;
  27594. video_info->menu_framebuffer_opacity =
  27595. settings->floats.menu_framebuffer_opacity;
  27596. video_info->libretro_running = p_rarch->current_core.game_loaded;
  27597. #else
  27598. video_info->menu_is_alive = false;
  27599. video_info->menu_footer_opacity = 0.0f;
  27600. video_info->menu_header_opacity = 0.0f;
  27601. video_info->materialui_color_theme = 0;
  27602. video_info->menu_shader_pipeline = 0;
  27603. video_info->xmb_color_theme = 0;
  27604. video_info->xmb_theme = 0;
  27605. video_info->timedate_enable = false;
  27606. video_info->battery_level_enable = false;
  27607. video_info->xmb_shadows_enable = false;
  27608. video_info->xmb_alpha_factor = 0.0f;
  27609. video_info->menu_framebuffer_opacity = 0.0f;
  27610. video_info->menu_wallpaper_opacity = 0.0f;
  27611. #endif
  27612. video_info->runloop_is_paused = p_rarch->runloop_paused;
  27613. video_info->runloop_is_slowmotion = p_rarch->runloop_slowmotion;
  27614. video_info->input_driver_nonblock_state = p_rarch->input_driver_nonblock_state;
  27615. video_info->input_driver_grab_mouse_state = p_rarch->input_driver_grab_mouse_state;
  27616. video_info->userdata = VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch, false);
  27617. #ifdef HAVE_THREADS
  27618. VIDEO_DRIVER_THREADED_UNLOCK(is_threaded);
  27619. #endif
  27620. }
  27621. /**
  27622. * video_driver_translate_coord_viewport:
  27623. * @mouse_x : Pointer X coordinate.
  27624. * @mouse_y : Pointer Y coordinate.
  27625. * @res_x : Scaled X coordinate.
  27626. * @res_y : Scaled Y coordinate.
  27627. * @res_screen_x : Scaled screen X coordinate.
  27628. * @res_screen_y : Scaled screen Y coordinate.
  27629. *
  27630. * Translates pointer [X,Y] coordinates into scaled screen
  27631. * coordinates based on viewport info.
  27632. *
  27633. * Returns: true (1) if successful, false if video driver doesn't support
  27634. * viewport info.
  27635. **/
  27636. bool video_driver_translate_coord_viewport(
  27637. struct video_viewport *vp,
  27638. int mouse_x, int mouse_y,
  27639. int16_t *res_x, int16_t *res_y,
  27640. int16_t *res_screen_x, int16_t *res_screen_y)
  27641. {
  27642. int scaled_screen_x, scaled_screen_y, scaled_x, scaled_y;
  27643. int norm_vp_width = (int)vp->width;
  27644. int norm_vp_height = (int)vp->height;
  27645. int norm_full_vp_width = (int)vp->full_width;
  27646. int norm_full_vp_height = (int)vp->full_height;
  27647. if (norm_vp_width <= 0 ||
  27648. norm_vp_height <= 0 ||
  27649. norm_full_vp_width <= 0 ||
  27650. norm_full_vp_height <= 0)
  27651. return false;
  27652. if (mouse_x >= 0 && mouse_x <= norm_full_vp_width)
  27653. scaled_screen_x = ((2 * mouse_x * 0x7fff)
  27654. / norm_full_vp_width) - 0x7fff;
  27655. else
  27656. scaled_screen_x = -0x8000; /* OOB */
  27657. if (mouse_y >= 0 && mouse_y <= norm_full_vp_height)
  27658. scaled_screen_y = ((2 * mouse_y * 0x7fff)
  27659. / norm_full_vp_height) - 0x7fff;
  27660. else
  27661. scaled_screen_y = -0x8000; /* OOB */
  27662. mouse_x -= vp->x;
  27663. mouse_y -= vp->y;
  27664. if (mouse_x >= 0 && mouse_x <= norm_vp_width)
  27665. scaled_x = ((2 * mouse_x * 0x7fff)
  27666. / norm_vp_width) - 0x7fff;
  27667. else
  27668. scaled_x = -0x8000; /* OOB */
  27669. if (mouse_y >= 0 && mouse_y <= norm_vp_height)
  27670. scaled_y = ((2 * mouse_y * 0x7fff)
  27671. / norm_vp_height) - 0x7fff;
  27672. else
  27673. scaled_y = -0x8000; /* OOB */
  27674. *res_x = scaled_x;
  27675. *res_y = scaled_y;
  27676. *res_screen_x = scaled_screen_x;
  27677. *res_screen_y = scaled_screen_y;
  27678. return true;
  27679. }
  27680. bool video_driver_has_focus(void)
  27681. {
  27682. struct rarch_state *p_rarch = &rarch_st;
  27683. return VIDEO_HAS_FOCUS(p_rarch);
  27684. }
  27685. void video_driver_get_window_title(char *buf, unsigned len)
  27686. {
  27687. struct rarch_state *p_rarch = &rarch_st;
  27688. if (buf && p_rarch->video_driver_window_title_update)
  27689. {
  27690. struct rarch_state *p_rarch = &rarch_st;
  27691. strlcpy(buf, p_rarch->video_driver_window_title, len);
  27692. p_rarch->video_driver_window_title_update = false;
  27693. }
  27694. }
  27695. /**
  27696. * video_context_driver_init:
  27697. * @data : Input data.
  27698. * @ctx : Graphics context driver to initialize.
  27699. * @ident : Identifier of graphics context driver to find.
  27700. * @api : API of higher-level graphics API.
  27701. * @major : Major version number of higher-level graphics API.
  27702. * @minor : Minor version number of higher-level graphics API.
  27703. * @hw_render_ctx : Request a graphics context driver capable of
  27704. * hardware rendering?
  27705. *
  27706. * Initialize graphics context driver.
  27707. *
  27708. * Returns: graphics context driver if successfully initialized,
  27709. * otherwise NULL.
  27710. **/
  27711. static const gfx_ctx_driver_t *video_context_driver_init(
  27712. void *data,
  27713. const gfx_ctx_driver_t *ctx,
  27714. const char *ident,
  27715. enum gfx_ctx_api api, unsigned major,
  27716. unsigned minor, bool hw_render_ctx,
  27717. void **ctx_data)
  27718. {
  27719. struct rarch_state *p_rarch = &rarch_st;
  27720. settings_t *settings = p_rarch->configuration_settings;
  27721. bool video_shared_context = settings->bools.video_shared_context || libretro_get_shared_context();
  27722. if (!ctx->bind_api(data, api, major, minor))
  27723. {
  27724. RARCH_WARN("Failed to bind API (#%u, version %u.%u)"
  27725. " on context driver \"%s\".\n",
  27726. (unsigned)api, major, minor, ctx->ident);
  27727. return NULL;
  27728. }
  27729. if (!(*ctx_data = ctx->init(data)))
  27730. return NULL;
  27731. if (ctx->bind_hw_render)
  27732. ctx->bind_hw_render(*ctx_data,
  27733. video_shared_context && hw_render_ctx);
  27734. return ctx;
  27735. }
  27736. #ifdef HAVE_VULKAN
  27737. static const gfx_ctx_driver_t *vk_context_driver_init_first(void *data,
  27738. const char *ident, enum gfx_ctx_api api, unsigned major,
  27739. unsigned minor, bool hw_render_ctx, void **ctx_data)
  27740. {
  27741. unsigned j;
  27742. struct rarch_state *p_rarch = &rarch_st;
  27743. int i = -1;
  27744. for (j = 0; gfx_ctx_vk_drivers[j]; j++)
  27745. {
  27746. if (string_is_equal_noncase(ident, gfx_ctx_vk_drivers[j]->ident))
  27747. {
  27748. i = j;
  27749. break;
  27750. }
  27751. }
  27752. if (i >= 0)
  27753. {
  27754. const gfx_ctx_driver_t *ctx = video_context_driver_init(data,
  27755. gfx_ctx_vk_drivers[i], ident,
  27756. api, major, minor, hw_render_ctx, ctx_data);
  27757. if (ctx)
  27758. {
  27759. p_rarch->video_context_data = *ctx_data;
  27760. return ctx;
  27761. }
  27762. }
  27763. for (i = 0; gfx_ctx_vk_drivers[i]; i++)
  27764. {
  27765. const gfx_ctx_driver_t *ctx =
  27766. video_context_driver_init(data, gfx_ctx_vk_drivers[i], ident,
  27767. api, major, minor, hw_render_ctx, ctx_data);
  27768. if (ctx)
  27769. {
  27770. p_rarch->video_context_data = *ctx_data;
  27771. return ctx;
  27772. }
  27773. }
  27774. return NULL;
  27775. }
  27776. #endif
  27777. static const gfx_ctx_driver_t *gl_context_driver_init_first(void *data,
  27778. const char *ident, enum gfx_ctx_api api, unsigned major,
  27779. unsigned minor, bool hw_render_ctx, void **ctx_data)
  27780. {
  27781. unsigned j;
  27782. struct rarch_state *p_rarch = &rarch_st;
  27783. int i = -1;
  27784. for (j = 0; gfx_ctx_gl_drivers[j]; j++)
  27785. {
  27786. if (string_is_equal_noncase(ident, gfx_ctx_gl_drivers[j]->ident))
  27787. {
  27788. i = j;
  27789. break;
  27790. }
  27791. }
  27792. if (i >= 0)
  27793. {
  27794. const gfx_ctx_driver_t *ctx = video_context_driver_init(data,
  27795. gfx_ctx_gl_drivers[i], ident,
  27796. api, major, minor, hw_render_ctx, ctx_data);
  27797. if (ctx)
  27798. {
  27799. p_rarch->video_context_data = *ctx_data;
  27800. return ctx;
  27801. }
  27802. }
  27803. for (i = 0; gfx_ctx_gl_drivers[i]; i++)
  27804. {
  27805. const gfx_ctx_driver_t *ctx =
  27806. video_context_driver_init(data, gfx_ctx_gl_drivers[i], ident,
  27807. api, major, minor, hw_render_ctx, ctx_data);
  27808. if (ctx)
  27809. {
  27810. p_rarch->video_context_data = *ctx_data;
  27811. return ctx;
  27812. }
  27813. }
  27814. return NULL;
  27815. }
  27816. /**
  27817. * video_context_driver_init_first:
  27818. * @data : Input data.
  27819. * @ident : Identifier of graphics context driver to find.
  27820. * @api : API of higher-level graphics API.
  27821. * @major : Major version number of higher-level graphics API.
  27822. * @minor : Minor version number of higher-level graphics API.
  27823. * @hw_render_ctx : Request a graphics context driver capable of
  27824. * hardware rendering?
  27825. *
  27826. * Finds first suitable graphics context driver and initializes.
  27827. *
  27828. * Returns: graphics context driver if found, otherwise NULL.
  27829. **/
  27830. const gfx_ctx_driver_t *video_context_driver_init_first(void *data,
  27831. const char *ident, enum gfx_ctx_api api, unsigned major,
  27832. unsigned minor, bool hw_render_ctx, void **ctx_data)
  27833. {
  27834. switch (api)
  27835. {
  27836. case GFX_CTX_VULKAN_API:
  27837. #ifdef HAVE_VULKAN
  27838. {
  27839. const gfx_ctx_driver_t *ptr = vk_context_driver_init_first(
  27840. data, ident, api, major, minor, hw_render_ctx, ctx_data);
  27841. if (ptr && !string_is_equal(ptr->ident, "null"))
  27842. return ptr;
  27843. /* fall-through if no valid driver was found */
  27844. }
  27845. #endif
  27846. case GFX_CTX_OPENGL_API:
  27847. case GFX_CTX_OPENGL_ES_API:
  27848. case GFX_CTX_OPENVG_API:
  27849. case GFX_CTX_METAL_API:
  27850. return gl_context_driver_init_first(data, ident, api, major, minor,
  27851. hw_render_ctx, ctx_data);
  27852. case GFX_CTX_NONE:
  27853. default:
  27854. break;
  27855. }
  27856. return NULL;
  27857. }
  27858. void video_context_driver_free(void)
  27859. {
  27860. struct rarch_state *p_rarch = &rarch_st;
  27861. video_context_driver_destroy_internal(&p_rarch->current_video_context);
  27862. p_rarch->video_context_data = NULL;
  27863. }
  27864. bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics)
  27865. {
  27866. struct rarch_state *p_rarch = &rarch_st;
  27867. if (p_rarch && p_rarch->current_video_context.get_metrics)
  27868. return p_rarch->current_video_context.get_metrics(
  27869. p_rarch->video_context_data,
  27870. metrics->type,
  27871. metrics->value);
  27872. return false;
  27873. }
  27874. bool video_context_driver_get_refresh_rate(float *refresh_rate)
  27875. {
  27876. struct rarch_state *p_rarch = &rarch_st;
  27877. if (!p_rarch->current_video_context.get_refresh_rate || !refresh_rate)
  27878. return false;
  27879. if (!p_rarch->video_context_data)
  27880. return false;
  27881. if (!p_rarch->video_driver_crt_switching_active)
  27882. {
  27883. if (refresh_rate)
  27884. *refresh_rate =
  27885. p_rarch->current_video_context.get_refresh_rate(
  27886. p_rarch->video_context_data);
  27887. }
  27888. else
  27889. {
  27890. float refresh_holder = 0;
  27891. if (refresh_rate)
  27892. refresh_holder =
  27893. p_rarch->current_video_context.get_refresh_rate(
  27894. p_rarch->video_context_data);
  27895. /* Fix for incorrect interlacing detection --
  27896. * HARD SET VSNC TO REQUIRED REFRESH FOR CRT*/
  27897. if (refresh_holder != p_rarch->video_driver_core_hz)
  27898. *refresh_rate = p_rarch->video_driver_core_hz;
  27899. }
  27900. return true;
  27901. }
  27902. bool video_context_driver_get_ident(gfx_ctx_ident_t *ident)
  27903. {
  27904. struct rarch_state *p_rarch = &rarch_st;
  27905. if (!ident)
  27906. return false;
  27907. ident->ident = p_rarch->current_video_context.ident;
  27908. return true;
  27909. }
  27910. bool video_context_driver_get_flags(gfx_ctx_flags_t *flags)
  27911. {
  27912. struct rarch_state *p_rarch = &rarch_st;
  27913. if (!p_rarch->current_video_context.get_flags)
  27914. return false;
  27915. if (p_rarch->deferred_video_context_driver_set_flags)
  27916. {
  27917. flags->flags =
  27918. p_rarch->deferred_flag_data.flags;
  27919. p_rarch->deferred_video_context_driver_set_flags = false;
  27920. return true;
  27921. }
  27922. flags->flags = p_rarch->current_video_context.get_flags(
  27923. p_rarch->video_context_data);
  27924. return true;
  27925. }
  27926. static bool video_driver_get_flags(gfx_ctx_flags_t *flags)
  27927. {
  27928. struct rarch_state *p_rarch = &rarch_st;
  27929. if (!p_rarch->video_driver_poke || !p_rarch->video_driver_poke->get_flags)
  27930. return false;
  27931. flags->flags = p_rarch->video_driver_poke->get_flags(p_rarch->video_driver_data);
  27932. return true;
  27933. }
  27934. gfx_ctx_flags_t video_driver_get_flags_wrapper(void)
  27935. {
  27936. gfx_ctx_flags_t flags;
  27937. flags.flags = 0;
  27938. if (!video_driver_get_flags(&flags))
  27939. video_context_driver_get_flags(&flags);
  27940. return flags;
  27941. }
  27942. /**
  27943. * video_driver_test_all_flags:
  27944. * @testflag : flag to test
  27945. *
  27946. * Poll both the video and context driver's flags and test
  27947. * whether @testflag is set or not.
  27948. **/
  27949. bool video_driver_test_all_flags(enum display_flags testflag)
  27950. {
  27951. gfx_ctx_flags_t flags;
  27952. if (video_driver_get_flags(&flags))
  27953. if (BIT32_GET(flags.flags, testflag))
  27954. return true;
  27955. if (video_context_driver_get_flags(&flags))
  27956. if (BIT32_GET(flags.flags, testflag))
  27957. return true;
  27958. return false;
  27959. }
  27960. bool video_context_driver_set_flags(gfx_ctx_flags_t *flags)
  27961. {
  27962. struct rarch_state *p_rarch = &rarch_st;
  27963. if (!flags)
  27964. return false;
  27965. if (p_rarch->current_video_context.set_flags)
  27966. {
  27967. p_rarch->current_video_context.set_flags(
  27968. p_rarch->video_context_data, flags->flags);
  27969. return true;
  27970. }
  27971. p_rarch->deferred_flag_data.flags = flags->flags;
  27972. p_rarch->deferred_video_context_driver_set_flags = true;
  27973. return false;
  27974. }
  27975. enum gfx_ctx_api video_context_driver_get_api(void)
  27976. {
  27977. struct rarch_state *p_rarch = &rarch_st;
  27978. enum gfx_ctx_api ctx_api = p_rarch->video_context_data ?
  27979. p_rarch->current_video_context.get_api(
  27980. p_rarch->video_context_data) : GFX_CTX_NONE;
  27981. if (ctx_api == GFX_CTX_NONE)
  27982. {
  27983. const char *video_ident = (p_rarch->current_video)
  27984. ? p_rarch->current_video->ident
  27985. : NULL;
  27986. if (string_starts_with_size(video_ident, "d3d", STRLEN_CONST("d3d")))
  27987. {
  27988. if (string_is_equal(video_ident, "d3d9"))
  27989. return GFX_CTX_DIRECT3D9_API;
  27990. else if (string_is_equal(video_ident, "d3d10"))
  27991. return GFX_CTX_DIRECT3D10_API;
  27992. else if (string_is_equal(video_ident, "d3d11"))
  27993. return GFX_CTX_DIRECT3D11_API;
  27994. else if (string_is_equal(video_ident, "d3d12"))
  27995. return GFX_CTX_DIRECT3D12_API;
  27996. }
  27997. if (string_starts_with_size(video_ident, "gl", STRLEN_CONST("gl")))
  27998. {
  27999. if (string_is_equal(video_ident, "gl"))
  28000. return GFX_CTX_OPENGL_API;
  28001. else if (string_is_equal(video_ident, "gl1"))
  28002. return GFX_CTX_OPENGL_API;
  28003. else if (string_is_equal(video_ident, "glcore"))
  28004. return GFX_CTX_OPENGL_API;
  28005. }
  28006. else if (string_is_equal(video_ident, "vulkan"))
  28007. return GFX_CTX_VULKAN_API;
  28008. else if (string_is_equal(video_ident, "metal"))
  28009. return GFX_CTX_METAL_API;
  28010. return GFX_CTX_NONE;
  28011. }
  28012. return ctx_api;
  28013. }
  28014. bool video_driver_has_windowed(void)
  28015. {
  28016. #if !(defined(RARCH_CONSOLE) || defined(RARCH_MOBILE))
  28017. struct rarch_state *p_rarch = &rarch_st;
  28018. if (p_rarch->video_driver_data && p_rarch->current_video->has_windowed)
  28019. return p_rarch->current_video->has_windowed(p_rarch->video_driver_data);
  28020. #endif
  28021. return false;
  28022. }
  28023. bool video_driver_cached_frame_has_valid_framebuffer(void)
  28024. {
  28025. struct rarch_state *p_rarch = &rarch_st;
  28026. if (p_rarch->frame_cache_data)
  28027. return (p_rarch->frame_cache_data == RETRO_HW_FRAME_BUFFER_VALID);
  28028. return false;
  28029. }
  28030. bool video_shader_driver_get_current_shader(video_shader_ctx_t *shader)
  28031. {
  28032. struct rarch_state *p_rarch = &rarch_st;
  28033. void *video_driver = VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch, true);
  28034. const video_poke_interface_t *video_poke = p_rarch->video_driver_poke;
  28035. shader->data = NULL;
  28036. if (!video_poke || !video_driver || !video_poke->get_current_shader)
  28037. return false;
  28038. shader->data = video_poke->get_current_shader(video_driver);
  28039. return true;
  28040. }
  28041. float video_driver_get_refresh_rate(void)
  28042. {
  28043. struct rarch_state *p_rarch = &rarch_st;
  28044. if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->get_refresh_rate)
  28045. return p_rarch->video_driver_poke->get_refresh_rate(p_rarch->video_driver_data);
  28046. return 0.0f;
  28047. }
  28048. #if defined(HAVE_GFX_WIDGETS)
  28049. bool video_driver_has_widgets(void)
  28050. {
  28051. struct rarch_state *p_rarch = &rarch_st;
  28052. return p_rarch->current_video
  28053. && p_rarch->current_video->gfx_widgets_enabled
  28054. && p_rarch->current_video->gfx_widgets_enabled(
  28055. p_rarch->video_driver_data);
  28056. }
  28057. #endif
  28058. void video_driver_set_gpu_device_string(const char *str)
  28059. {
  28060. struct rarch_state *p_rarch = &rarch_st;
  28061. strlcpy(p_rarch->video_driver_gpu_device_string, str,
  28062. sizeof(p_rarch->video_driver_gpu_device_string));
  28063. }
  28064. const char* video_driver_get_gpu_device_string(void)
  28065. {
  28066. struct rarch_state *p_rarch = &rarch_st;
  28067. return p_rarch->video_driver_gpu_device_string;
  28068. }
  28069. void video_driver_set_gpu_api_version_string(const char *str)
  28070. {
  28071. struct rarch_state *p_rarch = &rarch_st;
  28072. strlcpy(p_rarch->video_driver_gpu_api_version_string, str,
  28073. sizeof(p_rarch->video_driver_gpu_api_version_string));
  28074. }
  28075. const char* video_driver_get_gpu_api_version_string(void)
  28076. {
  28077. struct rarch_state *p_rarch = &rarch_st;
  28078. return p_rarch->video_driver_gpu_api_version_string;
  28079. }
  28080. /* string list stays owned by the caller and must be available at
  28081. * all times after the video driver is inited */
  28082. void video_driver_set_gpu_api_devices(
  28083. enum gfx_ctx_api api, struct string_list *list)
  28084. {
  28085. int i;
  28086. for (i = 0; i < ARRAY_SIZE(gpu_map); i++)
  28087. {
  28088. if (api == gpu_map[i].api)
  28089. {
  28090. gpu_map[i].list = list;
  28091. break;
  28092. }
  28093. }
  28094. }
  28095. struct string_list* video_driver_get_gpu_api_devices(enum gfx_ctx_api api)
  28096. {
  28097. int i;
  28098. for (i = 0; i < ARRAY_SIZE(gpu_map); i++)
  28099. {
  28100. if (api == gpu_map[i].api)
  28101. return gpu_map[i].list;
  28102. }
  28103. return NULL;
  28104. }
  28105. /* LOCATION */
  28106. /**
  28107. * config_get_location_driver_options:
  28108. *
  28109. * Get an enumerated list of all location driver names,
  28110. * separated by '|'.
  28111. *
  28112. * Returns: string listing of all location driver names,
  28113. * separated by '|'.
  28114. **/
  28115. const char* config_get_location_driver_options(void)
  28116. {
  28117. return char_list_new_special(STRING_LIST_LOCATION_DRIVERS, NULL);
  28118. }
  28119. static void find_location_driver(struct rarch_state *p_rarch)
  28120. {
  28121. settings_t *settings = p_rarch->configuration_settings;
  28122. int i = (int)driver_find_index(
  28123. "location_driver",
  28124. settings->arrays.location_driver);
  28125. if (i >= 0)
  28126. p_rarch->location_driver = (const location_driver_t*)location_drivers[i];
  28127. else
  28128. {
  28129. if (verbosity_is_enabled())
  28130. {
  28131. unsigned d;
  28132. RARCH_ERR("Couldn't find any location driver named \"%s\"\n",
  28133. settings->arrays.location_driver);
  28134. RARCH_LOG_OUTPUT("Available location drivers are:\n");
  28135. for (d = 0; location_drivers[d]; d++)
  28136. RARCH_LOG_OUTPUT("\t%s\n", location_drivers[d]->ident);
  28137. RARCH_WARN("Going to default to first location driver...\n");
  28138. }
  28139. p_rarch->location_driver = (const location_driver_t*)location_drivers[0];
  28140. if (!p_rarch->location_driver)
  28141. retroarch_fail(1, "find_location_driver()");
  28142. }
  28143. }
  28144. /**
  28145. * driver_location_start:
  28146. *
  28147. * Starts location driver interface..
  28148. * Used by RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE.
  28149. *
  28150. * Returns: true (1) if successful, otherwise false (0).
  28151. **/
  28152. static bool driver_location_start(void)
  28153. {
  28154. struct rarch_state *p_rarch = &rarch_st;
  28155. if ( p_rarch->location_driver
  28156. && p_rarch->location_data
  28157. && p_rarch->location_driver->start)
  28158. {
  28159. settings_t *settings = p_rarch->configuration_settings;
  28160. bool location_allow = settings->bools.location_allow;
  28161. if (location_allow)
  28162. return p_rarch->location_driver->start(p_rarch->location_data);
  28163. runloop_msg_queue_push("Location is explicitly disabled.\n",
  28164. 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
  28165. MESSAGE_QUEUE_CATEGORY_INFO);
  28166. }
  28167. return false;
  28168. }
  28169. /**
  28170. * driver_location_stop:
  28171. *
  28172. * Stops location driver interface..
  28173. * Used by RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE.
  28174. *
  28175. * Returns: true (1) if successful, otherwise false (0).
  28176. **/
  28177. static void driver_location_stop(void)
  28178. {
  28179. struct rarch_state *p_rarch = &rarch_st;
  28180. if ( p_rarch->location_driver
  28181. && p_rarch->location_driver->stop
  28182. && p_rarch->location_data)
  28183. p_rarch->location_driver->stop(p_rarch->location_data);
  28184. }
  28185. /**
  28186. * driver_location_set_interval:
  28187. * @interval_msecs : Interval time in milliseconds.
  28188. * @interval_distance : Distance at which to update.
  28189. *
  28190. * Sets interval update time for location driver interface.
  28191. * Used by RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE.
  28192. **/
  28193. static void driver_location_set_interval(unsigned interval_msecs,
  28194. unsigned interval_distance)
  28195. {
  28196. struct rarch_state *p_rarch = &rarch_st;
  28197. if ( p_rarch->location_driver
  28198. && p_rarch->location_driver->set_interval
  28199. && p_rarch->location_data)
  28200. p_rarch->location_driver->set_interval(p_rarch->location_data,
  28201. interval_msecs, interval_distance);
  28202. }
  28203. /**
  28204. * driver_location_get_position:
  28205. * @lat : Latitude of current position.
  28206. * @lon : Longitude of current position.
  28207. * @horiz_accuracy : Horizontal accuracy.
  28208. * @vert_accuracy : Vertical accuracy.
  28209. *
  28210. * Gets current positioning information from
  28211. * location driver interface.
  28212. * Used by RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE.
  28213. *
  28214. * Returns: bool (1) if successful, otherwise false (0).
  28215. **/
  28216. static bool driver_location_get_position(double *lat, double *lon,
  28217. double *horiz_accuracy, double *vert_accuracy)
  28218. {
  28219. struct rarch_state *p_rarch = &rarch_st;
  28220. if ( p_rarch->location_driver
  28221. && p_rarch->location_driver->get_position
  28222. && p_rarch->location_data)
  28223. return p_rarch->location_driver->get_position(p_rarch->location_data,
  28224. lat, lon, horiz_accuracy, vert_accuracy);
  28225. *lat = 0.0;
  28226. *lon = 0.0;
  28227. *horiz_accuracy = 0.0;
  28228. *vert_accuracy = 0.0;
  28229. return false;
  28230. }
  28231. static void init_location(void)
  28232. {
  28233. struct rarch_state *p_rarch = &rarch_st;
  28234. rarch_system_info_t *system = &p_rarch->runloop_system;
  28235. /* Resource leaks will follow if location interface is initialized twice. */
  28236. if (p_rarch->location_data)
  28237. return;
  28238. find_location_driver(p_rarch);
  28239. p_rarch->location_data = p_rarch->location_driver->init();
  28240. if (!p_rarch->location_data)
  28241. {
  28242. RARCH_ERR("Failed to initialize location driver. Will continue without location.\n");
  28243. p_rarch->location_driver_active = false;
  28244. }
  28245. if (system->location_cb.initialized)
  28246. system->location_cb.initialized();
  28247. }
  28248. static void uninit_location(void)
  28249. {
  28250. struct rarch_state *p_rarch = &rarch_st;
  28251. rarch_system_info_t *system = &p_rarch->runloop_system;
  28252. if (p_rarch->location_data && p_rarch->location_driver)
  28253. {
  28254. if (system->location_cb.deinitialized)
  28255. system->location_cb.deinitialized();
  28256. if (p_rarch->location_driver->free)
  28257. p_rarch->location_driver->free(p_rarch->location_data);
  28258. }
  28259. p_rarch->location_data = NULL;
  28260. }
  28261. /* CAMERA */
  28262. /**
  28263. * config_get_camera_driver_options:
  28264. *
  28265. * Get an enumerated list of all camera driver names,
  28266. * separated by '|'.
  28267. *
  28268. * Returns: string listing of all camera driver names,
  28269. * separated by '|'.
  28270. **/
  28271. const char *config_get_camera_driver_options(void)
  28272. {
  28273. return char_list_new_special(STRING_LIST_CAMERA_DRIVERS, NULL);
  28274. }
  28275. static bool driver_camera_start(void)
  28276. {
  28277. struct rarch_state *p_rarch = &rarch_st;
  28278. if ( p_rarch->camera_driver &&
  28279. p_rarch->camera_data &&
  28280. p_rarch->camera_driver->start)
  28281. {
  28282. settings_t *settings = p_rarch->configuration_settings;
  28283. bool camera_allow = settings->bools.camera_allow;
  28284. if (camera_allow)
  28285. return p_rarch->camera_driver->start(p_rarch->camera_data);
  28286. runloop_msg_queue_push(
  28287. "Camera is explicitly disabled.\n", 1, 180, false,
  28288. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  28289. }
  28290. return true;
  28291. }
  28292. static void driver_camera_stop(void)
  28293. {
  28294. struct rarch_state *p_rarch = &rarch_st;
  28295. if ( p_rarch->camera_driver
  28296. && p_rarch->camera_driver->stop
  28297. && p_rarch->camera_data)
  28298. p_rarch->camera_driver->stop(p_rarch->camera_data);
  28299. }
  28300. static void camera_driver_find_driver(struct rarch_state *p_rarch)
  28301. {
  28302. settings_t *settings = p_rarch->configuration_settings;
  28303. int i = (int)driver_find_index(
  28304. "camera_driver",
  28305. settings->arrays.camera_driver);
  28306. if (i >= 0)
  28307. p_rarch->camera_driver = (const camera_driver_t*)camera_drivers[i];
  28308. else
  28309. {
  28310. if (verbosity_is_enabled())
  28311. {
  28312. unsigned d;
  28313. RARCH_ERR("Couldn't find any camera driver named \"%s\"\n",
  28314. settings->arrays.camera_driver);
  28315. RARCH_LOG_OUTPUT("Available camera drivers are:\n");
  28316. for (d = 0; camera_drivers[d]; d++)
  28317. {
  28318. if (camera_drivers[d])
  28319. {
  28320. RARCH_LOG_OUTPUT("\t%s\n", camera_drivers[d]->ident);
  28321. }
  28322. }
  28323. RARCH_WARN("Going to default to first camera driver...\n");
  28324. }
  28325. p_rarch->camera_driver = (const camera_driver_t*)camera_drivers[0];
  28326. if (!p_rarch->camera_driver)
  28327. retroarch_fail(1, "find_camera_driver()");
  28328. }
  28329. }
  28330. static void driver_adjust_system_rates(struct rarch_state *p_rarch)
  28331. {
  28332. settings_t *settings = p_rarch->configuration_settings;
  28333. struct retro_system_av_info *av_info = &p_rarch->video_driver_av_info;
  28334. const struct retro_system_timing *info =
  28335. (const struct retro_system_timing*)&av_info->timing;
  28336. if (info->sample_rate > 0.0)
  28337. {
  28338. p_rarch->audio_driver_input =
  28339. audio_driver_monitor_adjust_system_rates(
  28340. p_rarch->configuration_settings,
  28341. &p_rarch->video_driver_av_info
  28342. );
  28343. RARCH_LOG("[Audio]: Set audio input rate to: %.2f Hz.\n",
  28344. p_rarch->audio_driver_input);
  28345. }
  28346. p_rarch->runloop_force_nonblock = false;
  28347. video_driver_monitor_adjust_system_rates(p_rarch);
  28348. if (!VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch, false))
  28349. return;
  28350. if (p_rarch->runloop_force_nonblock)
  28351. {
  28352. bool video_adaptive_vsync = settings->bools.video_adaptive_vsync;
  28353. unsigned video_swap_interval = settings->uints.video_swap_interval;
  28354. if (p_rarch->current_video->set_nonblock_state)
  28355. p_rarch->current_video->set_nonblock_state(
  28356. p_rarch->video_driver_data, true,
  28357. video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
  28358. video_adaptive_vsync,
  28359. video_swap_interval
  28360. );
  28361. }
  28362. else
  28363. driver_set_nonblock_state();
  28364. }
  28365. /**
  28366. * driver_set_nonblock_state:
  28367. *
  28368. * Sets audio and video drivers to nonblock state (if enabled).
  28369. *
  28370. * If nonblock state is false, sets
  28371. * blocking state for both audio and video drivers instead.
  28372. **/
  28373. void driver_set_nonblock_state(void)
  28374. {
  28375. struct rarch_state *p_rarch = &rarch_st;
  28376. bool enable = p_rarch->input_driver_nonblock_state;
  28377. settings_t *settings = p_rarch->configuration_settings;
  28378. bool audio_sync = settings->bools.audio_sync;
  28379. bool video_vsync = settings->bools.video_vsync;
  28380. bool adaptive_vsync = settings->bools.video_adaptive_vsync;
  28381. unsigned swap_interval = settings->uints.video_swap_interval;
  28382. bool video_driver_active = p_rarch->video_driver_active;
  28383. bool audio_driver_active = p_rarch->audio_driver_active;
  28384. bool runloop_force_nonblock = p_rarch->runloop_force_nonblock;
  28385. /* Only apply non-block-state for video if we're using vsync. */
  28386. if (video_driver_active && VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch, false))
  28387. {
  28388. if (p_rarch->current_video->set_nonblock_state)
  28389. {
  28390. bool video_nonblock = enable;
  28391. if (!video_vsync || runloop_force_nonblock)
  28392. video_nonblock = true;
  28393. p_rarch->current_video->set_nonblock_state(p_rarch->video_driver_data,
  28394. video_nonblock,
  28395. video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
  28396. adaptive_vsync, swap_interval);
  28397. }
  28398. }
  28399. if (audio_driver_active && p_rarch->audio_driver_context_audio_data)
  28400. p_rarch->current_audio->set_nonblock_state(
  28401. p_rarch->audio_driver_context_audio_data,
  28402. audio_sync ? enable : true);
  28403. p_rarch->audio_driver_chunk_size = enable
  28404. ? p_rarch->audio_driver_chunk_nonblock_size
  28405. : p_rarch->audio_driver_chunk_block_size;
  28406. }
  28407. /**
  28408. * drivers_init:
  28409. * @flags : Bitmask of drivers to initialize.
  28410. *
  28411. * Initializes drivers.
  28412. * @flags determines which drivers get initialized.
  28413. **/
  28414. static void drivers_init(struct rarch_state *p_rarch, int flags)
  28415. {
  28416. #ifdef HAVE_MENU
  28417. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  28418. #endif
  28419. bool video_is_threaded = VIDEO_DRIVER_IS_THREADED_INTERNAL();
  28420. settings_t *settings = p_rarch->configuration_settings;
  28421. #if defined(HAVE_GFX_WIDGETS)
  28422. bool video_font_enable = settings->bools.video_font_enable;
  28423. bool menu_enable_widgets = settings->bools.menu_enable_widgets;
  28424. /* By default, we want display widgets to persist through driver reinits. */
  28425. p_rarch->widgets_persisting = true;
  28426. #endif
  28427. #ifdef HAVE_MENU
  28428. /* By default, we want the menu to persist through driver reinits. */
  28429. if (menu_st)
  28430. menu_st->data_own = true;
  28431. #endif
  28432. if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK))
  28433. driver_adjust_system_rates(p_rarch);
  28434. /* Initialize video driver */
  28435. if (flags & DRIVER_VIDEO_MASK)
  28436. {
  28437. struct retro_hw_render_callback *hwr =
  28438. VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
  28439. p_rarch->video_driver_frame_time_count = 0;
  28440. video_driver_lock_new();
  28441. #ifdef HAVE_VIDEO_FILTER
  28442. video_driver_filter_free();
  28443. #endif
  28444. video_driver_set_cached_frame_ptr(NULL);
  28445. video_driver_init_internal(&video_is_threaded);
  28446. if (!p_rarch->video_driver_cache_context_ack
  28447. && hwr->context_reset)
  28448. hwr->context_reset();
  28449. p_rarch->video_driver_cache_context_ack = false;
  28450. p_rarch->runloop_frame_time_last = 0;
  28451. }
  28452. /* Initialize audio driver */
  28453. if (flags & DRIVER_AUDIO_MASK)
  28454. {
  28455. audio_driver_init_internal(p_rarch,
  28456. p_rarch->audio_callback.callback != NULL);
  28457. if ( p_rarch->current_audio &&
  28458. p_rarch->current_audio->device_list_new &&
  28459. p_rarch->audio_driver_context_audio_data)
  28460. p_rarch->audio_driver_devices_list = (struct string_list*)
  28461. p_rarch->current_audio->device_list_new(
  28462. p_rarch->audio_driver_context_audio_data);
  28463. }
  28464. if (flags & DRIVER_CAMERA_MASK)
  28465. {
  28466. /* Only initialize camera driver if we're ever going to use it. */
  28467. if (p_rarch->camera_driver_active)
  28468. {
  28469. /* Resource leaks will follow if camera is initialized twice. */
  28470. if (!p_rarch->camera_data)
  28471. {
  28472. camera_driver_find_driver(p_rarch);
  28473. if (p_rarch->camera_driver)
  28474. {
  28475. p_rarch->camera_data = p_rarch->camera_driver->init(
  28476. *settings->arrays.camera_device ?
  28477. settings->arrays.camera_device : NULL,
  28478. p_rarch->camera_cb.caps,
  28479. settings->uints.camera_width ?
  28480. settings->uints.camera_width : p_rarch->camera_cb.width,
  28481. settings->uints.camera_height ?
  28482. settings->uints.camera_height : p_rarch->camera_cb.height);
  28483. if (!p_rarch->camera_data)
  28484. {
  28485. RARCH_ERR("Failed to initialize camera driver. Will continue without camera.\n");
  28486. p_rarch->camera_driver_active = false;
  28487. }
  28488. if (p_rarch->camera_cb.initialized)
  28489. p_rarch->camera_cb.initialized();
  28490. }
  28491. }
  28492. }
  28493. }
  28494. if (flags & DRIVER_BLUETOOTH_MASK)
  28495. bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_INIT, NULL);
  28496. if ((flags & DRIVER_WIFI_MASK))
  28497. wifi_driver_ctl(RARCH_WIFI_CTL_INIT, NULL);
  28498. if (flags & DRIVER_LOCATION_MASK)
  28499. {
  28500. /* Only initialize location driver if we're ever going to use it. */
  28501. if (p_rarch->location_driver_active)
  28502. init_location();
  28503. }
  28504. core_info_init_current_core();
  28505. #if defined(HAVE_GFX_WIDGETS)
  28506. /* Note that we only enable widgets if 'video_font_enable'
  28507. * is true. 'video_font_enable' corresponds to the generic
  28508. * 'On-Screen Notifications' setting, which should serve as
  28509. * a global notifications on/off toggle switch */
  28510. if (video_font_enable &&
  28511. menu_enable_widgets &&
  28512. video_driver_has_widgets())
  28513. {
  28514. bool rarch_force_fullscreen = p_rarch->rarch_force_fullscreen;
  28515. bool video_is_fullscreen = settings->bools.video_fullscreen ||
  28516. rarch_force_fullscreen;
  28517. p_rarch->widgets_active = gfx_widgets_init(
  28518. (uintptr_t)&p_rarch->widgets_active,
  28519. video_is_threaded,
  28520. p_rarch->video_driver_width,
  28521. p_rarch->video_driver_height,
  28522. video_is_fullscreen,
  28523. settings->paths.directory_assets,
  28524. settings->paths.path_font);
  28525. }
  28526. else
  28527. #endif
  28528. {
  28529. gfx_display_init_first_driver(video_is_threaded);
  28530. }
  28531. #ifdef HAVE_MENU
  28532. if (flags & DRIVER_VIDEO_MASK)
  28533. {
  28534. /* Initialize menu driver */
  28535. if (flags & DRIVER_MENU_MASK)
  28536. {
  28537. if (!menu_driver_init(video_is_threaded))
  28538. RARCH_ERR("Unable to init menu driver.\n");
  28539. #ifdef HAVE_LIBRETRODB
  28540. menu_explore_context_init();
  28541. #endif
  28542. }
  28543. }
  28544. /* Initialising the menu driver will also initialise
  28545. * core info - if we are not initialising the menu
  28546. * driver, must initialise core info 'by hand' */
  28547. if (!(flags & DRIVER_VIDEO_MASK) ||
  28548. !(flags & DRIVER_MENU_MASK))
  28549. {
  28550. command_event(CMD_EVENT_CORE_INFO_INIT, NULL);
  28551. command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
  28552. }
  28553. #else
  28554. /* Qt uses core info, even if the menu is disabled */
  28555. command_event(CMD_EVENT_CORE_INFO_INIT, NULL);
  28556. command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
  28557. #endif
  28558. if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK))
  28559. {
  28560. /* Keep non-throttled state as good as possible. */
  28561. if (p_rarch->input_driver_nonblock_state)
  28562. driver_set_nonblock_state();
  28563. }
  28564. /* Initialize LED driver */
  28565. if (flags & DRIVER_LED_MASK)
  28566. led_driver_init(settings->arrays.led_driver);
  28567. /* Initialize MIDI driver */
  28568. if (flags & DRIVER_MIDI_MASK)
  28569. midi_driver_init(p_rarch);
  28570. }
  28571. /**
  28572. * Driver ownership - set this to true if the platform in
  28573. * question needs to 'own'
  28574. * the respective handle and therefore skip regular RetroArch
  28575. * driver teardown/reiniting procedure.
  28576. *
  28577. * If to true, the 'free' function will get skipped. It is
  28578. * then up to the driver implementation to properly handle
  28579. * 'reiniting' inside the 'init' function and make sure it
  28580. * returns the existing handle instead of allocating and
  28581. * returning a pointer to a new handle.
  28582. *
  28583. * Typically, if a driver intends to make use of this, it should
  28584. * set this to true at the end of its 'init' function.
  28585. **/
  28586. static void driver_uninit(struct rarch_state *p_rarch, int flags)
  28587. {
  28588. core_info_deinit_list();
  28589. core_info_free_current_core(&p_rarch->core_info_st);
  28590. #if defined(HAVE_GFX_WIDGETS)
  28591. /* This absolutely has to be done before video_driver_free_internal()
  28592. * is called/completes, otherwise certain menu drivers
  28593. * (e.g. Vulkan) will segfault */
  28594. if (gfx_widgets_deinit(p_rarch->widgets_persisting))
  28595. p_rarch->widgets_active = false;
  28596. #endif
  28597. #ifdef HAVE_MENU
  28598. if (flags & DRIVER_MENU_MASK)
  28599. {
  28600. #ifdef HAVE_LIBRETRODB
  28601. menu_explore_context_deinit();
  28602. #endif
  28603. menu_driver_ctl(RARCH_MENU_CTL_DEINIT, NULL);
  28604. }
  28605. #endif
  28606. if ((flags & DRIVER_LOCATION_MASK))
  28607. uninit_location();
  28608. if ((flags & DRIVER_CAMERA_MASK))
  28609. {
  28610. if (p_rarch->camera_data && p_rarch->camera_driver)
  28611. {
  28612. if (p_rarch->camera_cb.deinitialized)
  28613. p_rarch->camera_cb.deinitialized();
  28614. if (p_rarch->camera_driver->free)
  28615. p_rarch->camera_driver->free(p_rarch->camera_data);
  28616. }
  28617. p_rarch->camera_data = NULL;
  28618. }
  28619. if ((flags & DRIVER_BLUETOOTH_MASK))
  28620. bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_DEINIT, NULL);
  28621. if ((flags & DRIVER_WIFI_MASK))
  28622. wifi_driver_ctl(RARCH_WIFI_CTL_DEINIT, NULL);
  28623. if (flags & DRIVER_LED)
  28624. led_driver_free();
  28625. if (flags & DRIVERS_VIDEO_INPUT)
  28626. {
  28627. video_driver_free_internal(p_rarch);
  28628. VIDEO_DRIVER_LOCK_FREE();
  28629. p_rarch->video_driver_data = NULL;
  28630. video_driver_set_cached_frame_ptr(NULL);
  28631. }
  28632. if (flags & DRIVER_AUDIO_MASK)
  28633. audio_driver_deinit(p_rarch);
  28634. if ((flags & DRIVER_VIDEO_MASK))
  28635. p_rarch->video_driver_data = NULL;
  28636. if ((flags & DRIVER_INPUT_MASK))
  28637. p_rarch->current_input_data = NULL;
  28638. if ((flags & DRIVER_AUDIO_MASK))
  28639. p_rarch->audio_driver_context_audio_data = NULL;
  28640. if (flags & DRIVER_MIDI_MASK)
  28641. midi_driver_free(p_rarch);
  28642. }
  28643. static void retroarch_deinit_drivers(struct rarch_state *p_rarch, struct retro_callbacks *cbs)
  28644. {
  28645. #if defined(HAVE_GFX_WIDGETS)
  28646. /* Tear down display widgets no matter what
  28647. * in case the handle is lost in the threaded
  28648. * video driver in the meantime
  28649. * (breaking video_driver_has_widgets) */
  28650. if (gfx_widgets_deinit(p_rarch->widgets_persisting))
  28651. p_rarch->widgets_active = false;
  28652. #endif
  28653. /* Video */
  28654. video_display_server_destroy();
  28655. p_rarch->video_driver_use_rgba = false;
  28656. p_rarch->video_driver_active = false;
  28657. p_rarch->video_driver_cache_context = false;
  28658. p_rarch->video_driver_cache_context_ack = false;
  28659. p_rarch->video_driver_record_gpu_buffer = NULL;
  28660. p_rarch->current_video = NULL;
  28661. video_driver_set_cached_frame_ptr(NULL);
  28662. /* Audio */
  28663. p_rarch->audio_driver_active = false;
  28664. p_rarch->current_audio = NULL;
  28665. /* Input */
  28666. p_rarch->input_driver_keyboard_linefeed_enable = false;
  28667. p_rarch->input_driver_block_hotkey = false;
  28668. p_rarch->input_driver_block_libretro_input = false;
  28669. p_rarch->input_driver_nonblock_state = false;
  28670. p_rarch->input_driver_flushing_input = 0;
  28671. memset(&p_rarch->input_driver_turbo_btns, 0, sizeof(turbo_buttons_t));
  28672. p_rarch->current_input = NULL;
  28673. #ifdef HAVE_MENU
  28674. menu_driver_destroy(p_rarch,
  28675. &p_rarch->menu_driver_state);
  28676. p_rarch->menu_driver_alive = false;
  28677. #endif
  28678. p_rarch->location_driver_active = false;
  28679. p_rarch->location_driver = NULL;
  28680. /* Camera */
  28681. p_rarch->camera_driver_active = false;
  28682. p_rarch->camera_driver = NULL;
  28683. p_rarch->camera_data = NULL;
  28684. bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_DESTROY, NULL);
  28685. wifi_driver_ctl(RARCH_WIFI_CTL_DESTROY, NULL);
  28686. cbs->frame_cb = retro_frame_null;
  28687. cbs->poll_cb = retro_input_poll_null;
  28688. cbs->sample_cb = NULL;
  28689. cbs->sample_batch_cb = NULL;
  28690. cbs->state_cb = NULL;
  28691. p_rarch->current_core.inited = false;
  28692. }
  28693. bool driver_ctl(enum driver_ctl_state state, void *data)
  28694. {
  28695. struct rarch_state *p_rarch = &rarch_st;
  28696. driver_ctx_info_t *drv = (driver_ctx_info_t*)data;
  28697. switch (state)
  28698. {
  28699. case RARCH_DRIVER_CTL_SET_REFRESH_RATE:
  28700. {
  28701. float *hz = (float*)data;
  28702. video_monitor_set_refresh_rate(*hz);
  28703. /* Sets audio monitor rate to new value. */
  28704. p_rarch->audio_source_ratio_original =
  28705. p_rarch->audio_source_ratio_current =
  28706. (double)p_rarch->configuration_settings->uints.audio_out_rate
  28707. / p_rarch->audio_driver_input;
  28708. driver_adjust_system_rates(p_rarch);
  28709. }
  28710. break;
  28711. case RARCH_DRIVER_CTL_FIND_FIRST:
  28712. if (!drv)
  28713. return false;
  28714. find_driver_nonempty(drv->label, 0, drv->s, drv->len);
  28715. break;
  28716. case RARCH_DRIVER_CTL_FIND_LAST:
  28717. if (!drv)
  28718. return false;
  28719. driver_find_last(drv->label, drv->s, drv->len);
  28720. break;
  28721. case RARCH_DRIVER_CTL_FIND_PREV:
  28722. if (!drv)
  28723. return false;
  28724. return driver_find_prev(drv->label, drv->s, drv->len);
  28725. case RARCH_DRIVER_CTL_FIND_NEXT:
  28726. if (!drv)
  28727. return false;
  28728. return driver_find_next(drv->label, drv->s, drv->len);
  28729. case RARCH_DRIVER_CTL_NONE:
  28730. default:
  28731. break;
  28732. }
  28733. return true;
  28734. }
  28735. /* RUNAHEAD */
  28736. #ifdef HAVE_RUNAHEAD
  28737. static void mylist_resize(my_list *list,
  28738. int new_size, bool run_constructor)
  28739. {
  28740. int i;
  28741. int new_capacity;
  28742. int old_size;
  28743. void *element = NULL;
  28744. if (new_size < 0)
  28745. new_size = 0;
  28746. new_capacity = new_size;
  28747. old_size = list->size;
  28748. if (new_size == old_size)
  28749. return;
  28750. if (new_size > list->capacity)
  28751. {
  28752. if (new_capacity < list->capacity * 2)
  28753. new_capacity = list->capacity * 2;
  28754. /* try to realloc */
  28755. list->data = (void**)realloc(
  28756. (void*)list->data, new_capacity * sizeof(void*));
  28757. for (i = list->capacity; i < new_capacity; i++)
  28758. list->data[i] = NULL;
  28759. list->capacity = new_capacity;
  28760. }
  28761. if (new_size <= list->size)
  28762. {
  28763. for (i = new_size; i < list->size; i++)
  28764. {
  28765. element = list->data[i];
  28766. if (element)
  28767. {
  28768. list->destructor(element);
  28769. list->data[i] = NULL;
  28770. }
  28771. }
  28772. }
  28773. else
  28774. {
  28775. for (i = list->size; i < new_size; i++)
  28776. {
  28777. list->data[i] = NULL;
  28778. if (run_constructor)
  28779. list->data[i] = list->constructor();
  28780. }
  28781. }
  28782. list->size = new_size;
  28783. }
  28784. static void *mylist_add_element(my_list *list)
  28785. {
  28786. int old_size = list->size;
  28787. if (list)
  28788. mylist_resize(list, old_size + 1, true);
  28789. return list->data[old_size];
  28790. }
  28791. static void mylist_destroy(my_list **list_p)
  28792. {
  28793. my_list *list = NULL;
  28794. if (!list_p)
  28795. return;
  28796. list = *list_p;
  28797. if (list)
  28798. {
  28799. mylist_resize(list, 0, false);
  28800. free(list->data);
  28801. free(list);
  28802. *list_p = NULL;
  28803. }
  28804. }
  28805. static void mylist_create(my_list **list_p, int initial_capacity,
  28806. constructor_t constructor, destructor_t destructor)
  28807. {
  28808. my_list *list = NULL;
  28809. if (!list_p)
  28810. return;
  28811. list = *list_p;
  28812. if (list)
  28813. mylist_destroy(list_p);
  28814. list = (my_list*)malloc(sizeof(my_list));
  28815. *list_p = list;
  28816. list->size = 0;
  28817. list->constructor = constructor;
  28818. list->destructor = destructor;
  28819. list->data = (void**)calloc(initial_capacity, sizeof(void*));
  28820. list->capacity = initial_capacity;
  28821. }
  28822. static void *input_list_element_constructor(void)
  28823. {
  28824. void *ptr = malloc(sizeof(input_list_element));
  28825. input_list_element *element = (input_list_element*)ptr;
  28826. element->port = 0;
  28827. element->device = 0;
  28828. element->index = 0;
  28829. element->state = (int16_t*)calloc(256, sizeof(int16_t));
  28830. element->state_size = 256;
  28831. return ptr;
  28832. }
  28833. static void input_list_element_realloc(
  28834. input_list_element *element,
  28835. unsigned int new_size)
  28836. {
  28837. if (new_size > element->state_size)
  28838. {
  28839. element->state = (int16_t*)realloc(element->state,
  28840. new_size * sizeof(int16_t));
  28841. memset(&element->state[element->state_size], 0,
  28842. (new_size - element->state_size) * sizeof(int16_t));
  28843. element->state_size = new_size;
  28844. }
  28845. }
  28846. static void input_list_element_expand(
  28847. input_list_element *element, unsigned int new_index)
  28848. {
  28849. unsigned int new_size = element->state_size;
  28850. if (new_size == 0)
  28851. new_size = 32;
  28852. while (new_index >= new_size)
  28853. new_size *= 2;
  28854. input_list_element_realloc(element, new_size);
  28855. }
  28856. static void input_list_element_destructor(void* element_ptr)
  28857. {
  28858. input_list_element *element = (input_list_element*)element_ptr;
  28859. if (!element)
  28860. return;
  28861. free(element->state);
  28862. free(element_ptr);
  28863. }
  28864. static void input_state_set_last(unsigned port, unsigned device,
  28865. unsigned index, unsigned id, int16_t value)
  28866. {
  28867. unsigned i;
  28868. input_list_element *element = NULL;
  28869. struct rarch_state *p_rarch = &rarch_st;
  28870. if (!p_rarch->input_state_list)
  28871. mylist_create(&p_rarch->input_state_list, 16,
  28872. input_list_element_constructor,
  28873. input_list_element_destructor);
  28874. /* Find list item */
  28875. for (i = 0; i < (unsigned)p_rarch->input_state_list->size; i++)
  28876. {
  28877. element = (input_list_element*)p_rarch->input_state_list->data[i];
  28878. if ( (element->port == port) &&
  28879. (element->device == device) &&
  28880. (element->index == index)
  28881. )
  28882. {
  28883. if (id >= element->state_size)
  28884. input_list_element_expand(element, id);
  28885. element->state[id] = value;
  28886. return;
  28887. }
  28888. }
  28889. element = NULL;
  28890. if (p_rarch->input_state_list)
  28891. element = (input_list_element*)
  28892. mylist_add_element(p_rarch->input_state_list);
  28893. element->port = port;
  28894. element->device = device;
  28895. element->index = index;
  28896. if (id >= element->state_size)
  28897. input_list_element_expand(element, id);
  28898. element->state[id] = value;
  28899. }
  28900. static int16_t input_state_get_last(unsigned port,
  28901. unsigned device, unsigned index, unsigned id)
  28902. {
  28903. unsigned i;
  28904. struct rarch_state *p_rarch = &rarch_st;
  28905. if (!p_rarch->input_state_list)
  28906. return 0;
  28907. /* find list item */
  28908. for (i = 0; i < (unsigned)p_rarch->input_state_list->size; i++)
  28909. {
  28910. input_list_element *element =
  28911. (input_list_element*)p_rarch->input_state_list->data[i];
  28912. if ( (element->port == port) &&
  28913. (element->device == device) &&
  28914. (element->index == index))
  28915. {
  28916. if (id < element->state_size)
  28917. return element->state[id];
  28918. return 0;
  28919. }
  28920. }
  28921. return 0;
  28922. }
  28923. static int16_t input_state_with_logging(unsigned port,
  28924. unsigned device, unsigned index, unsigned id)
  28925. {
  28926. struct rarch_state *p_rarch = &rarch_st;
  28927. if (p_rarch->input_state_callback_original)
  28928. {
  28929. int16_t result = p_rarch->input_state_callback_original(
  28930. port, device, index, id);
  28931. int16_t last_input =
  28932. input_state_get_last(port, device, index, id);
  28933. if (result != last_input)
  28934. p_rarch->input_is_dirty = true;
  28935. /*arbitrary limit of up to 65536 elements in state array*/
  28936. if (id < 65536)
  28937. input_state_set_last(port, device, index, id, result);
  28938. return result;
  28939. }
  28940. return 0;
  28941. }
  28942. static void reset_hook(void)
  28943. {
  28944. struct rarch_state *p_rarch = &rarch_st;
  28945. p_rarch->input_is_dirty = true;
  28946. if (p_rarch->retro_reset_callback_original)
  28947. p_rarch->retro_reset_callback_original();
  28948. }
  28949. static bool unserialize_hook(const void *buf, size_t size)
  28950. {
  28951. struct rarch_state *p_rarch = &rarch_st;
  28952. p_rarch->input_is_dirty = true;
  28953. if (p_rarch->retro_unserialize_callback_original)
  28954. return p_rarch->retro_unserialize_callback_original(buf, size);
  28955. return false;
  28956. }
  28957. static void add_input_state_hook(struct rarch_state *p_rarch)
  28958. {
  28959. struct retro_callbacks *cbs = &p_rarch->retro_ctx;
  28960. if (!p_rarch->input_state_callback_original)
  28961. {
  28962. p_rarch->input_state_callback_original = cbs->state_cb;
  28963. cbs->state_cb = input_state_with_logging;
  28964. p_rarch->current_core.retro_set_input_state(cbs->state_cb);
  28965. }
  28966. if (!p_rarch->retro_reset_callback_original)
  28967. {
  28968. p_rarch->retro_reset_callback_original = p_rarch->current_core.retro_reset;
  28969. p_rarch->current_core.retro_reset = reset_hook;
  28970. }
  28971. if (!p_rarch->retro_unserialize_callback_original)
  28972. {
  28973. p_rarch->retro_unserialize_callback_original = p_rarch->current_core.retro_unserialize;
  28974. p_rarch->current_core.retro_unserialize = unserialize_hook;
  28975. }
  28976. }
  28977. static void remove_input_state_hook(struct rarch_state *p_rarch)
  28978. {
  28979. struct retro_callbacks *cbs = &p_rarch->retro_ctx;
  28980. if (p_rarch->input_state_callback_original)
  28981. {
  28982. cbs->state_cb = p_rarch->input_state_callback_original;
  28983. p_rarch->current_core.retro_set_input_state(cbs->state_cb);
  28984. p_rarch->input_state_callback_original = NULL;
  28985. mylist_destroy(&p_rarch->input_state_list);
  28986. }
  28987. if (p_rarch->retro_reset_callback_original)
  28988. {
  28989. p_rarch->current_core.retro_reset =
  28990. p_rarch->retro_reset_callback_original;
  28991. p_rarch->retro_reset_callback_original = NULL;
  28992. }
  28993. if (p_rarch->retro_unserialize_callback_original)
  28994. {
  28995. p_rarch->current_core.retro_unserialize =
  28996. p_rarch->retro_unserialize_callback_original;
  28997. p_rarch->retro_unserialize_callback_original = NULL;
  28998. }
  28999. }
  29000. static void *runahead_save_state_alloc(void)
  29001. {
  29002. struct rarch_state *p_rarch = &rarch_st;
  29003. retro_ctx_serialize_info_t *savestate = (retro_ctx_serialize_info_t*)
  29004. malloc(sizeof(retro_ctx_serialize_info_t));
  29005. if (!savestate)
  29006. return NULL;
  29007. savestate->data = NULL;
  29008. savestate->data_const = NULL;
  29009. savestate->size = 0;
  29010. if ( (p_rarch->runahead_save_state_size > 0) &&
  29011. p_rarch->runahead_save_state_size_known)
  29012. {
  29013. savestate->data = malloc(p_rarch->runahead_save_state_size);
  29014. savestate->data_const = savestate->data;
  29015. savestate->size = p_rarch->runahead_save_state_size;
  29016. }
  29017. return savestate;
  29018. }
  29019. static void runahead_save_state_free(void *data)
  29020. {
  29021. retro_ctx_serialize_info_t *savestate = (retro_ctx_serialize_info_t*)data;
  29022. if (!savestate)
  29023. return;
  29024. free(savestate->data);
  29025. free(savestate);
  29026. }
  29027. static void runahead_save_state_list_init(
  29028. struct rarch_state *p_rarch,
  29029. size_t save_state_size)
  29030. {
  29031. p_rarch->runahead_save_state_size = save_state_size;
  29032. p_rarch->runahead_save_state_size_known = true;
  29033. mylist_create(&p_rarch->runahead_save_state_list, 16,
  29034. runahead_save_state_alloc, runahead_save_state_free);
  29035. }
  29036. /* Hooks - Hooks to cleanup, and add dirty input hooks */
  29037. static void runahead_remove_hooks(struct rarch_state *p_rarch)
  29038. {
  29039. if (p_rarch->original_retro_deinit)
  29040. {
  29041. p_rarch->current_core.retro_deinit = p_rarch->original_retro_deinit;
  29042. p_rarch->original_retro_deinit = NULL;
  29043. }
  29044. if (p_rarch->original_retro_unload)
  29045. {
  29046. p_rarch->current_core.retro_unload_game = p_rarch->original_retro_unload;
  29047. p_rarch->original_retro_unload = NULL;
  29048. }
  29049. remove_input_state_hook(p_rarch);
  29050. }
  29051. static void runahead_destroy(struct rarch_state *p_rarch)
  29052. {
  29053. mylist_destroy(&p_rarch->runahead_save_state_list);
  29054. runahead_remove_hooks(p_rarch);
  29055. runahead_clear_variables(p_rarch);
  29056. }
  29057. static void unload_hook(void)
  29058. {
  29059. struct rarch_state *p_rarch = &rarch_st;
  29060. runahead_remove_hooks(p_rarch);
  29061. runahead_destroy(p_rarch);
  29062. secondary_core_destroy(p_rarch);
  29063. if (p_rarch->current_core.retro_unload_game)
  29064. p_rarch->current_core.retro_unload_game();
  29065. p_rarch->core_poll_type_override = POLL_TYPE_OVERRIDE_DONTCARE;
  29066. }
  29067. static void runahead_deinit_hook(void)
  29068. {
  29069. struct rarch_state *p_rarch = &rarch_st;
  29070. runahead_remove_hooks(p_rarch);
  29071. runahead_destroy(p_rarch);
  29072. secondary_core_destroy(p_rarch);
  29073. if (p_rarch->current_core.retro_deinit)
  29074. p_rarch->current_core.retro_deinit();
  29075. }
  29076. static void runahead_add_hooks(struct rarch_state *p_rarch)
  29077. {
  29078. if (!p_rarch->original_retro_deinit)
  29079. {
  29080. p_rarch->original_retro_deinit = p_rarch->current_core.retro_deinit;
  29081. p_rarch->current_core.retro_deinit = runahead_deinit_hook;
  29082. }
  29083. if (!p_rarch->original_retro_unload)
  29084. {
  29085. p_rarch->original_retro_unload = p_rarch->current_core.retro_unload_game;
  29086. p_rarch->current_core.retro_unload_game = unload_hook;
  29087. }
  29088. add_input_state_hook(p_rarch);
  29089. }
  29090. /* Runahead Code */
  29091. static void runahead_error(struct rarch_state *p_rarch)
  29092. {
  29093. p_rarch->runahead_available = false;
  29094. mylist_destroy(&p_rarch->runahead_save_state_list);
  29095. runahead_remove_hooks(p_rarch);
  29096. p_rarch->runahead_save_state_size = 0;
  29097. p_rarch->runahead_save_state_size_known = true;
  29098. }
  29099. static bool runahead_create(struct rarch_state *p_rarch)
  29100. {
  29101. /* get savestate size and allocate buffer */
  29102. retro_ctx_size_info_t info;
  29103. p_rarch->request_fast_savestate = true;
  29104. core_serialize_size(&info);
  29105. p_rarch->request_fast_savestate = false;
  29106. runahead_save_state_list_init(p_rarch, info.size);
  29107. p_rarch->runahead_video_driver_is_active =
  29108. p_rarch->video_driver_active;
  29109. if ( (p_rarch->runahead_save_state_size == 0) ||
  29110. !p_rarch->runahead_save_state_size_known)
  29111. {
  29112. runahead_error(p_rarch);
  29113. return false;
  29114. }
  29115. runahead_add_hooks(p_rarch);
  29116. p_rarch->runahead_force_input_dirty = true;
  29117. if (p_rarch->runahead_save_state_list)
  29118. mylist_resize(p_rarch->runahead_save_state_list, 1, true);
  29119. return true;
  29120. }
  29121. static bool runahead_save_state(struct rarch_state *p_rarch)
  29122. {
  29123. retro_ctx_serialize_info_t *serialize_info;
  29124. bool okay = false;
  29125. if (!p_rarch->runahead_save_state_list)
  29126. return false;
  29127. serialize_info =
  29128. (retro_ctx_serialize_info_t*)p_rarch->runahead_save_state_list->data[0];
  29129. p_rarch->request_fast_savestate = true;
  29130. okay = core_serialize(serialize_info);
  29131. p_rarch->request_fast_savestate = false;
  29132. if (okay)
  29133. return true;
  29134. runahead_error(p_rarch);
  29135. return false;
  29136. }
  29137. static bool runahead_load_state(struct rarch_state *p_rarch)
  29138. {
  29139. bool okay = false;
  29140. retro_ctx_serialize_info_t *serialize_info = (retro_ctx_serialize_info_t*)
  29141. p_rarch->runahead_save_state_list->data[0];
  29142. bool last_dirty = p_rarch->input_is_dirty;
  29143. p_rarch->request_fast_savestate = true;
  29144. /* calling core_unserialize has side effects with
  29145. * netplay (it triggers transmitting your save state)
  29146. call retro_unserialize directly from the core instead */
  29147. okay = p_rarch->current_core.retro_unserialize(
  29148. serialize_info->data_const, serialize_info->size);
  29149. p_rarch->request_fast_savestate = false;
  29150. p_rarch->input_is_dirty = last_dirty;
  29151. if (!okay)
  29152. runahead_error(p_rarch);
  29153. return okay;
  29154. }
  29155. #if HAVE_DYNAMIC
  29156. static bool runahead_load_state_secondary(struct rarch_state *p_rarch)
  29157. {
  29158. bool okay = false;
  29159. retro_ctx_serialize_info_t *serialize_info =
  29160. (retro_ctx_serialize_info_t*)p_rarch->runahead_save_state_list->data[0];
  29161. p_rarch->request_fast_savestate = true;
  29162. okay = secondary_core_deserialize(
  29163. p_rarch,
  29164. serialize_info->data_const, (int)serialize_info->size);
  29165. p_rarch->request_fast_savestate = false;
  29166. if (!okay)
  29167. {
  29168. p_rarch->runahead_secondary_core_available = false;
  29169. runahead_error(p_rarch);
  29170. return false;
  29171. }
  29172. return true;
  29173. }
  29174. #endif
  29175. static bool runahead_core_run_use_last_input(struct rarch_state *p_rarch)
  29176. {
  29177. struct retro_callbacks *cbs = &p_rarch->retro_ctx;
  29178. retro_input_poll_t old_poll_function = cbs->poll_cb;
  29179. retro_input_state_t old_input_function = cbs->state_cb;
  29180. cbs->poll_cb = retro_input_poll_null;
  29181. cbs->state_cb = input_state_get_last;
  29182. p_rarch->current_core.retro_set_input_poll(cbs->poll_cb);
  29183. p_rarch->current_core.retro_set_input_state(cbs->state_cb);
  29184. p_rarch->current_core.retro_run();
  29185. cbs->poll_cb = old_poll_function;
  29186. cbs->state_cb = old_input_function;
  29187. p_rarch->current_core.retro_set_input_poll(cbs->poll_cb);
  29188. p_rarch->current_core.retro_set_input_state(cbs->state_cb);
  29189. return true;
  29190. }
  29191. static void do_runahead(
  29192. struct rarch_state *p_rarch,
  29193. int runahead_count, bool use_secondary)
  29194. {
  29195. int frame_number = 0;
  29196. bool last_frame = false;
  29197. bool suspended_frame = false;
  29198. #if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
  29199. const bool have_dynamic = true;
  29200. #else
  29201. const bool have_dynamic = false;
  29202. #endif
  29203. uint64_t frame_count = p_rarch->video_driver_frame_count;
  29204. if (runahead_count <= 0 || !p_rarch->runahead_available)
  29205. goto force_input_dirty;
  29206. if (!p_rarch->runahead_save_state_size_known)
  29207. {
  29208. if (!runahead_create(p_rarch))
  29209. {
  29210. settings_t *settings = p_rarch->configuration_settings;
  29211. bool runahead_hide_warnings = settings->bools.run_ahead_hide_warnings;
  29212. if (!runahead_hide_warnings)
  29213. runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES), 0, 2 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  29214. goto force_input_dirty;
  29215. }
  29216. }
  29217. /* Check for GUI */
  29218. /* Hack: If we were in the GUI, force a resync. */
  29219. if (frame_count != p_rarch->runahead_last_frame_count + 1)
  29220. p_rarch->runahead_force_input_dirty = true;
  29221. p_rarch->runahead_last_frame_count = frame_count;
  29222. if ( !use_secondary
  29223. || !have_dynamic
  29224. || !p_rarch->runahead_secondary_core_available)
  29225. {
  29226. /* TODO: multiple savestates for higher performance
  29227. * when not using secondary core */
  29228. for (frame_number = 0; frame_number <= runahead_count; frame_number++)
  29229. {
  29230. last_frame = frame_number == runahead_count;
  29231. suspended_frame = !last_frame;
  29232. if (suspended_frame)
  29233. {
  29234. p_rarch->audio_suspended = true;
  29235. p_rarch->video_driver_active = false;
  29236. }
  29237. if (frame_number == 0)
  29238. core_run();
  29239. else
  29240. runahead_core_run_use_last_input(p_rarch);
  29241. if (suspended_frame)
  29242. {
  29243. RUNAHEAD_RESUME_VIDEO(p_rarch);
  29244. p_rarch->audio_suspended = false;
  29245. }
  29246. if (frame_number == 0)
  29247. {
  29248. if (!runahead_save_state(p_rarch))
  29249. {
  29250. runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  29251. return;
  29252. }
  29253. }
  29254. if (last_frame)
  29255. {
  29256. if (!runahead_load_state(p_rarch))
  29257. {
  29258. runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  29259. return;
  29260. }
  29261. }
  29262. }
  29263. }
  29264. else
  29265. {
  29266. #if HAVE_DYNAMIC
  29267. if (!secondary_core_ensure_exists(p_rarch))
  29268. {
  29269. secondary_core_destroy(p_rarch);
  29270. p_rarch->runahead_secondary_core_available = false;
  29271. runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  29272. goto force_input_dirty;
  29273. }
  29274. /* run main core with video suspended */
  29275. p_rarch->video_driver_active = false;
  29276. core_run();
  29277. RUNAHEAD_RESUME_VIDEO(p_rarch);
  29278. if ( p_rarch->input_is_dirty
  29279. || p_rarch->runahead_force_input_dirty)
  29280. {
  29281. p_rarch->input_is_dirty = false;
  29282. if (!runahead_save_state(p_rarch))
  29283. {
  29284. runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  29285. return;
  29286. }
  29287. if (!runahead_load_state_secondary(p_rarch))
  29288. {
  29289. runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  29290. return;
  29291. }
  29292. for (frame_number = 0; frame_number < runahead_count - 1; frame_number++)
  29293. {
  29294. p_rarch->video_driver_active = false;
  29295. p_rarch->audio_suspended = true;
  29296. p_rarch->hard_disable_audio = true;
  29297. RUNAHEAD_RUN_SECONDARY(p_rarch);
  29298. p_rarch->hard_disable_audio = false;
  29299. p_rarch->audio_suspended = false;
  29300. RUNAHEAD_RESUME_VIDEO(p_rarch);
  29301. }
  29302. }
  29303. p_rarch->audio_suspended = true;
  29304. p_rarch->hard_disable_audio = true;
  29305. RUNAHEAD_RUN_SECONDARY(p_rarch);
  29306. p_rarch->hard_disable_audio = false;
  29307. p_rarch->audio_suspended = false;
  29308. #endif
  29309. }
  29310. p_rarch->runahead_force_input_dirty = false;
  29311. return;
  29312. force_input_dirty:
  29313. core_run();
  29314. p_rarch->runahead_force_input_dirty = true;
  29315. }
  29316. #endif
  29317. static retro_time_t rarch_core_runtime_tick(
  29318. struct rarch_state *p_rarch,
  29319. retro_time_t current_time)
  29320. {
  29321. retro_time_t frame_time =
  29322. (1.0 / p_rarch->video_driver_av_info.timing.fps) * 1000000;
  29323. bool runloop_slowmotion = p_rarch->runloop_slowmotion;
  29324. bool runloop_fastmotion = p_rarch->runloop_fastmotion;
  29325. /* Account for slow motion */
  29326. if (runloop_slowmotion)
  29327. {
  29328. settings_t *settings = p_rarch->configuration_settings;
  29329. float slowmotion_ratio = settings->floats.slowmotion_ratio;
  29330. return (retro_time_t)((double)frame_time * slowmotion_ratio);
  29331. }
  29332. /* Account for fast forward */
  29333. if (runloop_fastmotion)
  29334. {
  29335. /* Doing it this way means we miss the first frame after
  29336. * turning fast forward on, but it saves the overhead of
  29337. * having to do:
  29338. * retro_time_t current_usec = cpu_features_get_time_usec();
  29339. * libretro_core_runtime_last = current_usec;
  29340. * every frame when fast forward is off. */
  29341. retro_time_t current_usec = current_time;
  29342. retro_time_t potential_frame_time = current_usec -
  29343. p_rarch->libretro_core_runtime_last;
  29344. p_rarch->libretro_core_runtime_last = current_usec;
  29345. if (potential_frame_time < frame_time)
  29346. return potential_frame_time;
  29347. }
  29348. return frame_time;
  29349. }
  29350. static void retroarch_print_features(void)
  29351. {
  29352. char buf[2048];
  29353. buf[0] = '\0';
  29354. frontend_driver_attach_console();
  29355. strlcat(buf, "\nFeatures:\n", sizeof(buf));
  29356. _PSUPP_BUF(buf, SUPPORTS_LIBRETRODB, "LibretroDB", "LibretroDB support");
  29357. _PSUPP_BUF(buf, SUPPORTS_COMMAND, "Command", "Command interface support");
  29358. _PSUPP_BUF(buf, SUPPORTS_NETWORK_COMMAND, "Network Command", "Network Command interface "
  29359. "support");
  29360. _PSUPP_BUF(buf, SUPPORTS_SDL, "SDL", "SDL input/audio/video drivers");
  29361. _PSUPP_BUF(buf, SUPPORTS_SDL2, "SDL2", "SDL2 input/audio/video drivers");
  29362. _PSUPP_BUF(buf, SUPPORTS_X11, "X11", "X11 input/video drivers");
  29363. _PSUPP_BUF(buf, SUPPORTS_WAYLAND, "wayland", "Wayland input/video drivers");
  29364. _PSUPP_BUF(buf, SUPPORTS_THREAD, "Threads", "Threading support");
  29365. _PSUPP_BUF(buf, SUPPORTS_VULKAN, "Vulkan", "Vulkan video driver");
  29366. _PSUPP_BUF(buf, SUPPORTS_METAL, "Metal", "Metal video driver");
  29367. _PSUPP_BUF(buf, SUPPORTS_OPENGL, "OpenGL", "OpenGL video driver support");
  29368. _PSUPP_BUF(buf, SUPPORTS_OPENGLES, "OpenGL ES", "OpenGLES video driver support");
  29369. _PSUPP_BUF(buf, SUPPORTS_XVIDEO, "XVideo", "Video driver");
  29370. _PSUPP_BUF(buf, SUPPORTS_UDEV, "UDEV", "UDEV/EVDEV input driver support");
  29371. _PSUPP_BUF(buf, SUPPORTS_EGL, "EGL", "Video context driver");
  29372. _PSUPP_BUF(buf, SUPPORTS_KMS, "KMS", "Video context driver");
  29373. _PSUPP_BUF(buf, SUPPORTS_VG, "OpenVG", "Video context driver");
  29374. _PSUPP_BUF(buf, SUPPORTS_COREAUDIO, "CoreAudio", "Audio driver");
  29375. _PSUPP_BUF(buf, SUPPORTS_COREAUDIO3, "CoreAudioV3", "Audio driver");
  29376. _PSUPP_BUF(buf, SUPPORTS_ALSA, "ALSA", "Audio driver");
  29377. _PSUPP_BUF(buf, SUPPORTS_OSS, "OSS", "Audio driver");
  29378. _PSUPP_BUF(buf, SUPPORTS_JACK, "Jack", "Audio driver");
  29379. _PSUPP_BUF(buf, SUPPORTS_RSOUND, "RSound", "Audio driver");
  29380. _PSUPP_BUF(buf, SUPPORTS_ROAR, "RoarAudio", "Audio driver");
  29381. _PSUPP_BUF(buf, SUPPORTS_PULSE, "PulseAudio", "Audio driver");
  29382. _PSUPP_BUF(buf, SUPPORTS_DSOUND, "DirectSound", "Audio driver");
  29383. _PSUPP_BUF(buf, SUPPORTS_WASAPI, "WASAPI", "Audio driver");
  29384. _PSUPP_BUF(buf, SUPPORTS_XAUDIO, "XAudio2", "Audio driver");
  29385. _PSUPP_BUF(buf, SUPPORTS_AL, "OpenAL", "Audio driver");
  29386. _PSUPP_BUF(buf, SUPPORTS_SL, "OpenSL", "Audio driver");
  29387. _PSUPP_BUF(buf, SUPPORTS_7ZIP, "7zip", "7zip extraction support");
  29388. _PSUPP_BUF(buf, SUPPORTS_ZLIB, "zlib", ".zip extraction support");
  29389. _PSUPP_BUF(buf, SUPPORTS_DYLIB, "External", "External filter and plugin support");
  29390. _PSUPP_BUF(buf, SUPPORTS_CG, "Cg", "Fragment/vertex shader driver");
  29391. _PSUPP_BUF(buf, SUPPORTS_GLSL, "GLSL", "Fragment/vertex shader driver");
  29392. _PSUPP_BUF(buf, SUPPORTS_HLSL, "HLSL", "Fragment/vertex shader driver");
  29393. _PSUPP_BUF(buf, SUPPORTS_SDL_IMAGE, "SDL_image", "SDL_image image loading");
  29394. _PSUPP_BUF(buf, SUPPORTS_RPNG, "rpng", "PNG image loading/encoding");
  29395. _PSUPP_BUF(buf, SUPPORTS_RJPEG, "rjpeg", "JPEG image loading");
  29396. _PSUPP_BUF(buf, SUPPORTS_DYNAMIC, "Dynamic", "Dynamic run-time loading of "
  29397. "libretro library");
  29398. _PSUPP_BUF(buf, SUPPORTS_FFMPEG, "FFmpeg", "On-the-fly recording of gameplay "
  29399. "with libavcodec");
  29400. _PSUPP_BUF(buf, SUPPORTS_FREETYPE, "FreeType", "TTF font rendering driver");
  29401. _PSUPP_BUF(buf, SUPPORTS_CORETEXT, "CoreText", "TTF font rendering driver ");
  29402. _PSUPP_BUF(buf, SUPPORTS_NETPLAY, "Netplay", "Peer-to-peer netplay");
  29403. _PSUPP_BUF(buf, SUPPORTS_PYTHON, "Python", "Script support in shaders");
  29404. _PSUPP_BUF(buf, SUPPORTS_LIBUSB, "Libusb", "Libusb support");
  29405. _PSUPP_BUF(buf, SUPPORTS_COCOA, "Cocoa", "Cocoa UI companion support "
  29406. "(for OSX and/or iOS)");
  29407. _PSUPP_BUF(buf, SUPPORTS_QT, "Qt", "Qt UI companion support");
  29408. _PSUPP_BUF(buf, SUPPORTS_V4L2, "Video4Linux2", "Camera driver");
  29409. puts(buf);
  29410. }
  29411. static void retroarch_print_version(void)
  29412. {
  29413. char str[255];
  29414. frontend_driver_attach_console();
  29415. str[0] = '\0';
  29416. fprintf(stderr, "%s: %s -- v%s",
  29417. msg_hash_to_str(MSG_PROGRAM),
  29418. msg_hash_to_str(MSG_LIBRETRO_FRONTEND),
  29419. PACKAGE_VERSION);
  29420. #ifdef HAVE_GIT_VERSION
  29421. printf(" -- %s --\n", retroarch_git_version);
  29422. #else
  29423. printf("\n");
  29424. #endif
  29425. retroarch_get_capabilities(RARCH_CAPABILITIES_COMPILER, str, sizeof(str));
  29426. strlcat(str, " Built: " __DATE__, sizeof(str));
  29427. fprintf(stdout, "%s\n", str);
  29428. }
  29429. /**
  29430. * retroarch_print_help:
  29431. *
  29432. * Prints help message explaining the program's commandline switches.
  29433. **/
  29434. static void retroarch_print_help(const char *arg0)
  29435. {
  29436. frontend_driver_attach_console();
  29437. puts("===================================================================");
  29438. retroarch_print_version();
  29439. puts("===================================================================");
  29440. printf("Usage: %s [OPTIONS]... [FILE]\n", arg0);
  29441. {
  29442. char buf[2148];
  29443. buf[0] = '\0';
  29444. strlcpy(buf, " -h, --help Show this help message.\n", sizeof(buf));
  29445. strlcat(buf, " -v, --verbose Verbose logging.\n", sizeof(buf));
  29446. strlcat(buf, " --log-file FILE Log messages to FILE.\n", sizeof(buf));
  29447. strlcat(buf, " --version Show version.\n", sizeof(buf));
  29448. strlcat(buf, " --features Prints available features compiled into "
  29449. "program.\n", sizeof(buf));
  29450. #ifdef HAVE_MENU
  29451. strlcat(buf, " --menu Do not require content or libretro core to "
  29452. "be loaded,\n"
  29453. " starts directly in menu. If no arguments "
  29454. "are passed to\n"
  29455. " the program, it is equivalent to using "
  29456. "--menu as only argument.\n", sizeof(buf));
  29457. #endif
  29458. strlcat(buf, " -s, --save=PATH Path for save files (*.srm). (DEPRECATED, use --appendconfig and savefile_directory)\n", sizeof(buf));
  29459. strlcat(buf, " -S, --savestate=PATH Path for the save state files (*.state). (DEPRECATED, use --appendconfig and savestate_directory)\n", sizeof(buf));
  29460. strlcat(buf, " --set-shader PATH Path to a shader (preset) that will be loaded each time content is loaded.\n"
  29461. " Effectively overrides automatic shader presets.\n"
  29462. " An empty argument \"\" will disable automatic shader presets.\n", sizeof(buf));
  29463. strlcat(buf, " -f, --fullscreen Start the program in fullscreen regardless "
  29464. "of config settings.\n", sizeof(buf));
  29465. #ifdef HAVE_CONFIGFILE
  29466. #ifdef _WIN32
  29467. strlcat(buf, " -c, --config=FILE Path for config file."
  29468. "\n\t\tDefaults to retroarch.cfg in same directory as retroarch.exe."
  29469. "\n\t\tIf a default config is not found, the program will attempt to "
  29470. "create one.\n"
  29471. , sizeof(buf));
  29472. #else
  29473. strlcat(buf, " -c, --config=FILE Path for config file."
  29474. "\n\t\tBy default looks for config in $XDG_CONFIG_HOME/retroarch/"
  29475. "retroarch.cfg,\n\t\t$HOME/.config/retroarch/retroarch.cfg,\n\t\t"
  29476. "and $HOME/.retroarch.cfg.\n\t\tIf a default config is not found, "
  29477. "the program will attempt to create one based on the \n\t\t"
  29478. "skeleton config (" GLOBAL_CONFIG_DIR "/retroarch.cfg). \n"
  29479. , sizeof(buf));
  29480. #endif
  29481. #endif
  29482. strlcat(buf, " --appendconfig=FILE\n"
  29483. " Extra config files are loaded in, "
  29484. "and take priority over\n"
  29485. " config selected in -c (or default). "
  29486. "Multiple configs are\n"
  29487. " delimited by '|'.\n", sizeof(buf));
  29488. #ifdef HAVE_DYNAMIC
  29489. strlcat(buf, " -L, --libretro=FILE Path to libretro implementation. "
  29490. "Overrides any config setting.\n", sizeof(buf));
  29491. #endif
  29492. strlcat(buf, " --subsystem=NAME Use a subsystem of the libretro core. "
  29493. "Multiple content\n"
  29494. " files are loaded as multiple arguments. "
  29495. "If a content\n"
  29496. " file is skipped, use a blank (\"\") "
  29497. "command line argument.\n"
  29498. " Content must be loaded in an order "
  29499. "which depends on the\n"
  29500. " particular subsystem used. See verbose "
  29501. "log output to learn\n"
  29502. " how a particular subsystem wants content "
  29503. "to be loaded.\n", sizeof(buf));
  29504. puts(buf);
  29505. }
  29506. printf(" -N, --nodevice=PORT\n"
  29507. " Disconnects controller device connected "
  29508. "to PORT (1 to %d).\n", MAX_USERS);
  29509. printf(" -A, --dualanalog=PORT\n"
  29510. " Connect a DualAnalog controller to PORT "
  29511. "(1 to %d).\n", MAX_USERS);
  29512. printf(" -d, --device=PORT:ID\n"
  29513. " Connect a generic device into PORT of "
  29514. "the device (1 to %d).\n", MAX_USERS);
  29515. {
  29516. char buf[2560];
  29517. buf[0] = '\0';
  29518. strlcpy(buf, " Format is PORT:ID, where ID is a number "
  29519. "corresponding to the particular device.\n", sizeof(buf));
  29520. #ifdef HAVE_BSV_MOVIE
  29521. strlcat(buf, " -P, --bsvplay=FILE Playback a BSV movie file.\n", sizeof(buf));
  29522. strlcat(buf, " -R, --bsvrecord=FILE Start recording a BSV movie file from "
  29523. "the beginning.\n", sizeof(buf));
  29524. strlcat(buf, " --eof-exit Exit upon reaching the end of the "
  29525. "BSV movie file.\n", sizeof(buf));
  29526. #endif
  29527. strlcat(buf, " -M, --sram-mode=MODE SRAM handling mode. MODE can be "
  29528. "'noload-nosave',\n"
  29529. " 'noload-save', 'load-nosave' or "
  29530. "'load-save'.\n"
  29531. " Note: 'noload-save' implies that "
  29532. "save files *WILL BE OVERWRITTEN*.\n", sizeof(buf));
  29533. #ifdef HAVE_NETWORKING
  29534. strlcat(buf, " -H, --host Host netplay as user 1.\n", sizeof(buf));
  29535. strlcat(buf, " -C, --connect=HOST Connect to netplay server as user 2.\n", sizeof(buf));
  29536. strlcat(buf, " --port=PORT Port used to netplay. Default is 55435.\n", sizeof(buf));
  29537. strlcat(buf, " --stateless Use \"stateless\" mode for netplay\n", sizeof(buf));
  29538. strlcat(buf, " (requires a very fast network).\n", sizeof(buf));
  29539. strlcat(buf, " --check-frames=NUMBER\n"
  29540. " Check frames when using netplay.\n", sizeof(buf));
  29541. #ifdef HAVE_NETWORK_CMD
  29542. strlcat(buf, " --command Sends a command over UDP to an already "
  29543. "running program process.\n", sizeof(buf));
  29544. strlcat(buf, " Available commands are listed if command is invalid.\n", sizeof(buf));
  29545. #endif
  29546. #endif
  29547. strlcat(buf, " --nick=NICK Picks a username (for use with netplay). "
  29548. "Not mandatory.\n", sizeof(buf));
  29549. strlcat(buf, " -r, --record=FILE Path to record video file.\n "
  29550. "Using .mkv extension is recommended.\n", sizeof(buf));
  29551. strlcat(buf, " --recordconfig Path to settings used during recording.\n", sizeof(buf));
  29552. strlcat(buf, " --size=WIDTHxHEIGHT\n"
  29553. " Overrides output video size when recording.\n", sizeof(buf));
  29554. #ifdef HAVE_PATCH
  29555. strlcat(buf, " -U, --ups=FILE Specifies path for UPS patch that will be "
  29556. "applied to content.\n", sizeof(buf));
  29557. strlcat(buf, " --bps=FILE Specifies path for BPS patch that will be "
  29558. "applied to content.\n", sizeof(buf));
  29559. strlcat(buf, " --ips=FILE Specifies path for IPS patch that will be "
  29560. "applied to content.\n", sizeof(buf));
  29561. strlcat(buf, " --no-patch Disables all forms of content patching.\n", sizeof(buf));
  29562. #endif
  29563. strlcat(buf, " -D, --detach Detach program from the running console. "
  29564. "Not relevant for all platforms.\n", sizeof(buf));
  29565. strlcat(buf, " --max-frames=NUMBER\n"
  29566. " Runs for the specified number of frames, "
  29567. "then exits.\n", sizeof(buf));
  29568. #ifdef HAVE_SCREENSHOTS
  29569. strlcat(buf, " --max-frames-ss\n"
  29570. " Takes a screenshot at the end of max-frames.\n", sizeof(buf));
  29571. strlcat(buf, " --max-frames-ss-path=FILE\n"
  29572. " Path to save the screenshot to at the end of max-frames.\n", sizeof(buf));
  29573. #endif
  29574. #ifdef HAVE_ACCESSIBILITY
  29575. strlcat(buf, " --accessibility\n"
  29576. " Enables accessibilty for blind users using text-to-speech.\n", sizeof(buf));
  29577. #endif
  29578. strlcat(buf, " --load-menu-on-error\n"
  29579. " Open menu instead of quitting if specified core or content fails to load.\n", sizeof(buf));
  29580. puts(buf);
  29581. }
  29582. }
  29583. /**
  29584. * retroarch_parse_input_and_config:
  29585. * @argc : Count of (commandline) arguments.
  29586. * @argv : (Commandline) arguments.
  29587. *
  29588. * Parses (commandline) arguments passed to program and loads the config file,
  29589. * with command line options overriding the config file.
  29590. *
  29591. **/
  29592. static void retroarch_parse_input_and_config(
  29593. struct rarch_state *p_rarch,
  29594. global_t *global,
  29595. int argc, char *argv[])
  29596. {
  29597. unsigned i;
  29598. static bool first_run = true;
  29599. const char *optstring = NULL;
  29600. bool explicit_menu = false;
  29601. bool cli_active = false;
  29602. bool cli_core_set = false;
  29603. bool cli_content_set = false;
  29604. const struct option opts[] = {
  29605. #ifdef HAVE_DYNAMIC
  29606. { "libretro", 1, NULL, 'L' },
  29607. #endif
  29608. { "menu", 0, NULL, RA_OPT_MENU },
  29609. { "help", 0, NULL, 'h' },
  29610. { "save", 1, NULL, 's' },
  29611. { "fullscreen", 0, NULL, 'f' },
  29612. { "record", 1, NULL, 'r' },
  29613. { "recordconfig", 1, NULL, RA_OPT_RECORDCONFIG },
  29614. { "size", 1, NULL, RA_OPT_SIZE },
  29615. { "verbose", 0, NULL, 'v' },
  29616. #ifdef HAVE_CONFIGFILE
  29617. { "config", 1, NULL, 'c' },
  29618. { "appendconfig", 1, NULL, RA_OPT_APPENDCONFIG },
  29619. #endif
  29620. { "nodevice", 1, NULL, 'N' },
  29621. { "dualanalog", 1, NULL, 'A' },
  29622. { "device", 1, NULL, 'd' },
  29623. { "savestate", 1, NULL, 'S' },
  29624. { "set-shader", 1, NULL, RA_OPT_SET_SHADER },
  29625. #ifdef HAVE_BSV_MOVIE
  29626. { "bsvplay", 1, NULL, 'P' },
  29627. { "bsvrecord", 1, NULL, 'R' },
  29628. #endif
  29629. { "sram-mode", 1, NULL, 'M' },
  29630. #ifdef HAVE_NETWORKING
  29631. { "host", 0, NULL, 'H' },
  29632. { "connect", 1, NULL, 'C' },
  29633. { "stateless", 0, NULL, RA_OPT_STATELESS },
  29634. { "check-frames", 1, NULL, RA_OPT_CHECK_FRAMES },
  29635. { "port", 1, NULL, RA_OPT_PORT },
  29636. #ifdef HAVE_NETWORK_CMD
  29637. { "command", 1, NULL, RA_OPT_COMMAND },
  29638. #endif
  29639. #endif
  29640. { "nick", 1, NULL, RA_OPT_NICK },
  29641. #ifdef HAVE_PATCH
  29642. { "ups", 1, NULL, 'U' },
  29643. { "bps", 1, NULL, RA_OPT_BPS },
  29644. { "ips", 1, NULL, RA_OPT_IPS },
  29645. { "no-patch", 0, NULL, RA_OPT_NO_PATCH },
  29646. #endif
  29647. { "detach", 0, NULL, 'D' },
  29648. { "features", 0, NULL, RA_OPT_FEATURES },
  29649. { "subsystem", 1, NULL, RA_OPT_SUBSYSTEM },
  29650. { "max-frames", 1, NULL, RA_OPT_MAX_FRAMES },
  29651. { "max-frames-ss", 0, NULL, RA_OPT_MAX_FRAMES_SCREENSHOT },
  29652. { "max-frames-ss-path", 1, NULL, RA_OPT_MAX_FRAMES_SCREENSHOT_PATH },
  29653. { "eof-exit", 0, NULL, RA_OPT_EOF_EXIT },
  29654. { "version", 0, NULL, RA_OPT_VERSION },
  29655. { "log-file", 1, NULL, RA_OPT_LOG_FILE },
  29656. { "accessibility", 0, NULL, RA_OPT_ACCESSIBILITY},
  29657. { "load-menu-on-error", 0, NULL, RA_OPT_LOAD_MENU_ON_ERROR },
  29658. { NULL, 0, NULL, 0 }
  29659. };
  29660. if (first_run)
  29661. {
  29662. /* Copy the args into a buffer so launch arguments can be reused */
  29663. for (i = 0; i < (unsigned)argc; i++)
  29664. {
  29665. strlcat(p_rarch->launch_arguments,
  29666. argv[i], sizeof(p_rarch->launch_arguments));
  29667. strlcat(p_rarch->launch_arguments, " ",
  29668. sizeof(p_rarch->launch_arguments));
  29669. }
  29670. string_trim_whitespace_left(p_rarch->launch_arguments);
  29671. string_trim_whitespace_right(p_rarch->launch_arguments);
  29672. first_run = false;
  29673. /* Command line interface is only considered
  29674. * to be 'active' (i.e. used by a third party)
  29675. * if this is the first run (subsequent runs
  29676. * are triggered by RetroArch itself) */
  29677. cli_active = true;
  29678. }
  29679. /* Handling the core type is finicky. Based on the arguments we pass in,
  29680. * we handle it differently.
  29681. * Some current cases which track desired behavior and how it is supposed to work:
  29682. *
  29683. * Dynamically linked RA:
  29684. * ./retroarch -> CORE_TYPE_DUMMY
  29685. * ./retroarch -v -> CORE_TYPE_DUMMY + verbose
  29686. * ./retroarch --menu -> CORE_TYPE_DUMMY
  29687. * ./retroarch --menu -v -> CORE_TYPE_DUMMY + verbose
  29688. * ./retroarch -L contentless-core -> CORE_TYPE_PLAIN
  29689. * ./retroarch -L content-core -> CORE_TYPE_PLAIN + FAIL (This currently crashes)
  29690. * ./retroarch [-L content-core] ROM -> CORE_TYPE_PLAIN
  29691. * ./retroarch <-L or ROM> --menu -> FAIL
  29692. *
  29693. * The heuristic here seems to be that if we use the -L CLI option or
  29694. * optind < argc at the end we should set CORE_TYPE_PLAIN.
  29695. * To handle --menu, we should ensure that CORE_TYPE_DUMMY is still set
  29696. * otherwise, fail early, since the CLI options are non-sensical.
  29697. * We could also simply ignore --menu in this case to be more friendly with
  29698. * bogus arguments.
  29699. */
  29700. if (!p_rarch->has_set_core)
  29701. retroarch_set_current_core_type(CORE_TYPE_DUMMY, false);
  29702. path_clear(RARCH_PATH_SUBSYSTEM);
  29703. retroarch_override_setting_free_state();
  29704. p_rarch->has_set_username = false;
  29705. #ifdef HAVE_PATCH
  29706. rarch_ctl(RARCH_CTL_UNSET_UPS_PREF, NULL);
  29707. rarch_ctl(RARCH_CTL_UNSET_IPS_PREF, NULL);
  29708. rarch_ctl(RARCH_CTL_UNSET_BPS_PREF, NULL);
  29709. *global->name.ups = '\0';
  29710. *global->name.bps = '\0';
  29711. *global->name.ips = '\0';
  29712. #endif
  29713. #ifdef HAVE_CONFIGFILE
  29714. p_rarch->runloop_overrides_active = false;
  29715. #endif
  29716. global->cli_load_menu_on_error = false;
  29717. /* Make sure we can call retroarch_parse_input several times ... */
  29718. optind = 0;
  29719. optstring = "hs:fvS:A:U:DN:d:"
  29720. BSV_MOVIE_ARG NETPLAY_ARG DYNAMIC_ARG FFMPEG_RECORD_ARG CONFIG_FILE_ARG;
  29721. #ifdef ORBIS
  29722. argv = &(argv[2]);
  29723. argc = argc - 2;
  29724. #endif
  29725. #ifndef HAVE_MENU
  29726. if (argc == 1)
  29727. {
  29728. printf("%s\n", msg_hash_to_str(MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN));
  29729. retroarch_print_help(argv[0]);
  29730. exit(0);
  29731. }
  29732. #endif
  29733. /* First pass: Read the config file path and any directory overrides, so
  29734. * they're in place when we load the config */
  29735. if (argc)
  29736. {
  29737. for (;;)
  29738. {
  29739. int c = getopt_long(argc, argv, optstring, opts, NULL);
  29740. #if 0
  29741. fprintf(stderr, "c is: %c (%d), optarg is: [%s]\n", c, c, string_is_empty(optarg) ? "" : optarg);
  29742. #endif
  29743. if (c == -1)
  29744. break;
  29745. switch (c)
  29746. {
  29747. case 'h':
  29748. retroarch_print_help(argv[0]);
  29749. exit(0);
  29750. #ifdef HAVE_CONFIGFILE
  29751. case 'c':
  29752. path_set(RARCH_PATH_CONFIG, optarg);
  29753. break;
  29754. case RA_OPT_APPENDCONFIG:
  29755. path_set(RARCH_PATH_CONFIG_APPEND, optarg);
  29756. break;
  29757. #endif
  29758. case 's':
  29759. strlcpy(global->name.savefile, optarg,
  29760. sizeof(global->name.savefile));
  29761. retroarch_override_setting_set(
  29762. RARCH_OVERRIDE_SETTING_SAVE_PATH, NULL);
  29763. break;
  29764. case 'S':
  29765. strlcpy(global->name.savestate, optarg,
  29766. sizeof(global->name.savestate));
  29767. retroarch_override_setting_set(
  29768. RARCH_OVERRIDE_SETTING_STATE_PATH, NULL);
  29769. break;
  29770. /* Must handle '?' otherwise you get an infinite loop */
  29771. case '?':
  29772. retroarch_print_help(argv[0]);
  29773. retroarch_fail(1, "retroarch_parse_input()");
  29774. break;
  29775. /* All other arguments are handled in the second pass */
  29776. }
  29777. }
  29778. }
  29779. /* Flush out some states that could have been set
  29780. * by core environment variables. */
  29781. p_rarch->current_core.has_set_input_descriptors = false;
  29782. p_rarch->current_core.has_set_subsystems = false;
  29783. /* Load the config file now that we know what it is */
  29784. #ifdef HAVE_CONFIGFILE
  29785. if (!p_rarch->rarch_block_config_read)
  29786. #endif
  29787. {
  29788. /* If this is a static build, load salamander
  29789. * config file first (sets RARCH_PATH_CORE) */
  29790. #if !defined(HAVE_DYNAMIC)
  29791. config_load_file_salamander();
  29792. #endif
  29793. config_load(&p_rarch->g_extern);
  29794. }
  29795. /* Second pass: All other arguments override the config file */
  29796. optind = 1;
  29797. if (argc)
  29798. {
  29799. for (;;)
  29800. {
  29801. int c = getopt_long(argc, argv, optstring, opts, NULL);
  29802. if (c == -1)
  29803. break;
  29804. switch (c)
  29805. {
  29806. case 'd':
  29807. {
  29808. unsigned new_port;
  29809. unsigned id = 0;
  29810. struct string_list *list = string_split(optarg, ":");
  29811. int port = 0;
  29812. if (list && list->size == 2)
  29813. {
  29814. port = (int)strtol(list->elems[0].data, NULL, 0);
  29815. id = (unsigned)strtoul(list->elems[1].data, NULL, 0);
  29816. }
  29817. string_list_free(list);
  29818. if (port < 1 || port > MAX_USERS)
  29819. {
  29820. RARCH_ERR("%s\n", msg_hash_to_str(MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT));
  29821. retroarch_print_help(argv[0]);
  29822. retroarch_fail(1, "retroarch_parse_input()");
  29823. }
  29824. new_port = port -1;
  29825. input_config_set_device(new_port, id);
  29826. retroarch_override_setting_set(
  29827. RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE, &new_port);
  29828. }
  29829. break;
  29830. case 'A':
  29831. {
  29832. unsigned new_port;
  29833. int port = (int)strtol(optarg, NULL, 0);
  29834. if (port < 1 || port > MAX_USERS)
  29835. {
  29836. RARCH_ERR("Connect dualanalog to a valid port.\n");
  29837. retroarch_print_help(argv[0]);
  29838. retroarch_fail(1, "retroarch_parse_input()");
  29839. }
  29840. new_port = port - 1;
  29841. input_config_set_device(new_port, RETRO_DEVICE_ANALOG);
  29842. retroarch_override_setting_set(
  29843. RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE, &new_port);
  29844. }
  29845. break;
  29846. case 'f':
  29847. p_rarch->rarch_force_fullscreen = true;
  29848. break;
  29849. case 'v':
  29850. verbosity_enable();
  29851. retroarch_override_setting_set(
  29852. RARCH_OVERRIDE_SETTING_VERBOSITY, NULL);
  29853. break;
  29854. case 'N':
  29855. {
  29856. unsigned new_port;
  29857. int port = (int)strtol(optarg, NULL, 0);
  29858. if (port < 1 || port > MAX_USERS)
  29859. {
  29860. RARCH_ERR("%s\n",
  29861. msg_hash_to_str(MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT));
  29862. retroarch_print_help(argv[0]);
  29863. retroarch_fail(1, "retroarch_parse_input()");
  29864. }
  29865. new_port = port - 1;
  29866. input_config_set_device(port - 1, RETRO_DEVICE_NONE);
  29867. retroarch_override_setting_set(
  29868. RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE, &new_port);
  29869. }
  29870. break;
  29871. case 'r':
  29872. strlcpy(global->record.path, optarg,
  29873. sizeof(global->record.path));
  29874. if (p_rarch->recording_enable)
  29875. p_rarch->recording_enable = true;
  29876. break;
  29877. case RA_OPT_SET_SHADER:
  29878. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  29879. /* disable auto-shaders */
  29880. if (string_is_empty(optarg))
  29881. {
  29882. p_rarch->cli_shader_disable = true;
  29883. break;
  29884. }
  29885. /* rebase on shader directory */
  29886. if (!path_is_absolute(optarg))
  29887. {
  29888. settings_t *settings = p_rarch->configuration_settings;
  29889. char *ref_path = settings->paths.directory_video_shader;
  29890. fill_pathname_join(p_rarch->cli_shader,
  29891. ref_path, optarg, sizeof(p_rarch->cli_shader));
  29892. break;
  29893. }
  29894. strlcpy(p_rarch->cli_shader, optarg, sizeof(p_rarch->cli_shader));
  29895. #endif
  29896. break;
  29897. #ifdef HAVE_DYNAMIC
  29898. case 'L':
  29899. {
  29900. int path_stats;
  29901. if (string_ends_with_size(optarg, "builtin",
  29902. strlen(optarg), STRLEN_CONST("builtin")))
  29903. {
  29904. RARCH_LOG("--libretro argument \"%s\" is a built-in core. Ignoring.\n",
  29905. optarg);
  29906. break;
  29907. }
  29908. path_stats = path_stat(optarg);
  29909. if ((path_stats & RETRO_VFS_STAT_IS_DIRECTORY) != 0)
  29910. {
  29911. settings_t *settings = p_rarch->configuration_settings;
  29912. path_clear(RARCH_PATH_CORE);
  29913. configuration_set_string(settings,
  29914. settings->paths.directory_libretro, optarg);
  29915. retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL);
  29916. retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO_DIRECTORY, NULL);
  29917. RARCH_WARN("Using old --libretro behavior. "
  29918. "Setting libretro_directory to \"%s\" instead.\n",
  29919. optarg);
  29920. }
  29921. else if ((path_stats & RETRO_VFS_STAT_IS_VALID) != 0)
  29922. {
  29923. path_set(RARCH_PATH_CORE, optarg);
  29924. retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL);
  29925. /* We requested explicit core, so use PLAIN core type. */
  29926. retroarch_set_current_core_type(CORE_TYPE_PLAIN, false);
  29927. }
  29928. else
  29929. {
  29930. RARCH_WARN("--libretro argument \"%s\" is neither a file nor directory. Ignoring.\n",
  29931. optarg);
  29932. }
  29933. }
  29934. break;
  29935. #endif
  29936. case 'P':
  29937. #ifdef HAVE_BSV_MOVIE
  29938. strlcpy(p_rarch->bsv_movie_state.movie_start_path, optarg,
  29939. sizeof(p_rarch->bsv_movie_state.movie_start_path));
  29940. p_rarch->bsv_movie_state.movie_start_playback = true;
  29941. p_rarch->bsv_movie_state.movie_start_recording = false;
  29942. #endif
  29943. break;
  29944. case 'R':
  29945. #ifdef HAVE_BSV_MOVIE
  29946. strlcpy(p_rarch->bsv_movie_state.movie_start_path, optarg,
  29947. sizeof(p_rarch->bsv_movie_state.movie_start_path));
  29948. p_rarch->bsv_movie_state.movie_start_playback = false;
  29949. p_rarch->bsv_movie_state.movie_start_recording = true;
  29950. #endif
  29951. break;
  29952. case 'M':
  29953. if (string_is_equal(optarg, "noload-nosave"))
  29954. {
  29955. p_rarch->rarch_is_sram_load_disabled = true;
  29956. p_rarch->rarch_is_sram_save_disabled = true;
  29957. }
  29958. else if (string_is_equal(optarg, "noload-save"))
  29959. p_rarch->rarch_is_sram_load_disabled = true;
  29960. else if (string_is_equal(optarg, "load-nosave"))
  29961. p_rarch->rarch_is_sram_save_disabled = true;
  29962. else if (string_is_not_equal(optarg, "load-save"))
  29963. {
  29964. RARCH_ERR("Invalid argument in --sram-mode.\n");
  29965. retroarch_print_help(argv[0]);
  29966. retroarch_fail(1, "retroarch_parse_input()");
  29967. }
  29968. break;
  29969. #ifdef HAVE_NETWORKING
  29970. case 'H':
  29971. retroarch_override_setting_set(
  29972. RARCH_OVERRIDE_SETTING_NETPLAY_MODE, NULL);
  29973. netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_SERVER, NULL);
  29974. break;
  29975. case 'C':
  29976. {
  29977. settings_t *settings = p_rarch->configuration_settings;
  29978. retroarch_override_setting_set(
  29979. RARCH_OVERRIDE_SETTING_NETPLAY_MODE, NULL);
  29980. retroarch_override_setting_set(
  29981. RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS, NULL);
  29982. netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
  29983. configuration_set_string(settings,
  29984. settings->paths.netplay_server, optarg);
  29985. }
  29986. break;
  29987. case RA_OPT_STATELESS:
  29988. {
  29989. settings_t *settings = p_rarch->configuration_settings;
  29990. configuration_set_bool(settings,
  29991. settings->bools.netplay_stateless_mode, true);
  29992. retroarch_override_setting_set(
  29993. RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE, NULL);
  29994. }
  29995. break;
  29996. case RA_OPT_CHECK_FRAMES:
  29997. {
  29998. settings_t *settings = p_rarch->configuration_settings;
  29999. retroarch_override_setting_set(
  30000. RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES, NULL);
  30001. configuration_set_int(settings,
  30002. settings->ints.netplay_check_frames,
  30003. (int)strtoul(optarg, NULL, 0));
  30004. }
  30005. break;
  30006. case RA_OPT_PORT:
  30007. {
  30008. settings_t *settings = p_rarch->configuration_settings;
  30009. retroarch_override_setting_set(
  30010. RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT, NULL);
  30011. configuration_set_uint(settings,
  30012. settings->uints.netplay_port,
  30013. (int)strtoul(optarg, NULL, 0));
  30014. }
  30015. break;
  30016. #ifdef HAVE_NETWORK_CMD
  30017. case RA_OPT_COMMAND:
  30018. #ifdef HAVE_COMMAND
  30019. if (command_network_send((const char*)optarg))
  30020. exit(0);
  30021. else
  30022. retroarch_fail(1, "network_cmd_send()");
  30023. #endif
  30024. break;
  30025. #endif
  30026. #endif
  30027. case RA_OPT_BPS:
  30028. #ifdef HAVE_PATCH
  30029. strlcpy(global->name.bps, optarg,
  30030. sizeof(global->name.bps));
  30031. p_rarch->rarch_bps_pref = true;
  30032. retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_BPS_PREF, NULL);
  30033. #endif
  30034. break;
  30035. case 'U':
  30036. #ifdef HAVE_PATCH
  30037. strlcpy(global->name.ups, optarg,
  30038. sizeof(global->name.ups));
  30039. p_rarch->rarch_ups_pref = true;
  30040. retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_UPS_PREF, NULL);
  30041. #endif
  30042. break;
  30043. case RA_OPT_IPS:
  30044. #ifdef HAVE_PATCH
  30045. strlcpy(global->name.ips, optarg,
  30046. sizeof(global->name.ips));
  30047. p_rarch->rarch_ips_pref = true;
  30048. retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_IPS_PREF, NULL);
  30049. #endif
  30050. break;
  30051. case RA_OPT_NO_PATCH:
  30052. #ifdef HAVE_PATCH
  30053. p_rarch->rarch_patch_blocked = true;
  30054. #endif
  30055. break;
  30056. case 'D':
  30057. frontend_driver_detach_console();
  30058. break;
  30059. case RA_OPT_MENU:
  30060. explicit_menu = true;
  30061. break;
  30062. case RA_OPT_NICK:
  30063. {
  30064. settings_t *settings = p_rarch->configuration_settings;
  30065. p_rarch->has_set_username = true;
  30066. configuration_set_string(settings,
  30067. settings->paths.username, optarg);
  30068. }
  30069. break;
  30070. case RA_OPT_SIZE:
  30071. if (sscanf(optarg, "%ux%u",
  30072. &p_rarch->recording_width,
  30073. &p_rarch->recording_height) != 2)
  30074. {
  30075. RARCH_ERR("Wrong format for --size.\n");
  30076. retroarch_print_help(argv[0]);
  30077. retroarch_fail(1, "retroarch_parse_input()");
  30078. }
  30079. break;
  30080. case RA_OPT_RECORDCONFIG:
  30081. strlcpy(global->record.config, optarg,
  30082. sizeof(global->record.config));
  30083. break;
  30084. case RA_OPT_MAX_FRAMES:
  30085. p_rarch->runloop_max_frames = (unsigned)strtoul(optarg, NULL, 10);
  30086. break;
  30087. case RA_OPT_MAX_FRAMES_SCREENSHOT:
  30088. #ifdef HAVE_SCREENSHOTS
  30089. p_rarch->runloop_max_frames_screenshot = true;
  30090. #endif
  30091. break;
  30092. case RA_OPT_MAX_FRAMES_SCREENSHOT_PATH:
  30093. #ifdef HAVE_SCREENSHOTS
  30094. strlcpy(p_rarch->runloop_max_frames_screenshot_path,
  30095. optarg,
  30096. sizeof(p_rarch->runloop_max_frames_screenshot_path));
  30097. #endif
  30098. break;
  30099. case RA_OPT_SUBSYSTEM:
  30100. path_set(RARCH_PATH_SUBSYSTEM, optarg);
  30101. break;
  30102. case RA_OPT_FEATURES:
  30103. retroarch_print_features();
  30104. exit(0);
  30105. case RA_OPT_EOF_EXIT:
  30106. #ifdef HAVE_BSV_MOVIE
  30107. p_rarch->bsv_movie_state.eof_exit = true;
  30108. #endif
  30109. break;
  30110. case RA_OPT_VERSION:
  30111. retroarch_print_version();
  30112. exit(0);
  30113. case RA_OPT_LOG_FILE:
  30114. /* Enable 'log to file' */
  30115. configuration_set_bool(p_rarch->configuration_settings,
  30116. p_rarch->configuration_settings->bools.log_to_file, true);
  30117. retroarch_override_setting_set(
  30118. RARCH_OVERRIDE_SETTING_LOG_TO_FILE, NULL);
  30119. /* Cache log file path override */
  30120. rarch_log_file_set_override(optarg);
  30121. break;
  30122. case 'h':
  30123. #ifdef HAVE_CONFIGFILE
  30124. case 'c':
  30125. case RA_OPT_APPENDCONFIG:
  30126. #endif
  30127. case 's':
  30128. case 'S':
  30129. break; /* Handled in the first pass */
  30130. case '?':
  30131. retroarch_print_help(argv[0]);
  30132. retroarch_fail(1, "retroarch_parse_input()");
  30133. case RA_OPT_ACCESSIBILITY:
  30134. #ifdef HAVE_ACCESSIBILITY
  30135. p_rarch->accessibility_enabled = true;
  30136. #endif
  30137. break;
  30138. case RA_OPT_LOAD_MENU_ON_ERROR:
  30139. global->cli_load_menu_on_error = true;
  30140. break;
  30141. default:
  30142. RARCH_ERR("%s\n", msg_hash_to_str(MSG_ERROR_PARSING_ARGUMENTS));
  30143. retroarch_fail(1, "retroarch_parse_input()");
  30144. }
  30145. }
  30146. }
  30147. if (verbosity_is_enabled())
  30148. rarch_log_file_init(
  30149. p_rarch->configuration_settings->bools.log_to_file,
  30150. p_rarch->configuration_settings->bools.log_to_file_timestamp,
  30151. p_rarch->configuration_settings->paths.log_dir);
  30152. #ifdef HAVE_GIT_VERSION
  30153. RARCH_LOG("RetroArch %s (Git %s)\n",
  30154. PACKAGE_VERSION, retroarch_git_version);
  30155. #endif
  30156. if (explicit_menu)
  30157. {
  30158. if (optind < argc)
  30159. {
  30160. RARCH_ERR("--menu was used, but content file was passed as well.\n");
  30161. retroarch_fail(1, "retroarch_parse_input()");
  30162. }
  30163. #ifdef HAVE_DYNAMIC
  30164. else
  30165. {
  30166. /* Allow stray -L arguments to go through to workaround cases
  30167. * where it's used as "config file".
  30168. *
  30169. * This seems to still be the case for Android, which
  30170. * should be properly fixed. */
  30171. retroarch_set_current_core_type(CORE_TYPE_DUMMY, false);
  30172. }
  30173. #endif
  30174. }
  30175. if (optind < argc)
  30176. {
  30177. bool subsystem_path_is_empty = path_is_empty(RARCH_PATH_SUBSYSTEM);
  30178. /* We requested explicit ROM, so use PLAIN core type. */
  30179. retroarch_set_current_core_type(CORE_TYPE_PLAIN, false);
  30180. if (subsystem_path_is_empty)
  30181. path_set(RARCH_PATH_NAMES, (const char*)argv[optind]);
  30182. else
  30183. path_set_special(argv + optind, argc - optind);
  30184. /* Register that content has been set via the
  30185. * command line interface */
  30186. cli_content_set = true;
  30187. }
  30188. /* Check whether a core has been set via the
  30189. * command line interface */
  30190. cli_core_set = (p_rarch->current_core_type != CORE_TYPE_DUMMY);
  30191. /* Update global 'content launched from command
  30192. * line' status flag */
  30193. global->launched_from_cli = cli_active && (cli_core_set || cli_content_set);
  30194. /* Copy SRM/state dirs used, so they can be reused on reentrancy. */
  30195. if (retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_SAVE_PATH, NULL) &&
  30196. path_is_directory(global->name.savefile))
  30197. dir_set(RARCH_DIR_SAVEFILE, global->name.savefile);
  30198. if (retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_STATE_PATH, NULL) &&
  30199. path_is_directory(global->name.savestate))
  30200. dir_set(RARCH_DIR_SAVESTATE, global->name.savestate);
  30201. }
  30202. static bool retroarch_validate_per_core_options(char *s,
  30203. size_t len, bool mkdir,
  30204. const char *core_name, const char *game_name)
  30205. {
  30206. char config_directory[PATH_MAX_LENGTH];
  30207. config_directory[0] = '\0';
  30208. if (!s ||
  30209. (len < 1) ||
  30210. string_is_empty(core_name) ||
  30211. string_is_empty(game_name))
  30212. return false;
  30213. fill_pathname_application_special(config_directory,
  30214. sizeof(config_directory), APPLICATION_SPECIAL_DIRECTORY_CONFIG);
  30215. fill_pathname_join_special_ext(s,
  30216. config_directory, core_name, game_name,
  30217. ".opt", len);
  30218. /* No need to make a directory if file already exists... */
  30219. if (mkdir && !path_is_valid(s))
  30220. {
  30221. char new_path[PATH_MAX_LENGTH];
  30222. new_path[0] = '\0';
  30223. fill_pathname_join(new_path,
  30224. config_directory, core_name, sizeof(new_path));
  30225. if (!path_is_directory(new_path))
  30226. path_mkdir(new_path);
  30227. }
  30228. return true;
  30229. }
  30230. static bool retroarch_validate_game_options(char *s, size_t len, bool mkdir)
  30231. {
  30232. struct rarch_state *p_rarch = &rarch_st;
  30233. const char *core_name = p_rarch->runloop_system.info.library_name;
  30234. const char *game_name = path_basename(path_get(RARCH_PATH_BASENAME));
  30235. return retroarch_validate_per_core_options(s, len, mkdir,
  30236. core_name, game_name);
  30237. }
  30238. static bool retroarch_validate_folder_options(char *s, size_t len, bool mkdir)
  30239. {
  30240. struct rarch_state *p_rarch = &rarch_st;
  30241. const char *core_name = p_rarch->runloop_system.info.library_name;
  30242. const char *game_path = path_get(RARCH_PATH_BASENAME);
  30243. char folder_name[PATH_MAX_LENGTH];
  30244. folder_name[0] = '\0';
  30245. if (string_is_empty(game_path))
  30246. return false;
  30247. fill_pathname_parent_dir_name(folder_name,
  30248. game_path, sizeof(folder_name));
  30249. return retroarch_validate_per_core_options(s, len, mkdir,
  30250. core_name, folder_name);
  30251. }
  30252. /* Validates CPU features for given processor architecture.
  30253. * Make sure we haven't compiled for something we cannot run.
  30254. * Ideally, code would get swapped out depending on CPU support,
  30255. * but this will do for now. */
  30256. static void retroarch_validate_cpu_features(void)
  30257. {
  30258. uint64_t cpu = cpu_features_get();
  30259. (void)cpu;
  30260. #ifdef __MMX__
  30261. if (!(cpu & RETRO_SIMD_MMX))
  30262. FAIL_CPU("MMX");
  30263. #endif
  30264. #ifdef __SSE__
  30265. if (!(cpu & RETRO_SIMD_SSE))
  30266. FAIL_CPU("SSE");
  30267. #endif
  30268. #ifdef __SSE2__
  30269. if (!(cpu & RETRO_SIMD_SSE2))
  30270. FAIL_CPU("SSE2");
  30271. #endif
  30272. #ifdef __AVX__
  30273. if (!(cpu & RETRO_SIMD_AVX))
  30274. FAIL_CPU("AVX");
  30275. #endif
  30276. }
  30277. /**
  30278. * retroarch_main_init:
  30279. * @argc : Count of (commandline) arguments.
  30280. * @argv : (Commandline) arguments.
  30281. *
  30282. * Initializes the program.
  30283. *
  30284. * Returns: true on success, otherwise false if there was an error.
  30285. **/
  30286. bool retroarch_main_init(int argc, char *argv[])
  30287. {
  30288. #if defined(DEBUG) && defined(HAVE_DRMINGW)
  30289. char log_file_name[128];
  30290. #endif
  30291. bool init_failed = false;
  30292. struct rarch_state *p_rarch = &rarch_st;
  30293. global_t *global = &p_rarch->g_extern;
  30294. p_rarch->osk_idx = OSK_LOWERCASE_LATIN;
  30295. p_rarch->video_driver_active = true;
  30296. p_rarch->audio_driver_active = true;
  30297. if (setjmp(p_rarch->error_sjlj_context) > 0)
  30298. {
  30299. RARCH_ERR("%s: \"%s\"\n",
  30300. msg_hash_to_str(MSG_FATAL_ERROR_RECEIVED_IN), p_rarch->error_string);
  30301. goto error;
  30302. }
  30303. p_rarch->rarch_error_on_init = true;
  30304. /* Have to initialise non-file logging once at the start... */
  30305. retro_main_log_file_init(NULL, false);
  30306. retroarch_parse_input_and_config(p_rarch, &p_rarch->g_extern, argc, argv);
  30307. #ifdef HAVE_ACCESSIBILITY
  30308. if (is_accessibility_enabled(p_rarch))
  30309. {
  30310. /* State that the narrator is on, and also include the first menu
  30311. item we're on at startup. */
  30312. accessibility_speak_priority(p_rarch,
  30313. "RetroArch accessibility on. Main Menu Load Core.",
  30314. 10);
  30315. }
  30316. #endif
  30317. if (verbosity_is_enabled())
  30318. {
  30319. {
  30320. char str_output[256];
  30321. const char *cpu_model = NULL;
  30322. str_output[0] = '\0';
  30323. cpu_model = frontend_driver_get_cpu_model_name();
  30324. strlcat(str_output,
  30325. "=== Build =======================================\n",
  30326. sizeof(str_output));
  30327. if (!string_is_empty(cpu_model))
  30328. {
  30329. strlcat(str_output, FILE_PATH_LOG_INFO " CPU Model Name: ", sizeof(str_output));
  30330. strlcat(str_output, cpu_model, sizeof(str_output));
  30331. strlcat(str_output, "\n", sizeof(str_output));
  30332. }
  30333. RARCH_LOG_OUTPUT(str_output);
  30334. }
  30335. {
  30336. char str_output[256];
  30337. char str[128];
  30338. str[0] = str_output[0] = '\0';
  30339. retroarch_get_capabilities(RARCH_CAPABILITIES_CPU, str, sizeof(str));
  30340. strlcat(str_output, msg_hash_to_str(MSG_CAPABILITIES),
  30341. sizeof(str_output));
  30342. strlcat(str_output, ": ", sizeof(str_output));
  30343. strlcat(str_output, str, sizeof(str_output));
  30344. strlcat(str_output, "\n" FILE_PATH_LOG_INFO " Built: " __DATE__ "\n" FILE_PATH_LOG_INFO " Version: " PACKAGE_VERSION "\n", sizeof(str_output));
  30345. #ifdef HAVE_GIT_VERSION
  30346. strlcat(str_output, FILE_PATH_LOG_INFO " Git: ", sizeof(str_output));
  30347. strlcat(str_output, retroarch_git_version, sizeof(str_output));
  30348. strlcat(str_output, "\n", sizeof(str_output));
  30349. #endif
  30350. strlcat(str_output, FILE_PATH_LOG_INFO " =================================================\n", sizeof(str_output));
  30351. RARCH_LOG_OUTPUT(str_output);
  30352. }
  30353. }
  30354. #if defined(DEBUG) && defined(HAVE_DRMINGW)
  30355. RARCH_LOG_OUTPUT("Initializing Dr.MingW Exception handler\n");
  30356. fill_str_dated_filename(log_file_name, "crash",
  30357. "log", sizeof(log_file_name));
  30358. ExcHndlInit();
  30359. ExcHndlSetLogFileNameA(log_file_name);
  30360. #endif
  30361. retroarch_validate_cpu_features();
  30362. retroarch_init_task_queue();
  30363. {
  30364. const char *fullpath = path_get(RARCH_PATH_CONTENT);
  30365. if (!string_is_empty(fullpath))
  30366. {
  30367. settings_t *settings = p_rarch->configuration_settings;
  30368. enum rarch_content_type cont_type = path_is_media_type(fullpath);
  30369. #ifdef HAVE_IMAGEVIEWER
  30370. bool builtin_imageviewer = settings ? settings->bools.multimedia_builtin_imageviewer_enable : false;
  30371. #endif
  30372. bool builtin_mediaplayer = settings ? settings->bools.multimedia_builtin_mediaplayer_enable : false;
  30373. switch (cont_type)
  30374. {
  30375. case RARCH_CONTENT_MOVIE:
  30376. case RARCH_CONTENT_MUSIC:
  30377. if (builtin_mediaplayer)
  30378. {
  30379. /* TODO/FIXME - it needs to become possible to
  30380. * switch between FFmpeg and MPV at runtime */
  30381. #if defined(HAVE_MPV)
  30382. retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL);
  30383. retroarch_set_current_core_type(CORE_TYPE_MPV, false);
  30384. #elif defined(HAVE_FFMPEG)
  30385. retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL);
  30386. retroarch_set_current_core_type(CORE_TYPE_FFMPEG, false);
  30387. #endif
  30388. }
  30389. break;
  30390. #ifdef HAVE_IMAGEVIEWER
  30391. case RARCH_CONTENT_IMAGE:
  30392. if (builtin_imageviewer)
  30393. {
  30394. retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL);
  30395. retroarch_set_current_core_type(CORE_TYPE_IMAGEVIEWER, false);
  30396. }
  30397. break;
  30398. #endif
  30399. #ifdef HAVE_GONG
  30400. case RARCH_CONTENT_GONG:
  30401. retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL);
  30402. retroarch_set_current_core_type(CORE_TYPE_GONG, false);
  30403. break;
  30404. #endif
  30405. default:
  30406. break;
  30407. }
  30408. }
  30409. }
  30410. /* Pre-initialize all drivers
  30411. * Attempts to find a default driver for
  30412. * all driver types.
  30413. */
  30414. audio_driver_find_driver(p_rarch);
  30415. video_driver_find_driver(p_rarch);
  30416. input_driver_find_driver(p_rarch);
  30417. camera_driver_find_driver(p_rarch);
  30418. bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_FIND_DRIVER, NULL);
  30419. wifi_driver_ctl(RARCH_WIFI_CTL_FIND_DRIVER, NULL);
  30420. find_location_driver(p_rarch);
  30421. #ifdef HAVE_MENU
  30422. menu_driver_ctl(RARCH_MENU_CTL_FIND_DRIVER, NULL);
  30423. #endif
  30424. /* Attempt to initialize core */
  30425. if (p_rarch->has_set_core)
  30426. {
  30427. p_rarch->has_set_core = false;
  30428. if (!command_event(CMD_EVENT_CORE_INIT,
  30429. &p_rarch->explicit_current_core_type))
  30430. init_failed = true;
  30431. }
  30432. else if (!command_event(CMD_EVENT_CORE_INIT,
  30433. &p_rarch->current_core_type))
  30434. init_failed = true;
  30435. /* Handle core initialization failure */
  30436. if (init_failed)
  30437. {
  30438. /* Check if menu was active prior to core initialization */
  30439. if ( !global->launched_from_cli
  30440. || global->cli_load_menu_on_error
  30441. #ifdef HAVE_MENU
  30442. || p_rarch->menu_driver_alive
  30443. #endif
  30444. )
  30445. {
  30446. /* Attempt initializing dummy core */
  30447. p_rarch->current_core_type = CORE_TYPE_DUMMY;
  30448. if (!command_event(CMD_EVENT_CORE_INIT, &p_rarch->current_core_type))
  30449. goto error;
  30450. }
  30451. else /* Fall back to regular error handling */
  30452. goto error;
  30453. }
  30454. #ifdef HAVE_CHEATS
  30455. cheat_manager_state_free();
  30456. command_event_init_cheats(p_rarch->configuration_settings, p_rarch);
  30457. #endif
  30458. drivers_init(p_rarch, DRIVERS_CMD_ALL);
  30459. #ifdef HAVE_COMMAND
  30460. input_driver_deinit_command(p_rarch);
  30461. input_driver_init_command(p_rarch);
  30462. #endif
  30463. #ifdef HAVE_NETWORKGAMEPAD
  30464. if (p_rarch->input_driver_remote)
  30465. input_remote_free(p_rarch->input_driver_remote,
  30466. p_rarch->input_driver_max_users);
  30467. p_rarch->input_driver_remote = NULL;
  30468. if (p_rarch->configuration_settings->bools.network_remote_enable)
  30469. p_rarch->input_driver_remote = input_driver_init_remote(
  30470. p_rarch->configuration_settings,
  30471. p_rarch->input_driver_max_users);
  30472. #endif
  30473. if (p_rarch->input_driver_mapper)
  30474. free(p_rarch->input_driver_mapper);
  30475. p_rarch->input_driver_mapper = NULL;
  30476. if (p_rarch->configuration_settings->bools.input_remap_binds_enable)
  30477. p_rarch->input_driver_mapper = (input_mapper_t*)calloc(1, sizeof(*p_rarch->input_driver_mapper));
  30478. #ifdef HAVE_REWIND
  30479. command_event(CMD_EVENT_REWIND_INIT, NULL);
  30480. #endif
  30481. command_event_init_controllers(p_rarch);
  30482. if (!string_is_empty(global->record.path))
  30483. command_event(CMD_EVENT_RECORD_INIT, NULL);
  30484. path_init_savefile(p_rarch);
  30485. command_event(CMD_EVENT_SET_PER_GAME_RESOLUTION, NULL);
  30486. p_rarch->rarch_error_on_init = false;
  30487. p_rarch->rarch_is_inited = true;
  30488. #ifdef HAVE_DISCORD
  30489. if (command_event(CMD_EVENT_DISCORD_INIT, NULL))
  30490. discord_is_inited = true;
  30491. if (discord_is_inited)
  30492. {
  30493. discord_userdata_t userdata;
  30494. userdata.status = DISCORD_PRESENCE_MENU;
  30495. command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
  30496. }
  30497. #endif
  30498. #if defined(HAVE_AUDIOMIXER)
  30499. audio_driver_load_system_sounds();
  30500. #endif
  30501. return true;
  30502. error:
  30503. command_event(CMD_EVENT_CORE_DEINIT, NULL);
  30504. p_rarch->rarch_is_inited = false;
  30505. return false;
  30506. }
  30507. #if 0
  30508. static bool retroarch_is_on_main_thread(void)
  30509. {
  30510. #ifdef HAVE_THREAD_STORAGE
  30511. struct rarch_state *p_rarch = &rarch_st;
  30512. if (sthread_tls_get(&p_rarch->rarch_tls) != MAGIC_POINTER)
  30513. return false;
  30514. #endif
  30515. return true;
  30516. }
  30517. #endif
  30518. #ifdef HAVE_MENU
  30519. /* This callback gets triggered by the keyboard whenever
  30520. * we press or release a keyboard key. When a keyboard
  30521. * key is being pressed down, 'down' will be true. If it
  30522. * is being released, 'down' will be false.
  30523. */
  30524. static void menu_input_key_event(bool down, unsigned keycode,
  30525. uint32_t character, uint16_t mod)
  30526. {
  30527. struct rarch_state *p_rarch = &rarch_st;
  30528. enum retro_key key = (enum retro_key)keycode;
  30529. if (key == RETROK_UNKNOWN)
  30530. {
  30531. unsigned i;
  30532. for (i = 0; i < RETROK_LAST; i++)
  30533. p_rarch->menu_keyboard_key_state[i] =
  30534. (p_rarch->menu_keyboard_key_state[(enum retro_key)i] & 1) << 1;
  30535. }
  30536. else
  30537. p_rarch->menu_keyboard_key_state[key] =
  30538. ((p_rarch->menu_keyboard_key_state[key] & 1) << 1) | down;
  30539. }
  30540. /* Gets called when we want to toggle the menu.
  30541. * If the menu is already running, it will be turned off.
  30542. * If the menu is off, then the menu will be started.
  30543. */
  30544. static void menu_driver_toggle(
  30545. struct rarch_state *p_rarch,
  30546. menu_handle_t *menu,
  30547. settings_t *settings,
  30548. retro_keyboard_event_t *key_event,
  30549. retro_keyboard_event_t *frontend_key_event,
  30550. bool on)
  30551. {
  30552. /* TODO/FIXME - retroarch_main_quit calls menu_driver_toggle -
  30553. * we might have to redesign this to avoid EXXC_BAD_ACCESS errors
  30554. * on OSX - for now we work around this by checking if the settings
  30555. * struct is NULL
  30556. */
  30557. bool pause_libretro = settings ?
  30558. settings->bools.menu_pause_libretro : false;
  30559. #ifdef HAVE_AUDIOMIXER
  30560. bool audio_enable_menu = settings ? settings->bools.audio_enable_menu : false;
  30561. #if 0
  30562. bool audio_enable_menu_bgm = settings ? settings->bools.audio_enable_menu_bgm : false;
  30563. #endif
  30564. #endif
  30565. bool runloop_shutdown_initiated = p_rarch->runloop_shutdown_initiated;
  30566. if (menu->driver_ctx && menu->driver_ctx->toggle)
  30567. menu->driver_ctx->toggle(menu->userdata, on);
  30568. p_rarch->menu_driver_alive = on;
  30569. /* Apply any required menu pointer input inhibits
  30570. * (i.e. prevent phantom input when using an overlay
  30571. * to toggle the menu on) */
  30572. menu_input_driver_toggle(p_rarch,
  30573. &p_rarch->menu_input_state, settings, on);
  30574. if (p_rarch->menu_driver_alive)
  30575. {
  30576. bool refresh = false;
  30577. #ifdef WIIU
  30578. /* Enable burn-in protection menu is running */
  30579. IMEnableDim();
  30580. #endif
  30581. menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
  30582. /* Menu should always run with vsync on. */
  30583. if (p_rarch->current_video->set_nonblock_state)
  30584. p_rarch->current_video->set_nonblock_state(p_rarch->video_driver_data, false,
  30585. video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
  30586. settings->bools.video_adaptive_vsync,
  30587. settings->uints.video_swap_interval
  30588. );
  30589. /* Stop all rumbling before entering the menu. */
  30590. command_event(CMD_EVENT_RUMBLE_STOP, NULL);
  30591. if (pause_libretro && !audio_enable_menu)
  30592. command_event(CMD_EVENT_AUDIO_STOP, NULL);
  30593. #if 0
  30594. if (audio_enable_menu && audio_enable_menu_bgm)
  30595. audio_driver_mixer_play_menu_sound_looped(AUDIO_MIXER_SYSTEM_SLOT_BGM);
  30596. #endif
  30597. /* Override keyboard callback to redirect to menu instead.
  30598. * We'll use this later for something ... */
  30599. if (key_event && frontend_key_event)
  30600. {
  30601. *frontend_key_event = *key_event;
  30602. *key_event = menu_input_key_event;
  30603. p_rarch->runloop_frame_time_last = 0;
  30604. }
  30605. }
  30606. else
  30607. {
  30608. #ifdef WIIU
  30609. /* Disable burn-in protection while core is running; this is needed
  30610. * because HID inputs don't count for the purpose of Wii U
  30611. * power-saving. */
  30612. IMDisableDim();
  30613. #endif
  30614. if (!runloop_shutdown_initiated)
  30615. driver_set_nonblock_state();
  30616. if (pause_libretro && !audio_enable_menu)
  30617. command_event(CMD_EVENT_AUDIO_START, NULL);
  30618. #if 0
  30619. if (audio_enable_menu && audio_enable_menu_bgm)
  30620. audio_driver_mixer_stop_stream(AUDIO_MIXER_SYSTEM_SLOT_BGM);
  30621. #endif
  30622. /* Restore libretro keyboard callback. */
  30623. if (key_event && frontend_key_event)
  30624. *key_event = *frontend_key_event;
  30625. }
  30626. }
  30627. #endif
  30628. void retroarch_menu_running(void)
  30629. {
  30630. struct rarch_state *p_rarch = &rarch_st;
  30631. #if defined(HAVE_MENU) || defined(HAVE_OVERLAY)
  30632. settings_t *settings = p_rarch->configuration_settings;
  30633. #endif
  30634. #ifdef HAVE_OVERLAY
  30635. bool input_overlay_hide_in_menu = settings->bools.input_overlay_hide_in_menu;
  30636. #endif
  30637. #ifdef HAVE_AUDIOMIXER
  30638. bool audio_enable_menu = settings->bools.audio_enable_menu;
  30639. bool audio_enable_menu_bgm = settings->bools.audio_enable_menu_bgm;
  30640. #endif
  30641. #ifdef HAVE_MENU
  30642. menu_handle_t *menu = p_rarch->menu_driver_data;
  30643. if (menu)
  30644. menu_driver_toggle(p_rarch, menu, settings,
  30645. &p_rarch->runloop_key_event,
  30646. &p_rarch->runloop_frontend_key_event,
  30647. true);
  30648. /* Prevent stray input (for a single frame) */
  30649. p_rarch->input_driver_flushing_input = 1;
  30650. #ifdef HAVE_AUDIOMIXER
  30651. if (audio_enable_menu && audio_enable_menu_bgm)
  30652. audio_driver_mixer_play_menu_sound_looped(AUDIO_MIXER_SYSTEM_SLOT_BGM);
  30653. #endif
  30654. /* Ensure that game focus mode is disabled when
  30655. * running the menu (note: it is not currently
  30656. * possible for game focus to be enabled at this
  30657. * point, but must safeguard against future changes) */
  30658. if (p_rarch->game_focus_state.enabled)
  30659. {
  30660. enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_OFF;
  30661. command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd);
  30662. }
  30663. #endif
  30664. #ifdef HAVE_OVERLAY
  30665. if (input_overlay_hide_in_menu)
  30666. command_event(CMD_EVENT_OVERLAY_DEINIT, NULL);
  30667. #endif
  30668. }
  30669. void retroarch_menu_running_finished(bool quit)
  30670. {
  30671. struct rarch_state *p_rarch = &rarch_st;
  30672. #if defined(HAVE_MENU) || defined(HAVE_OVERLAY)
  30673. settings_t *settings = p_rarch->configuration_settings;
  30674. #endif
  30675. #ifdef HAVE_MENU
  30676. menu_handle_t *menu = p_rarch->menu_driver_data;
  30677. if (menu)
  30678. menu_driver_toggle(p_rarch, menu, settings,
  30679. &p_rarch->runloop_key_event,
  30680. &p_rarch->runloop_frontend_key_event,
  30681. false);
  30682. /* Prevent stray input
  30683. * (for a single frame) */
  30684. p_rarch->input_driver_flushing_input = 1;
  30685. #ifdef HAVE_AUDIOMIXER
  30686. if (!quit)
  30687. /* Stop menu background music before we exit the menu */
  30688. if ( settings &&
  30689. settings->bools.audio_enable_menu &&
  30690. settings->bools.audio_enable_menu_bgm
  30691. )
  30692. audio_driver_mixer_stop_stream(AUDIO_MIXER_SYSTEM_SLOT_BGM);
  30693. #endif
  30694. /* Enable game focus mode, if required */
  30695. if (!quit && (p_rarch->current_core_type != CORE_TYPE_DUMMY))
  30696. {
  30697. enum input_auto_game_focus_type auto_game_focus_type = settings ?
  30698. (enum input_auto_game_focus_type)settings->uints.input_auto_game_focus :
  30699. AUTO_GAME_FOCUS_OFF;
  30700. if ((auto_game_focus_type == AUTO_GAME_FOCUS_ON) ||
  30701. ((auto_game_focus_type == AUTO_GAME_FOCUS_DETECT) &&
  30702. p_rarch->game_focus_state.core_requested))
  30703. {
  30704. enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_ON;
  30705. command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd);
  30706. }
  30707. }
  30708. #endif
  30709. video_driver_set_texture_enable(false, false);
  30710. #ifdef HAVE_OVERLAY
  30711. if (!quit)
  30712. if (settings && settings->bools.input_overlay_hide_in_menu)
  30713. retroarch_overlay_init(p_rarch);
  30714. #endif
  30715. }
  30716. /**
  30717. * rarch_game_specific_options:
  30718. *
  30719. * Returns: true (1) if a game specific core
  30720. * options path has been found,
  30721. * otherwise false (0).
  30722. **/
  30723. static bool rarch_game_specific_options(char **output)
  30724. {
  30725. char game_options_path[PATH_MAX_LENGTH];
  30726. game_options_path[0] ='\0';
  30727. if (!retroarch_validate_game_options(game_options_path,
  30728. sizeof(game_options_path), false) ||
  30729. !path_is_valid(game_options_path))
  30730. return false;
  30731. RARCH_LOG("%s %s\n",
  30732. msg_hash_to_str(MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT),
  30733. game_options_path);
  30734. *output = strdup(game_options_path);
  30735. return true;
  30736. }
  30737. /**
  30738. * rarch_folder_specific_options:
  30739. *
  30740. * Returns: true (1) if a folder specific core
  30741. * options path has been found,
  30742. * otherwise false (0).
  30743. **/
  30744. static bool rarch_folder_specific_options(char **output)
  30745. {
  30746. char folder_options_path[PATH_MAX_LENGTH];
  30747. folder_options_path[0] ='\0';
  30748. if (!retroarch_validate_folder_options(folder_options_path,
  30749. sizeof(folder_options_path), false) ||
  30750. !path_is_valid(folder_options_path))
  30751. return false;
  30752. RARCH_LOG("%s %s\n",
  30753. msg_hash_to_str(MSG_FOLDER_SPECIFIC_CORE_OPTIONS_FOUND_AT),
  30754. folder_options_path);
  30755. *output = strdup(folder_options_path);
  30756. return true;
  30757. }
  30758. static void runloop_task_msg_queue_push(
  30759. retro_task_t *task, const char *msg,
  30760. unsigned prio, unsigned duration,
  30761. bool flush)
  30762. {
  30763. #if defined(HAVE_GFX_WIDGETS)
  30764. struct rarch_state *p_rarch = &rarch_st;
  30765. bool widgets_active = p_rarch->widgets_active;
  30766. if (widgets_active && task->title && !task->mute)
  30767. {
  30768. RUNLOOP_MSG_QUEUE_LOCK(p_rarch);
  30769. ui_companion_driver_msg_queue_push(p_rarch, msg,
  30770. prio, task ? duration : duration * 60 / 1000, flush);
  30771. #ifdef HAVE_ACCESSIBILITY
  30772. if (is_accessibility_enabled(p_rarch))
  30773. accessibility_speak_priority(p_rarch, (char*)msg, 0);
  30774. #endif
  30775. gfx_widgets_msg_queue_push(
  30776. &p_rarch->dispwidget_st,
  30777. task,
  30778. msg,
  30779. duration,
  30780. NULL,
  30781. (enum message_queue_icon)MESSAGE_QUEUE_CATEGORY_INFO,
  30782. (enum message_queue_category)MESSAGE_QUEUE_ICON_DEFAULT,
  30783. prio,
  30784. flush,
  30785. #ifdef HAVE_MENU
  30786. p_rarch->menu_driver_alive
  30787. #else
  30788. false
  30789. #endif
  30790. );
  30791. RUNLOOP_MSG_QUEUE_UNLOCK(p_rarch);
  30792. }
  30793. else
  30794. #endif
  30795. runloop_msg_queue_push(msg, prio, duration, flush, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  30796. }
  30797. /* Fetches core options path for current core/content
  30798. * - path: path from which options should be read
  30799. * from/saved to
  30800. * - src_path: in the event that 'path' file does not
  30801. * yet exist, provides source path from which initial
  30802. * options should be extracted
  30803. * */
  30804. static void rarch_init_core_options_path(
  30805. struct rarch_state *p_rarch,
  30806. char *path, size_t len,
  30807. char *src_path, size_t src_len)
  30808. {
  30809. char *game_options_path = NULL;
  30810. char *folder_options_path = NULL;
  30811. settings_t *settings = p_rarch->configuration_settings;
  30812. bool game_specific_options = settings->bools.game_specific_options;
  30813. /* Ensure that 'input' strings are null terminated */
  30814. if (len > 0)
  30815. path[0] = '\0';
  30816. if (src_len > 0)
  30817. src_path[0] = '\0';
  30818. /* Check whether game-specific options exist */
  30819. if (game_specific_options &&
  30820. rarch_game_specific_options(&game_options_path))
  30821. {
  30822. /* Notify system that we have a valid core options
  30823. * override */
  30824. path_set(RARCH_PATH_CORE_OPTIONS, game_options_path);
  30825. p_rarch->runloop_game_options_active = true;
  30826. p_rarch->runloop_folder_options_active = false;
  30827. /* Copy options path */
  30828. strlcpy(path, game_options_path, len);
  30829. free(game_options_path);
  30830. }
  30831. /* Check whether folder-specific options exist */
  30832. else if (game_specific_options &&
  30833. rarch_folder_specific_options(&folder_options_path))
  30834. {
  30835. /* Notify system that we have a valid core options
  30836. * override */
  30837. path_set(RARCH_PATH_CORE_OPTIONS, folder_options_path);
  30838. p_rarch->runloop_game_options_active = false;
  30839. p_rarch->runloop_folder_options_active = true;
  30840. /* Copy options path */
  30841. strlcpy(path, folder_options_path, len);
  30842. free(folder_options_path);
  30843. }
  30844. else
  30845. {
  30846. char global_options_path[PATH_MAX_LENGTH];
  30847. char per_core_options_path[PATH_MAX_LENGTH];
  30848. bool per_core_options_exist = false;
  30849. bool per_core_options = !settings->bools.global_core_options;
  30850. const char *path_core_options = settings->paths.path_core_options;
  30851. global_options_path[0] = '\0';
  30852. per_core_options_path[0] = '\0';
  30853. if (per_core_options)
  30854. {
  30855. const char *core_name = p_rarch->runloop_system.info.library_name;
  30856. /* Get core-specific options path
  30857. * > if retroarch_validate_per_core_options() returns
  30858. * false, then per-core options are disabled (due to
  30859. * unknown system errors...) */
  30860. per_core_options = retroarch_validate_per_core_options(
  30861. per_core_options_path, sizeof(per_core_options_path), true,
  30862. core_name, core_name);
  30863. /* If we can use per-core options, check whether an options
  30864. * file already exists */
  30865. if (per_core_options)
  30866. per_core_options_exist = path_is_valid(per_core_options_path);
  30867. }
  30868. /* If not using per-core options, or if a per-core options
  30869. * file does not yet exist, must fetch 'global' options path */
  30870. if (!per_core_options || !per_core_options_exist)
  30871. {
  30872. const char *options_path = path_core_options;
  30873. if (!string_is_empty(options_path))
  30874. strlcpy(global_options_path,
  30875. options_path, sizeof(global_options_path));
  30876. else if (!path_is_empty(RARCH_PATH_CONFIG))
  30877. fill_pathname_resolve_relative(
  30878. global_options_path, path_get(RARCH_PATH_CONFIG),
  30879. FILE_PATH_CORE_OPTIONS_CONFIG, sizeof(global_options_path));
  30880. }
  30881. /* Allocate correct path/src_path strings */
  30882. if (per_core_options)
  30883. {
  30884. strlcpy(path, per_core_options_path, len);
  30885. if (!per_core_options_exist)
  30886. strlcpy(src_path, global_options_path, src_len);
  30887. }
  30888. else
  30889. strlcpy(path, global_options_path, len);
  30890. /* Notify system that we *do not* have a valid core options
  30891. * options override */
  30892. p_rarch->runloop_game_options_active = false;
  30893. p_rarch->runloop_folder_options_active = false;
  30894. }
  30895. }
  30896. static void rarch_init_core_options(
  30897. struct rarch_state *p_rarch,
  30898. const struct retro_core_option_definition *option_defs)
  30899. {
  30900. char options_path[PATH_MAX_LENGTH];
  30901. char src_options_path[PATH_MAX_LENGTH];
  30902. options_path[0] = '\0';
  30903. src_options_path[0] = '\0';
  30904. /* Get core options file path */
  30905. rarch_init_core_options_path(p_rarch,
  30906. options_path, sizeof(options_path),
  30907. src_options_path, sizeof(src_options_path));
  30908. if (!string_is_empty(options_path))
  30909. p_rarch->runloop_core_options =
  30910. core_option_manager_new(options_path, src_options_path, option_defs);
  30911. }
  30912. void retroarch_init_task_queue(void)
  30913. {
  30914. #ifdef HAVE_THREADS
  30915. struct rarch_state *p_rarch = &rarch_st;
  30916. settings_t *settings = p_rarch->configuration_settings;
  30917. bool threaded_enable = settings->bools.threaded_data_runloop_enable;
  30918. #else
  30919. bool threaded_enable = false;
  30920. #endif
  30921. task_queue_deinit();
  30922. task_queue_init(threaded_enable, runloop_task_msg_queue_push);
  30923. }
  30924. bool rarch_ctl(enum rarch_ctl_state state, void *data)
  30925. {
  30926. struct rarch_state *p_rarch = &rarch_st;
  30927. switch(state)
  30928. {
  30929. case RARCH_CTL_HAS_SET_SUBSYSTEMS:
  30930. return (p_rarch->current_core.has_set_subsystems);
  30931. case RARCH_CTL_CORE_IS_RUNNING:
  30932. return p_rarch->runloop_core_running;
  30933. #ifdef HAVE_BSV_MOVIE
  30934. case RARCH_CTL_BSV_MOVIE_IS_INITED:
  30935. return (p_rarch->bsv_movie_state_handle != NULL);
  30936. #endif
  30937. #ifdef HAVE_PATCH
  30938. case RARCH_CTL_IS_PATCH_BLOCKED:
  30939. return p_rarch->rarch_patch_blocked;
  30940. case RARCH_CTL_IS_BPS_PREF:
  30941. return p_rarch->rarch_bps_pref;
  30942. case RARCH_CTL_UNSET_BPS_PREF:
  30943. p_rarch->rarch_bps_pref = false;
  30944. break;
  30945. case RARCH_CTL_IS_UPS_PREF:
  30946. return p_rarch->rarch_ups_pref;
  30947. case RARCH_CTL_UNSET_UPS_PREF:
  30948. p_rarch->rarch_ups_pref = false;
  30949. break;
  30950. case RARCH_CTL_IS_IPS_PREF:
  30951. return p_rarch->rarch_ips_pref;
  30952. case RARCH_CTL_UNSET_IPS_PREF:
  30953. p_rarch->rarch_ips_pref = false;
  30954. break;
  30955. #endif
  30956. case RARCH_CTL_IS_DUMMY_CORE:
  30957. return (p_rarch->current_core_type == CORE_TYPE_DUMMY);
  30958. case RARCH_CTL_IS_CORE_LOADED:
  30959. {
  30960. const char *core_path = (const char*)data;
  30961. const char *core_file = NULL;
  30962. const char *loaded_core_path = NULL;
  30963. const char *loaded_core_file = NULL;
  30964. if (string_is_empty(core_path))
  30965. return false;
  30966. /* Get core file name */
  30967. core_file = path_basename(core_path);
  30968. if (string_is_empty(core_file))
  30969. return false;
  30970. /* Get loaded core file name */
  30971. loaded_core_path = path_get(RARCH_PATH_CORE);
  30972. if (!string_is_empty(loaded_core_path))
  30973. loaded_core_file = path_basename(loaded_core_path);
  30974. /* Check whether specified core and currently
  30975. * loaded core are the same */
  30976. if (!string_is_empty(loaded_core_file) &&
  30977. string_is_equal(core_file, loaded_core_file))
  30978. return true;
  30979. }
  30980. return false;
  30981. case RARCH_CTL_HAS_SET_USERNAME:
  30982. return p_rarch->has_set_username;
  30983. case RARCH_CTL_IS_INITED:
  30984. return p_rarch->rarch_is_inited;
  30985. case RARCH_CTL_MAIN_DEINIT:
  30986. if (!p_rarch->rarch_is_inited)
  30987. return false;
  30988. command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
  30989. #ifdef HAVE_COMMAND
  30990. input_driver_deinit_command(p_rarch);
  30991. #endif
  30992. #ifdef HAVE_NETWORKGAMEPAD
  30993. if (p_rarch->input_driver_remote)
  30994. input_remote_free(p_rarch->input_driver_remote,
  30995. p_rarch->input_driver_max_users);
  30996. p_rarch->input_driver_remote = NULL;
  30997. #endif
  30998. if (p_rarch->input_driver_mapper)
  30999. free(p_rarch->input_driver_mapper);
  31000. p_rarch->input_driver_mapper = NULL;
  31001. #ifdef HAVE_THREADS
  31002. retroarch_autosave_deinit(p_rarch);
  31003. #endif
  31004. command_event(CMD_EVENT_RECORD_DEINIT, NULL);
  31005. command_event(CMD_EVENT_SAVE_FILES, NULL);
  31006. #ifdef HAVE_REWIND
  31007. command_event(CMD_EVENT_REWIND_DEINIT, NULL);
  31008. #endif
  31009. #ifdef HAVE_CHEATS
  31010. cheat_manager_state_free();
  31011. #endif
  31012. #ifdef HAVE_BSV_MOVIE
  31013. bsv_movie_deinit(p_rarch);
  31014. #endif
  31015. command_event(CMD_EVENT_CORE_DEINIT, NULL);
  31016. content_deinit();
  31017. path_deinit_subsystem(p_rarch);
  31018. path_deinit_savefile();
  31019. p_rarch->rarch_is_inited = false;
  31020. #ifdef HAVE_THREAD_STORAGE
  31021. sthread_tls_delete(&p_rarch->rarch_tls);
  31022. #endif
  31023. break;
  31024. #ifdef HAVE_CONFIGFILE
  31025. case RARCH_CTL_SET_BLOCK_CONFIG_READ:
  31026. p_rarch->rarch_block_config_read = true;
  31027. break;
  31028. case RARCH_CTL_UNSET_BLOCK_CONFIG_READ:
  31029. p_rarch->rarch_block_config_read = false;
  31030. break;
  31031. #endif
  31032. case RARCH_CTL_GET_CORE_OPTION_SIZE:
  31033. {
  31034. unsigned *idx = (unsigned*)data;
  31035. if (!idx)
  31036. return false;
  31037. if (p_rarch->runloop_core_options)
  31038. *idx = (unsigned)p_rarch->runloop_core_options->size;
  31039. else
  31040. *idx = 0;
  31041. }
  31042. break;
  31043. case RARCH_CTL_HAS_CORE_OPTIONS:
  31044. return (p_rarch->runloop_core_options != NULL);
  31045. case RARCH_CTL_CORE_OPTIONS_LIST_GET:
  31046. {
  31047. core_option_manager_t **coreopts = (core_option_manager_t**)data;
  31048. if (!coreopts || !p_rarch->runloop_core_options)
  31049. return false;
  31050. *coreopts = p_rarch->runloop_core_options;
  31051. }
  31052. break;
  31053. #ifdef HAVE_CONFIGFILE
  31054. case RARCH_CTL_IS_OVERRIDES_ACTIVE:
  31055. return p_rarch->runloop_overrides_active;
  31056. case RARCH_CTL_SET_REMAPS_CORE_ACTIVE:
  31057. p_rarch->runloop_remaps_core_active = true;
  31058. break;
  31059. case RARCH_CTL_UNSET_REMAPS_CORE_ACTIVE:
  31060. p_rarch->runloop_remaps_core_active = false;
  31061. break;
  31062. case RARCH_CTL_IS_REMAPS_CORE_ACTIVE:
  31063. return p_rarch->runloop_remaps_core_active;
  31064. case RARCH_CTL_SET_REMAPS_GAME_ACTIVE:
  31065. p_rarch->runloop_remaps_game_active = true;
  31066. break;
  31067. case RARCH_CTL_UNSET_REMAPS_GAME_ACTIVE:
  31068. p_rarch->runloop_remaps_game_active = false;
  31069. break;
  31070. case RARCH_CTL_IS_REMAPS_GAME_ACTIVE:
  31071. return p_rarch->runloop_remaps_game_active;
  31072. case RARCH_CTL_SET_REMAPS_CONTENT_DIR_ACTIVE:
  31073. p_rarch->runloop_remaps_content_dir_active = true;
  31074. break;
  31075. case RARCH_CTL_UNSET_REMAPS_CONTENT_DIR_ACTIVE:
  31076. p_rarch->runloop_remaps_content_dir_active = false;
  31077. break;
  31078. case RARCH_CTL_IS_REMAPS_CONTENT_DIR_ACTIVE:
  31079. return p_rarch->runloop_remaps_content_dir_active;
  31080. #endif
  31081. case RARCH_CTL_SET_MISSING_BIOS:
  31082. p_rarch->runloop_missing_bios = true;
  31083. break;
  31084. case RARCH_CTL_UNSET_MISSING_BIOS:
  31085. p_rarch->runloop_missing_bios = false;
  31086. break;
  31087. case RARCH_CTL_IS_MISSING_BIOS:
  31088. return p_rarch->runloop_missing_bios;
  31089. case RARCH_CTL_IS_GAME_OPTIONS_ACTIVE:
  31090. return p_rarch->runloop_game_options_active;
  31091. case RARCH_CTL_IS_FOLDER_OPTIONS_ACTIVE:
  31092. return p_rarch->runloop_folder_options_active;
  31093. case RARCH_CTL_GET_PERFCNT:
  31094. {
  31095. bool **perfcnt = (bool**)data;
  31096. if (!perfcnt)
  31097. return false;
  31098. *perfcnt = &p_rarch->runloop_perfcnt_enable;
  31099. }
  31100. break;
  31101. case RARCH_CTL_SET_PERFCNT_ENABLE:
  31102. p_rarch->runloop_perfcnt_enable = true;
  31103. break;
  31104. case RARCH_CTL_UNSET_PERFCNT_ENABLE:
  31105. p_rarch->runloop_perfcnt_enable = false;
  31106. break;
  31107. case RARCH_CTL_IS_PERFCNT_ENABLE:
  31108. return p_rarch->runloop_perfcnt_enable;
  31109. case RARCH_CTL_SET_WINDOWED_SCALE:
  31110. {
  31111. unsigned *idx = (unsigned*)data;
  31112. if (!idx)
  31113. return false;
  31114. p_rarch->runloop_pending_windowed_scale = *idx;
  31115. }
  31116. break;
  31117. case RARCH_CTL_STATE_FREE:
  31118. p_rarch->runloop_perfcnt_enable = false;
  31119. p_rarch->runloop_idle = false;
  31120. p_rarch->runloop_paused = false;
  31121. p_rarch->runloop_slowmotion = false;
  31122. #ifdef HAVE_CONFIGFILE
  31123. p_rarch->runloop_overrides_active = false;
  31124. #endif
  31125. p_rarch->runloop_autosave = false;
  31126. retroarch_frame_time_free(p_rarch);
  31127. retroarch_audio_buffer_status_free(p_rarch);
  31128. retroarch_game_focus_free(p_rarch);
  31129. break;
  31130. case RARCH_CTL_IS_IDLE:
  31131. return p_rarch->runloop_idle;
  31132. case RARCH_CTL_SET_IDLE:
  31133. {
  31134. bool *ptr = (bool*)data;
  31135. if (!ptr)
  31136. return false;
  31137. p_rarch->runloop_idle = *ptr;
  31138. }
  31139. break;
  31140. case RARCH_CTL_SET_PAUSED:
  31141. {
  31142. bool *ptr = (bool*)data;
  31143. if (!ptr)
  31144. return false;
  31145. p_rarch->runloop_paused = *ptr;
  31146. }
  31147. break;
  31148. case RARCH_CTL_IS_PAUSED:
  31149. return p_rarch->runloop_paused;
  31150. case RARCH_CTL_SET_SHUTDOWN:
  31151. p_rarch->runloop_shutdown_initiated = true;
  31152. break;
  31153. case RARCH_CTL_CORE_OPTION_PREV:
  31154. /*
  31155. * Get previous value for core option specified by @idx.
  31156. * Options wrap around.
  31157. */
  31158. {
  31159. unsigned *idx = (unsigned*)data;
  31160. if (!idx || !p_rarch->runloop_core_options)
  31161. return false;
  31162. core_option_manager_adjust_val(p_rarch->runloop_core_options, *idx, -1);
  31163. }
  31164. break;
  31165. case RARCH_CTL_CORE_OPTION_NEXT:
  31166. /*
  31167. * Get next value for core option specified by @idx.
  31168. * Options wrap around.
  31169. */
  31170. {
  31171. unsigned* idx = (unsigned*)data;
  31172. if (!idx || !p_rarch->runloop_core_options)
  31173. return false;
  31174. core_option_manager_adjust_val(p_rarch->runloop_core_options, *idx, 1);
  31175. }
  31176. break;
  31177. case RARCH_CTL_NONE:
  31178. default:
  31179. return false;
  31180. }
  31181. return true;
  31182. }
  31183. static void retroarch_deinit_core_options(struct rarch_state *p_rarch)
  31184. {
  31185. /* Check whether game-specific options file is being used */
  31186. if (!path_is_empty(RARCH_PATH_CORE_OPTIONS))
  31187. {
  31188. const char *path = path_get(RARCH_PATH_CORE_OPTIONS);
  31189. config_file_t *conf_tmp = NULL;
  31190. /* We only need to save configuration settings for
  31191. * the current core
  31192. * > If game-specific options file exists, have
  31193. * to read it (to ensure file only gets written
  31194. * if config values change)
  31195. * > Otherwise, create a new, empty config_file_t
  31196. * object */
  31197. if (path_is_valid(path))
  31198. conf_tmp = config_file_new_from_path_to_string(path);
  31199. if (!conf_tmp)
  31200. conf_tmp = config_file_new_alloc();
  31201. if (conf_tmp)
  31202. {
  31203. core_option_manager_flush(
  31204. conf_tmp,
  31205. p_rarch->runloop_core_options);
  31206. RARCH_LOG("[Core Options]: Saved %s-specific core options to \"%s\"\n",
  31207. p_rarch->runloop_game_options_active ? "game" : "folder", path);
  31208. config_file_write(conf_tmp, path, true);
  31209. config_file_free(conf_tmp);
  31210. conf_tmp = NULL;
  31211. }
  31212. path_clear(RARCH_PATH_CORE_OPTIONS);
  31213. }
  31214. else
  31215. {
  31216. const char *path = p_rarch->runloop_core_options->conf_path;
  31217. core_option_manager_flush(
  31218. p_rarch->runloop_core_options->conf,
  31219. p_rarch->runloop_core_options);
  31220. RARCH_LOG("[Core Options]: Saved core options file to \"%s\"\n", path);
  31221. config_file_write(p_rarch->runloop_core_options->conf, path, true);
  31222. }
  31223. p_rarch->runloop_game_options_active = false;
  31224. p_rarch->runloop_folder_options_active = false;
  31225. if (p_rarch->runloop_core_options)
  31226. core_option_manager_free(p_rarch->runloop_core_options);
  31227. p_rarch->runloop_core_options = NULL;
  31228. }
  31229. static void retroarch_init_core_variables(
  31230. struct rarch_state *p_rarch,
  31231. const struct retro_variable *vars)
  31232. {
  31233. char options_path[PATH_MAX_LENGTH];
  31234. char src_options_path[PATH_MAX_LENGTH];
  31235. options_path[0] = '\0';
  31236. src_options_path[0] = '\0';
  31237. /* Get core options file path */
  31238. rarch_init_core_options_path(p_rarch,
  31239. options_path, sizeof(options_path),
  31240. src_options_path, sizeof(src_options_path));
  31241. if (!string_is_empty(options_path))
  31242. p_rarch->runloop_core_options =
  31243. core_option_manager_new_vars(options_path, src_options_path, vars);
  31244. }
  31245. bool retroarch_is_forced_fullscreen(void)
  31246. {
  31247. struct rarch_state *p_rarch = &rarch_st;
  31248. return p_rarch->rarch_force_fullscreen;
  31249. }
  31250. bool retroarch_is_switching_display_mode(void)
  31251. {
  31252. struct rarch_state *p_rarch = &rarch_st;
  31253. return p_rarch->rarch_is_switching_display_mode;
  31254. }
  31255. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  31256. static bool retroarch_load_shader_preset_internal(
  31257. struct rarch_state *p_rarch,
  31258. const char *shader_directory,
  31259. const char *core_name,
  31260. const char *special_name)
  31261. {
  31262. unsigned i;
  31263. char shader_path[PATH_MAX_LENGTH];
  31264. static enum rarch_shader_type types[] =
  31265. {
  31266. /* Shader preset priority, highest to lowest
  31267. * only important for video drivers with multiple shader backends */
  31268. RARCH_SHADER_GLSL, RARCH_SHADER_SLANG, RARCH_SHADER_CG, RARCH_SHADER_HLSL
  31269. };
  31270. for (i = 0; i < ARRAY_SIZE(types); i++)
  31271. {
  31272. if (!video_shader_is_supported(types[i]))
  31273. continue;
  31274. /* Concatenate strings into full paths */
  31275. if (!string_is_empty(core_name))
  31276. fill_pathname_join_special_ext(shader_path,
  31277. shader_directory, core_name,
  31278. special_name,
  31279. video_shader_get_preset_extension(types[i]),
  31280. sizeof(shader_path));
  31281. else
  31282. {
  31283. if (string_is_empty(special_name))
  31284. break;
  31285. fill_pathname_join(shader_path, shader_directory,
  31286. special_name, sizeof(shader_path));
  31287. strlcat(shader_path,
  31288. video_shader_get_preset_extension(types[i]),
  31289. sizeof(shader_path));
  31290. }
  31291. if (!path_is_valid(shader_path))
  31292. continue;
  31293. /* Shader preset exists, load it. */
  31294. RARCH_LOG("[Shaders]: Specific shader preset found at %s.\n",
  31295. shader_path);
  31296. strlcpy(
  31297. p_rarch->runtime_shader_preset,
  31298. shader_path,
  31299. sizeof(p_rarch->runtime_shader_preset));
  31300. return true;
  31301. }
  31302. return false;
  31303. }
  31304. /**
  31305. * retroarch_load_shader_preset:
  31306. *
  31307. * Tries to load a supported core-, game-, folder-specific or global
  31308. * shader preset from its respective location:
  31309. *
  31310. * global: $CONFIG_DIR/global.$PRESET_EXT
  31311. * core-specific: $CONFIG_DIR/$CORE_NAME/$CORE_NAME.$PRESET_EXT
  31312. * folder-specific: $CONFIG_DIR/$CORE_NAME/$FOLDER_NAME.$PRESET_EXT
  31313. * game-specific: $CONFIG_DIR/$CORE_NAME/$GAME_NAME.$PRESET_EXT
  31314. *
  31315. * $CONFIG_DIR is expected to be Menu Config directory, or failing that, the
  31316. * directory where retroarch.cfg is stored.
  31317. *
  31318. * For compatibility purposes with versions 1.8.7 and older, the presets
  31319. * subdirectory on the Video Shader path is used as a fallback directory.
  31320. *
  31321. * Note: Uses video_shader_is_supported() which only works after
  31322. * context driver initialization.
  31323. *
  31324. * Returns: false if there was an error or no action was performed.
  31325. */
  31326. static bool retroarch_load_shader_preset(struct rarch_state *p_rarch)
  31327. {
  31328. settings_t *settings = p_rarch->configuration_settings;
  31329. const char *video_shader_directory = settings->paths.directory_video_shader;
  31330. const char *menu_config_directory = settings->paths.directory_menu_config;
  31331. const char *core_name =
  31332. p_rarch->runloop_system.info.library_name;
  31333. const char *rarch_path_basename = path_get(RARCH_PATH_BASENAME);
  31334. const char *game_name = path_basename(rarch_path_basename);
  31335. const char *dirs[3] = {0};
  31336. size_t i = 0;
  31337. bool ret = false;
  31338. char content_dir_name[PATH_MAX_LENGTH];
  31339. char config_file_directory[PATH_MAX_LENGTH];
  31340. char old_presets_directory[PATH_MAX_LENGTH];
  31341. content_dir_name[0] = '\0';
  31342. config_file_directory[0] = '\0';
  31343. old_presets_directory[0] = '\0';
  31344. if (!string_is_empty(rarch_path_basename))
  31345. fill_pathname_parent_dir_name(content_dir_name,
  31346. rarch_path_basename, sizeof(content_dir_name));
  31347. config_file_directory[0] = '\0';
  31348. if (!path_is_empty(RARCH_PATH_CONFIG))
  31349. fill_pathname_basedir(config_file_directory,
  31350. path_get(RARCH_PATH_CONFIG), sizeof(config_file_directory));
  31351. old_presets_directory[0] = '\0';
  31352. if (!string_is_empty(video_shader_directory))
  31353. fill_pathname_join(old_presets_directory,
  31354. video_shader_directory, "presets", sizeof(old_presets_directory));
  31355. dirs[0] = menu_config_directory;
  31356. dirs[1] = config_file_directory;
  31357. dirs[2] = old_presets_directory;
  31358. for (i = 0; i < ARRAY_SIZE(dirs); i++)
  31359. {
  31360. if (string_is_empty(dirs[i]))
  31361. continue;
  31362. #ifdef DEBUG
  31363. RARCH_LOG("[Shaders]: preset directory: %s\n", dirs[i]);
  31364. #endif
  31365. ret = retroarch_load_shader_preset_internal(p_rarch,
  31366. dirs[i], core_name,
  31367. game_name);
  31368. if (ret)
  31369. {
  31370. #ifdef DEBUG
  31371. RARCH_LOG("[Shaders]: game-specific shader preset found.\n");
  31372. #endif
  31373. break;
  31374. }
  31375. ret = retroarch_load_shader_preset_internal(p_rarch,
  31376. dirs[i], core_name,
  31377. content_dir_name);
  31378. if (ret)
  31379. {
  31380. #ifdef DEBUG
  31381. RARCH_LOG("[Shaders]: folder-specific shader preset found.\n");
  31382. #endif
  31383. break;
  31384. }
  31385. ret = retroarch_load_shader_preset_internal(p_rarch,
  31386. dirs[i], core_name,
  31387. core_name);
  31388. if (ret)
  31389. {
  31390. #ifdef DEBUG
  31391. RARCH_LOG("[Shaders]: core-specific shader preset found.\n");
  31392. #endif
  31393. break;
  31394. }
  31395. ret = retroarch_load_shader_preset_internal(p_rarch,
  31396. dirs[i], NULL,
  31397. "global");
  31398. if (ret)
  31399. {
  31400. #ifdef DEBUG
  31401. RARCH_LOG("[Shaders]: global shader preset found.\n");
  31402. #endif
  31403. break;
  31404. }
  31405. }
  31406. return ret;
  31407. }
  31408. #endif
  31409. /* get the name of the current shader preset */
  31410. const char *retroarch_get_shader_preset(void)
  31411. {
  31412. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  31413. struct rarch_state *p_rarch = &rarch_st;
  31414. settings_t *settings = p_rarch->configuration_settings;
  31415. const char *core_name = p_rarch->runloop_system.info.library_name;
  31416. bool video_shader_enable = settings->bools.video_shader_enable;
  31417. unsigned video_shader_delay = settings->uints.video_shader_delay;
  31418. bool auto_shaders_enable = settings->bools.auto_shaders_enable;
  31419. bool cli_shader_disable = p_rarch->cli_shader_disable;
  31420. if (!video_shader_enable)
  31421. return NULL;
  31422. if (video_shader_delay && !p_rarch->shader_delay_timer.timer_end)
  31423. return NULL;
  31424. /* disallow loading auto-shaders when no core is loaded */
  31425. if (string_is_empty(core_name))
  31426. return NULL;
  31427. if (!string_is_empty(p_rarch->runtime_shader_preset))
  31428. return p_rarch->runtime_shader_preset;
  31429. /* load auto-shader once, --set-shader works like a global auto-shader */
  31430. if (p_rarch->shader_presets_need_reload && !cli_shader_disable)
  31431. {
  31432. p_rarch->shader_presets_need_reload = false;
  31433. if (video_shader_is_supported(video_shader_parse_type(p_rarch->cli_shader)))
  31434. strlcpy(p_rarch->runtime_shader_preset,
  31435. p_rarch->cli_shader,
  31436. sizeof(p_rarch->runtime_shader_preset));
  31437. else
  31438. if (auto_shaders_enable) /* sets runtime_shader_preset */
  31439. retroarch_load_shader_preset(p_rarch);
  31440. return p_rarch->runtime_shader_preset;
  31441. }
  31442. #endif
  31443. return NULL;
  31444. }
  31445. bool retroarch_override_setting_is_set(
  31446. enum rarch_override_setting enum_idx, void *data)
  31447. {
  31448. struct rarch_state *p_rarch = &rarch_st;
  31449. switch (enum_idx)
  31450. {
  31451. case RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE:
  31452. {
  31453. unsigned *val = (unsigned*)data;
  31454. if (val)
  31455. {
  31456. unsigned bit = *val;
  31457. return BIT256_GET(p_rarch->has_set_libretro_device, bit);
  31458. }
  31459. }
  31460. break;
  31461. case RARCH_OVERRIDE_SETTING_VERBOSITY:
  31462. return p_rarch->has_set_verbosity;
  31463. case RARCH_OVERRIDE_SETTING_LIBRETRO:
  31464. return p_rarch->has_set_libretro;
  31465. case RARCH_OVERRIDE_SETTING_LIBRETRO_DIRECTORY:
  31466. return p_rarch->has_set_libretro_directory;
  31467. case RARCH_OVERRIDE_SETTING_SAVE_PATH:
  31468. return p_rarch->has_set_save_path;
  31469. case RARCH_OVERRIDE_SETTING_STATE_PATH:
  31470. return p_rarch->has_set_state_path;
  31471. #ifdef HAVE_NETWORKING
  31472. case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
  31473. return p_rarch->has_set_netplay_mode;
  31474. case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
  31475. return p_rarch->has_set_netplay_ip_address;
  31476. case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
  31477. return p_rarch->has_set_netplay_ip_port;
  31478. case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
  31479. return p_rarch->has_set_netplay_stateless_mode;
  31480. case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
  31481. return p_rarch->has_set_netplay_check_frames;
  31482. #endif
  31483. #ifdef HAVE_PATCH
  31484. case RARCH_OVERRIDE_SETTING_UPS_PREF:
  31485. return p_rarch->has_set_ups_pref;
  31486. case RARCH_OVERRIDE_SETTING_BPS_PREF:
  31487. return p_rarch->has_set_bps_pref;
  31488. case RARCH_OVERRIDE_SETTING_IPS_PREF:
  31489. return p_rarch->has_set_ips_pref;
  31490. #endif
  31491. case RARCH_OVERRIDE_SETTING_LOG_TO_FILE:
  31492. return p_rarch->has_set_log_to_file;
  31493. case RARCH_OVERRIDE_SETTING_NONE:
  31494. default:
  31495. break;
  31496. }
  31497. return false;
  31498. }
  31499. int retroarch_get_capabilities(enum rarch_capabilities type,
  31500. char *s, size_t len)
  31501. {
  31502. switch (type)
  31503. {
  31504. case RARCH_CAPABILITIES_CPU:
  31505. {
  31506. uint64_t cpu = cpu_features_get();
  31507. if (cpu & RETRO_SIMD_MMX)
  31508. strlcat(s, " MMX", len);
  31509. if (cpu & RETRO_SIMD_MMXEXT)
  31510. strlcat(s, " MMXEXT", len);
  31511. if (cpu & RETRO_SIMD_SSE)
  31512. strlcat(s, " SSE", len);
  31513. if (cpu & RETRO_SIMD_SSE2)
  31514. strlcat(s, " SSE2", len);
  31515. if (cpu & RETRO_SIMD_SSE3)
  31516. strlcat(s, " SSE3", len);
  31517. if (cpu & RETRO_SIMD_SSSE3)
  31518. strlcat(s, " SSSE3", len);
  31519. if (cpu & RETRO_SIMD_SSE4)
  31520. strlcat(s, " SSE4", len);
  31521. if (cpu & RETRO_SIMD_SSE42)
  31522. strlcat(s, " SSE4.2", len);
  31523. if (cpu & RETRO_SIMD_AES)
  31524. strlcat(s, " AES", len);
  31525. if (cpu & RETRO_SIMD_AVX)
  31526. strlcat(s, " AVX", len);
  31527. if (cpu & RETRO_SIMD_AVX2)
  31528. strlcat(s, " AVX2", len);
  31529. if (cpu & RETRO_SIMD_NEON)
  31530. strlcat(s, " NEON", len);
  31531. if (cpu & RETRO_SIMD_VFPV3)
  31532. strlcat(s, " VFPv3", len);
  31533. if (cpu & RETRO_SIMD_VFPV4)
  31534. strlcat(s, " VFPv4", len);
  31535. if (cpu & RETRO_SIMD_VMX)
  31536. strlcat(s, " VMX", len);
  31537. if (cpu & RETRO_SIMD_VMX128)
  31538. strlcat(s, " VMX128", len);
  31539. if (cpu & RETRO_SIMD_VFPU)
  31540. strlcat(s, " VFPU", len);
  31541. if (cpu & RETRO_SIMD_PS)
  31542. strlcat(s, " PS", len);
  31543. if (cpu & RETRO_SIMD_ASIMD)
  31544. strlcat(s, " ASIMD", len);
  31545. }
  31546. break;
  31547. case RARCH_CAPABILITIES_COMPILER:
  31548. #if defined(_MSC_VER)
  31549. snprintf(s, len, "%s: MSVC (%d) %u-bit",
  31550. msg_hash_to_str(MSG_COMPILER),
  31551. _MSC_VER, (unsigned)
  31552. (CHAR_BIT * sizeof(size_t)));
  31553. #elif defined(__SNC__)
  31554. snprintf(s, len, "%s: SNC (%d) %u-bit",
  31555. msg_hash_to_str(MSG_COMPILER),
  31556. __SN_VER__, (unsigned)(CHAR_BIT * sizeof(size_t)));
  31557. #elif defined(_WIN32) && defined(__GNUC__)
  31558. snprintf(s, len, "%s: MinGW (%d.%d.%d) %u-bit",
  31559. msg_hash_to_str(MSG_COMPILER),
  31560. __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, (unsigned)
  31561. (CHAR_BIT * sizeof(size_t)));
  31562. #elif defined(__clang__)
  31563. snprintf(s, len, "%s: Clang/LLVM (%s) %u-bit",
  31564. msg_hash_to_str(MSG_COMPILER),
  31565. __clang_version__, (unsigned)(CHAR_BIT * sizeof(size_t)));
  31566. #elif defined(__GNUC__)
  31567. snprintf(s, len, "%s: GCC (%d.%d.%d) %u-bit",
  31568. msg_hash_to_str(MSG_COMPILER),
  31569. __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, (unsigned)
  31570. (CHAR_BIT * sizeof(size_t)));
  31571. #else
  31572. snprintf(s, len, "%s %u-bit",
  31573. msg_hash_to_str(MSG_UNKNOWN_COMPILER),
  31574. (unsigned)(CHAR_BIT * sizeof(size_t)));
  31575. #endif
  31576. break;
  31577. default:
  31578. case RARCH_CAPABILITIES_NONE:
  31579. break;
  31580. }
  31581. return 0;
  31582. }
  31583. void retroarch_set_current_core_type(
  31584. enum rarch_core_type type, bool explicitly_set)
  31585. {
  31586. struct rarch_state *p_rarch = &rarch_st;
  31587. if (p_rarch->has_set_core)
  31588. return;
  31589. if (explicitly_set)
  31590. {
  31591. p_rarch->has_set_core = true;
  31592. p_rarch->explicit_current_core_type = type;
  31593. }
  31594. p_rarch->current_core_type = type;
  31595. }
  31596. /**
  31597. * retroarch_fail:
  31598. * @error_code : Error code.
  31599. * @error : Error message to show.
  31600. *
  31601. * Sanely kills the program.
  31602. **/
  31603. static void retroarch_fail(int error_code, const char *error)
  31604. {
  31605. struct rarch_state *p_rarch = &rarch_st;
  31606. /* We cannot longjmp unless we're in retroarch_main_init().
  31607. * If not, something went very wrong, and we should
  31608. * just exit right away. */
  31609. retro_assert(p_rarch->rarch_error_on_init);
  31610. strlcpy(p_rarch->error_string,
  31611. error, sizeof(p_rarch->error_string));
  31612. longjmp(p_rarch->error_sjlj_context, error_code);
  31613. }
  31614. bool retroarch_main_quit(void)
  31615. {
  31616. struct rarch_state *p_rarch = &rarch_st;
  31617. global_t *global = &p_rarch->g_extern;
  31618. #ifdef HAVE_DISCORD
  31619. discord_state_t *discord_st = &p_rarch->discord_st;
  31620. if (discord_is_inited)
  31621. {
  31622. discord_userdata_t userdata;
  31623. userdata.status = DISCORD_PRESENCE_SHUTDOWN;
  31624. command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
  31625. }
  31626. if (discord_st->ready)
  31627. {
  31628. Discord_ClearPresence();
  31629. Discord_UpdateConnection();
  31630. Discord_Shutdown();
  31631. discord_st->ready = false;
  31632. }
  31633. discord_is_inited = false;
  31634. #endif
  31635. if (!p_rarch->runloop_shutdown_initiated)
  31636. {
  31637. command_event_save_auto_state(p_rarch->configuration_settings,
  31638. global,
  31639. p_rarch);
  31640. /* If any save states are in progress, wait
  31641. * until all tasks are complete (otherwise
  31642. * save state file may be truncated) */
  31643. content_wait_for_save_state_task();
  31644. #ifdef HAVE_CONFIGFILE
  31645. if (p_rarch->runloop_overrides_active)
  31646. command_event_disable_overrides(p_rarch);
  31647. #endif
  31648. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  31649. p_rarch->runtime_shader_preset[0] = '\0';
  31650. #endif
  31651. #ifdef HAVE_CONFIGFILE
  31652. if ( p_rarch->runloop_remaps_core_active
  31653. || p_rarch->runloop_remaps_content_dir_active
  31654. || p_rarch->runloop_remaps_game_active
  31655. )
  31656. input_remapping_set_defaults(true);
  31657. #endif
  31658. }
  31659. p_rarch->runloop_shutdown_initiated = true;
  31660. retroarch_menu_running_finished(true);
  31661. return true;
  31662. }
  31663. void runloop_msg_queue_push(const char *msg,
  31664. unsigned prio, unsigned duration,
  31665. bool flush,
  31666. char *title,
  31667. enum message_queue_icon icon,
  31668. enum message_queue_category category)
  31669. {
  31670. struct rarch_state *p_rarch = &rarch_st;
  31671. #if defined(HAVE_GFX_WIDGETS)
  31672. bool widgets_active = p_rarch->widgets_active;
  31673. #endif
  31674. RUNLOOP_MSG_QUEUE_LOCK(p_rarch);
  31675. #ifdef HAVE_ACCESSIBILITY
  31676. if (is_accessibility_enabled(p_rarch))
  31677. accessibility_speak_priority(p_rarch, (char*) msg, 0);
  31678. #endif
  31679. #if defined(HAVE_GFX_WIDGETS)
  31680. if (widgets_active)
  31681. {
  31682. gfx_widgets_msg_queue_push(
  31683. &p_rarch->dispwidget_st,
  31684. NULL,
  31685. msg,
  31686. roundf((float)duration / 60.0f * 1000.0f),
  31687. title,
  31688. icon,
  31689. category,
  31690. prio,
  31691. flush,
  31692. #ifdef HAVE_MENU
  31693. p_rarch->menu_driver_alive
  31694. #else
  31695. false
  31696. #endif
  31697. );
  31698. duration = duration * 60 / 1000;
  31699. }
  31700. else
  31701. #endif
  31702. {
  31703. if (flush)
  31704. msg_queue_clear(&p_rarch->runloop_msg_queue);
  31705. msg_queue_push(&p_rarch->runloop_msg_queue, msg,
  31706. prio, duration,
  31707. title, icon, category);
  31708. p_rarch->runloop_msg_queue_size = msg_queue_size(
  31709. &p_rarch->runloop_msg_queue);
  31710. }
  31711. ui_companion_driver_msg_queue_push(p_rarch,
  31712. msg,
  31713. prio, duration, flush);
  31714. RUNLOOP_MSG_QUEUE_UNLOCK(p_rarch);
  31715. }
  31716. void runloop_get_status(bool *is_paused, bool *is_idle,
  31717. bool *is_slowmotion, bool *is_perfcnt_enable)
  31718. {
  31719. struct rarch_state *p_rarch = &rarch_st;
  31720. *is_paused = p_rarch->runloop_paused;
  31721. *is_idle = p_rarch->runloop_idle;
  31722. *is_slowmotion = p_rarch->runloop_slowmotion;
  31723. *is_perfcnt_enable = p_rarch->runloop_perfcnt_enable;
  31724. }
  31725. #ifdef HAVE_MENU
  31726. static bool input_driver_toggle_button_combo(
  31727. unsigned mode,
  31728. retro_time_t current_time,
  31729. input_bits_t* p_input)
  31730. {
  31731. switch (mode)
  31732. {
  31733. case INPUT_TOGGLE_DOWN_Y_L_R:
  31734. if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_DOWN) &&
  31735. BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_Y) &&
  31736. BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_L) &&
  31737. BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_R))
  31738. return true;
  31739. break;
  31740. case INPUT_TOGGLE_L3_R3:
  31741. if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_L3) &&
  31742. BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_R3))
  31743. return true;
  31744. break;
  31745. case INPUT_TOGGLE_L1_R1_START_SELECT:
  31746. if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_L) &&
  31747. BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_R) &&
  31748. BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_START) &&
  31749. BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_SELECT))
  31750. return true;
  31751. break;
  31752. case INPUT_TOGGLE_START_SELECT:
  31753. if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_START) &&
  31754. BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_SELECT))
  31755. return true;
  31756. break;
  31757. case INPUT_TOGGLE_L3_R:
  31758. if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_L3) &&
  31759. BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_R))
  31760. return true;
  31761. break;
  31762. case INPUT_TOGGLE_L_R:
  31763. if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_L) &&
  31764. BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_R))
  31765. return true;
  31766. break;
  31767. case INPUT_TOGGLE_DOWN_SELECT:
  31768. if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_DOWN) &&
  31769. BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_SELECT))
  31770. return true;
  31771. break;
  31772. case INPUT_TOGGLE_L2_R2:
  31773. if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_L2) &&
  31774. BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_R2))
  31775. return true;
  31776. break;
  31777. case INPUT_TOGGLE_HOLD_START:
  31778. {
  31779. static rarch_timer_t timer = {0};
  31780. if (!BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_START))
  31781. {
  31782. /* timer only runs while start is held down */
  31783. RARCH_TIMER_END(timer);
  31784. return false;
  31785. }
  31786. /* User started holding down the start button, start the timer */
  31787. if (!timer.timer_begin)
  31788. {
  31789. uint64_t current_usec = cpu_features_get_time_usec();
  31790. RARCH_TIMER_BEGIN_NEW_TIME_USEC(timer,
  31791. current_usec,
  31792. HOLD_BTN_DELAY_SEC * 1000000);
  31793. timer.timer_begin = true;
  31794. timer.timer_end = false;
  31795. }
  31796. RARCH_TIMER_TICK(timer, current_time);
  31797. if (!timer.timer_end && RARCH_TIMER_HAS_EXPIRED(timer))
  31798. {
  31799. /* start has been held down long enough,
  31800. * stop timer and enter menu */
  31801. RARCH_TIMER_END(timer);
  31802. return true;
  31803. }
  31804. return false;
  31805. }
  31806. case INPUT_TOGGLE_HOLD_SELECT:
  31807. {
  31808. static rarch_timer_t timer = {0};
  31809. if (!BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_SELECT))
  31810. {
  31811. /* timer only runs while select is held down */
  31812. RARCH_TIMER_END(timer);
  31813. return false;
  31814. }
  31815. /* user started holding down the select button, start the timer */
  31816. if (!timer.timer_begin)
  31817. {
  31818. uint64_t current_usec = cpu_features_get_time_usec();
  31819. RARCH_TIMER_BEGIN_NEW_TIME_USEC(timer,
  31820. current_usec,
  31821. HOLD_BTN_DELAY_SEC * 1000000);
  31822. timer.timer_begin = true;
  31823. timer.timer_end = false;
  31824. }
  31825. RARCH_TIMER_TICK(timer, current_time);
  31826. if (!timer.timer_end && RARCH_TIMER_HAS_EXPIRED(timer))
  31827. {
  31828. /* select has been held down long enough,
  31829. * stop timer and enter menu */
  31830. RARCH_TIMER_END(timer);
  31831. return true;
  31832. }
  31833. return false;
  31834. }
  31835. default:
  31836. case INPUT_TOGGLE_NONE:
  31837. break;
  31838. }
  31839. return false;
  31840. }
  31841. /* Display the libretro core's framebuffer onscreen. */
  31842. static bool menu_display_libretro(
  31843. struct rarch_state *p_rarch,
  31844. bool libretro_running,
  31845. retro_time_t current_time)
  31846. {
  31847. bool runloop_idle = p_rarch->runloop_idle;
  31848. if ( p_rarch->video_driver_poke &&
  31849. p_rarch->video_driver_poke->set_texture_enable)
  31850. p_rarch->video_driver_poke->set_texture_enable(
  31851. p_rarch->video_driver_data,
  31852. true, false);
  31853. if (libretro_running)
  31854. {
  31855. if (!p_rarch->input_driver_block_libretro_input)
  31856. p_rarch->input_driver_block_libretro_input = true;
  31857. core_run();
  31858. p_rarch->libretro_core_runtime_usec +=
  31859. rarch_core_runtime_tick(p_rarch, current_time);
  31860. p_rarch->input_driver_block_libretro_input = false;
  31861. return false;
  31862. }
  31863. if (runloop_idle)
  31864. {
  31865. #ifdef HAVE_DISCORD
  31866. discord_userdata_t userdata;
  31867. userdata.status = DISCORD_PRESENCE_GAME_PAUSED;
  31868. command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
  31869. #endif
  31870. return false;
  31871. }
  31872. return true;
  31873. }
  31874. #endif
  31875. static void update_savestate_slot(int state_slot)
  31876. {
  31877. char msg[128];
  31878. msg[0] = '\0';
  31879. snprintf(msg, sizeof(msg), "%s: %d",
  31880. msg_hash_to_str(MSG_STATE_SLOT),
  31881. state_slot);
  31882. runloop_msg_queue_push(msg, 2, 180, true, NULL,
  31883. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  31884. RARCH_LOG("%s\n", msg);
  31885. }
  31886. static enum runloop_state runloop_check_state(
  31887. struct rarch_state *p_rarch,
  31888. settings_t *settings,
  31889. retro_time_t current_time)
  31890. {
  31891. input_bits_t current_bits;
  31892. #ifdef HAVE_MENU
  31893. static input_bits_t last_input = {{0}};
  31894. #endif
  31895. static bool old_focus = true;
  31896. struct retro_callbacks *cbs = &p_rarch->retro_ctx;
  31897. bool is_focused = false;
  31898. bool is_alive = false;
  31899. uint64_t frame_count = 0;
  31900. bool focused = true;
  31901. bool rarch_is_initialized = p_rarch->rarch_is_inited;
  31902. bool runloop_paused = p_rarch->runloop_paused;
  31903. float fastforward_ratio = settings->floats.fastforward_ratio;
  31904. bool pause_nonactive = settings->bools.pause_nonactive;
  31905. #ifdef HAVE_MENU
  31906. menu_handle_t *menu = p_rarch->menu_driver_data;
  31907. unsigned menu_toggle_gamepad_combo = settings->uints.input_menu_toggle_gamepad_combo;
  31908. bool menu_driver_binding_state = p_rarch->menu_driver_is_binding;
  31909. bool menu_is_alive = p_rarch->menu_driver_alive;
  31910. bool display_kb = menu_input_dialog_get_display_kb();
  31911. #endif
  31912. #if defined(HAVE_GFX_WIDGETS)
  31913. bool widgets_active = p_rarch->widgets_active;
  31914. #endif
  31915. #ifdef HAVE_CHEEVOS
  31916. bool cheevos_hardcore_active = rcheevos_hardcore_active();
  31917. #endif
  31918. #if defined(HAVE_TRANSLATE) && defined(HAVE_GFX_WIDGETS)
  31919. if (p_rarch->dispwidget_st.ai_service_overlay_state == 3)
  31920. {
  31921. command_event(CMD_EVENT_PAUSE, NULL);
  31922. p_rarch->dispwidget_st.ai_service_overlay_state = 1;
  31923. }
  31924. #endif
  31925. #ifdef HAVE_LIBNX
  31926. /* Should be called once per frame */
  31927. if (!appletMainLoop())
  31928. return RUNLOOP_STATE_QUIT;
  31929. #endif
  31930. #ifdef _3DS
  31931. /* Should be called once per frame */
  31932. if (!aptMainLoop())
  31933. return RUNLOOP_STATE_QUIT;
  31934. #endif
  31935. BIT256_CLEAR_ALL_PTR(&current_bits);
  31936. p_rarch->input_driver_block_libretro_input = false;
  31937. p_rarch->input_driver_block_hotkey = false;
  31938. if (p_rarch->keyboard_mapping_blocked)
  31939. p_rarch->input_driver_block_hotkey = true;
  31940. {
  31941. rarch_joypad_info_t joypad_info;
  31942. unsigned port = 0;
  31943. int input_hotkey_block_delay = settings->uints.input_hotkey_block_delay;
  31944. input_driver_t *current_input = p_rarch->current_input;
  31945. const struct retro_keybind *binds_norm = &input_config_binds[port][RARCH_ENABLE_HOTKEY];
  31946. const struct retro_keybind *binds_auto = &input_autoconf_binds[port][RARCH_ENABLE_HOTKEY];
  31947. const struct retro_keybind *binds = input_config_binds[port];
  31948. struct retro_keybind *auto_binds = input_autoconf_binds[port];
  31949. struct retro_keybind *general_binds = input_config_binds[port];
  31950. #ifdef HAVE_MENU
  31951. bool menu_input_active = menu_is_alive && !(settings->bools.menu_unified_controls && !display_kb);
  31952. #else
  31953. bool menu_input_active = false;
  31954. #endif
  31955. #ifdef HAVE_MFI
  31956. const input_device_driver_t
  31957. *sec_joypad = p_rarch->sec_joypad;
  31958. #else
  31959. const input_device_driver_t
  31960. *sec_joypad = NULL;
  31961. #endif
  31962. joypad_info.joy_idx = settings->uints.input_joypad_map[port];
  31963. joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx];
  31964. joypad_info.axis_threshold = p_rarch->input_driver_axis_threshold;
  31965. #ifdef HAVE_MENU
  31966. if (menu_input_active)
  31967. {
  31968. unsigned k;
  31969. unsigned x_plus = RARCH_ANALOG_LEFT_X_PLUS;
  31970. unsigned y_plus = RARCH_ANALOG_LEFT_Y_PLUS;
  31971. unsigned x_minus = RARCH_ANALOG_LEFT_X_MINUS;
  31972. unsigned y_minus = RARCH_ANALOG_LEFT_Y_MINUS;
  31973. /* Push analog to D-Pad mappings to binds. */
  31974. for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
  31975. {
  31976. (auto_binds)[k].orig_joyaxis = (auto_binds)[k].joyaxis;
  31977. (general_binds)[k].orig_joyaxis = (general_binds)[k].joyaxis;
  31978. }
  31979. if (!INHERIT_JOYAXIS(auto_binds))
  31980. {
  31981. unsigned j = x_plus + 3;
  31982. /* Inherit joyaxis from analogs. */
  31983. for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
  31984. (auto_binds)[k].joyaxis = (auto_binds)[j--].joyaxis;
  31985. }
  31986. if (!INHERIT_JOYAXIS(general_binds))
  31987. {
  31988. unsigned j = x_plus + 3;
  31989. /* Inherit joyaxis from analogs. */
  31990. for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
  31991. (general_binds)[k].joyaxis = (general_binds)[j--].joyaxis;
  31992. }
  31993. }
  31994. #endif
  31995. input_keys_pressed(port, menu_input_active, input_hotkey_block_delay, p_rarch,
  31996. &current_bits, &binds, binds_norm, binds_auto,
  31997. &joypad_info);
  31998. #ifdef HAVE_MENU
  31999. if (menu_input_active)
  32000. {
  32001. unsigned j;
  32002. /* Restores analog D-pad binds temporarily overridden. */
  32003. for (j = RETRO_DEVICE_ID_JOYPAD_UP; j <= RETRO_DEVICE_ID_JOYPAD_RIGHT; j++)
  32004. {
  32005. (auto_binds)[j].joyaxis = (auto_binds)[j].orig_joyaxis;
  32006. (general_binds)[j].joyaxis = (general_binds)[j].orig_joyaxis;
  32007. }
  32008. if ( !display_kb
  32009. && current_input->input_state)
  32010. {
  32011. unsigned i;
  32012. unsigned ids[][2] =
  32013. {
  32014. {RETROK_SPACE, RETRO_DEVICE_ID_JOYPAD_START },
  32015. {RETROK_SLASH, RETRO_DEVICE_ID_JOYPAD_X },
  32016. {RETROK_RSHIFT, RETRO_DEVICE_ID_JOYPAD_SELECT },
  32017. {RETROK_RIGHT, RETRO_DEVICE_ID_JOYPAD_RIGHT },
  32018. {RETROK_LEFT, RETRO_DEVICE_ID_JOYPAD_LEFT },
  32019. {RETROK_DOWN, RETRO_DEVICE_ID_JOYPAD_DOWN },
  32020. {RETROK_UP, RETRO_DEVICE_ID_JOYPAD_UP },
  32021. {RETROK_PAGEUP, RETRO_DEVICE_ID_JOYPAD_L },
  32022. {RETROK_PAGEDOWN, RETRO_DEVICE_ID_JOYPAD_R },
  32023. {0, RARCH_QUIT_KEY },
  32024. {0, RARCH_FULLSCREEN_TOGGLE_KEY },
  32025. {RETROK_BACKSPACE, RETRO_DEVICE_ID_JOYPAD_B },
  32026. {RETROK_RETURN, RETRO_DEVICE_ID_JOYPAD_A },
  32027. {RETROK_DELETE, RETRO_DEVICE_ID_JOYPAD_Y },
  32028. {0, RARCH_UI_COMPANION_TOGGLE },
  32029. {0, RARCH_FPS_TOGGLE },
  32030. {0, RARCH_SEND_DEBUG_INFO },
  32031. {0, RARCH_NETPLAY_HOST_TOGGLE },
  32032. {0, RARCH_MENU_TOGGLE },
  32033. };
  32034. ids[9][0] = input_config_binds[port][RARCH_QUIT_KEY].key;
  32035. ids[10][0] = input_config_binds[port][RARCH_FULLSCREEN_TOGGLE_KEY].key;
  32036. ids[14][0] = input_config_binds[port][RARCH_UI_COMPANION_TOGGLE].key;
  32037. ids[15][0] = input_config_binds[port][RARCH_FPS_TOGGLE].key;
  32038. ids[16][0] = input_config_binds[port][RARCH_SEND_DEBUG_INFO].key;
  32039. ids[17][0] = input_config_binds[port][RARCH_NETPLAY_HOST_TOGGLE].key;
  32040. ids[18][0] = input_config_binds[port][RARCH_MENU_TOGGLE].key;
  32041. if (settings->bools.input_menu_swap_ok_cancel_buttons)
  32042. {
  32043. ids[11][1] = RETRO_DEVICE_ID_JOYPAD_A;
  32044. ids[12][1] = RETRO_DEVICE_ID_JOYPAD_B;
  32045. }
  32046. for (i = 0; i < ARRAY_SIZE(ids); i++)
  32047. {
  32048. if (current_input->input_state(
  32049. p_rarch->current_input_data,
  32050. p_rarch->joypad,
  32051. sec_joypad,
  32052. &joypad_info, &binds,
  32053. p_rarch->keyboard_mapping_blocked,
  32054. port,
  32055. RETRO_DEVICE_KEYBOARD, 0, ids[i][0]))
  32056. BIT256_SET_PTR(&current_bits, ids[i][1]);
  32057. }
  32058. }
  32059. }
  32060. else
  32061. #endif
  32062. {
  32063. #ifdef HAVE_ACCESSIBILITY
  32064. #ifdef HAVE_TRANSLATE
  32065. if (settings->bools.ai_service_enable)
  32066. {
  32067. unsigned i;
  32068. p_rarch->gamepad_input_override = 0;
  32069. for (i = 0; i < MAX_USERS; i++)
  32070. {
  32071. /* Set gamepad input override */
  32072. if (p_rarch->ai_gamepad_state[i] == 2)
  32073. p_rarch->gamepad_input_override |= (1 << i);
  32074. p_rarch->ai_gamepad_state[i] = 0;
  32075. }
  32076. }
  32077. #endif
  32078. #endif
  32079. }
  32080. }
  32081. #ifdef HAVE_MENU
  32082. last_input = current_bits;
  32083. if (
  32084. ((menu_toggle_gamepad_combo != INPUT_TOGGLE_NONE) &&
  32085. input_driver_toggle_button_combo(
  32086. menu_toggle_gamepad_combo, current_time,
  32087. &last_input)))
  32088. BIT256_SET(current_bits, RARCH_MENU_TOGGLE);
  32089. #endif
  32090. if (p_rarch->input_driver_flushing_input > 0)
  32091. {
  32092. bool input_active = bits_any_set(current_bits.data, ARRAY_SIZE(current_bits.data));
  32093. p_rarch->input_driver_flushing_input = input_active
  32094. ? p_rarch->input_driver_flushing_input
  32095. : (p_rarch->input_driver_flushing_input - 1);
  32096. if (input_active || (p_rarch->input_driver_flushing_input > 0))
  32097. {
  32098. BIT256_CLEAR_ALL(current_bits);
  32099. if (runloop_paused)
  32100. BIT256_SET(current_bits, RARCH_PAUSE_TOGGLE);
  32101. }
  32102. }
  32103. if (!VIDEO_DRIVER_IS_THREADED_INTERNAL())
  32104. {
  32105. const ui_application_t *application = p_rarch->ui_companion
  32106. ? p_rarch->ui_companion->application
  32107. : NULL;
  32108. if (application)
  32109. application->process_events();
  32110. }
  32111. frame_count = p_rarch->video_driver_frame_count;
  32112. is_alive = p_rarch->current_video
  32113. ? p_rarch->current_video->alive(p_rarch->video_driver_data)
  32114. : true;
  32115. is_focused = VIDEO_HAS_FOCUS(p_rarch);
  32116. #ifdef HAVE_MENU
  32117. if (menu_driver_binding_state)
  32118. BIT256_CLEAR_ALL(current_bits);
  32119. #endif
  32120. /* Check fullscreen toggle */
  32121. {
  32122. bool fullscreen_toggled = !runloop_paused
  32123. #ifdef HAVE_MENU
  32124. || menu_is_alive;
  32125. #else
  32126. ;
  32127. #endif
  32128. HOTKEY_CHECK(RARCH_FULLSCREEN_TOGGLE_KEY, CMD_EVENT_FULLSCREEN_TOGGLE,
  32129. fullscreen_toggled, NULL);
  32130. }
  32131. /* Check mouse grab toggle */
  32132. HOTKEY_CHECK(RARCH_GRAB_MOUSE_TOGGLE, CMD_EVENT_GRAB_MOUSE_TOGGLE, true, NULL);
  32133. #ifdef HAVE_OVERLAY
  32134. if (settings->bools.input_overlay_enable)
  32135. {
  32136. static char prev_overlay_restore = false;
  32137. static unsigned last_width = 0;
  32138. static unsigned last_height = 0;
  32139. unsigned video_driver_width = p_rarch->video_driver_width;
  32140. unsigned video_driver_height = p_rarch->video_driver_height;
  32141. bool check_next_rotation = true;
  32142. bool input_overlay_hide_in_menu = settings->bools.input_overlay_hide_in_menu;
  32143. bool input_overlay_hide_when_gamepad_connected = settings->bools.input_overlay_hide_when_gamepad_connected;
  32144. bool input_overlay_auto_rotate = settings->bools.input_overlay_auto_rotate;
  32145. /* Check whether overlay should be hidden
  32146. * when a gamepad is connected */
  32147. if (input_overlay_hide_when_gamepad_connected)
  32148. {
  32149. static bool last_controller_connected = false;
  32150. bool controller_connected = (input_config_get_device_name(0) != NULL);
  32151. if (controller_connected != last_controller_connected)
  32152. {
  32153. if (controller_connected)
  32154. retroarch_overlay_deinit(p_rarch);
  32155. else
  32156. retroarch_overlay_init(p_rarch);
  32157. last_controller_connected = controller_connected;
  32158. }
  32159. }
  32160. /* Check next overlay */
  32161. HOTKEY_CHECK(RARCH_OVERLAY_NEXT, CMD_EVENT_OVERLAY_NEXT, true, &check_next_rotation);
  32162. /* Ensure overlay is restored after displaying osk */
  32163. if (p_rarch->input_driver_keyboard_linefeed_enable)
  32164. prev_overlay_restore = true;
  32165. else if (prev_overlay_restore)
  32166. {
  32167. if (!input_overlay_hide_in_menu)
  32168. retroarch_overlay_init(p_rarch);
  32169. prev_overlay_restore = false;
  32170. }
  32171. /* Check whether video aspect has changed */
  32172. if ((video_driver_width != last_width) ||
  32173. (video_driver_height != last_height))
  32174. {
  32175. /* Update scaling/offset factors */
  32176. command_event(CMD_EVENT_OVERLAY_SET_SCALE_FACTOR, NULL);
  32177. /* Check overlay rotation, if required */
  32178. if (input_overlay_auto_rotate)
  32179. input_overlay_auto_rotate_(p_rarch,
  32180. p_rarch->overlay_ptr);
  32181. last_width = video_driver_width;
  32182. last_height = video_driver_height;
  32183. }
  32184. }
  32185. #endif
  32186. /* Check quit key */
  32187. {
  32188. bool trig_quit_key, quit_press_twice;
  32189. static bool quit_key = false;
  32190. static bool old_quit_key = false;
  32191. static bool runloop_exec = false;
  32192. quit_key = BIT256_GET(
  32193. current_bits, RARCH_QUIT_KEY);
  32194. trig_quit_key = quit_key && !old_quit_key;
  32195. old_quit_key = quit_key;
  32196. quit_press_twice = settings->bools.quit_press_twice;
  32197. /* Check double press if enabled */
  32198. if (trig_quit_key && quit_press_twice)
  32199. {
  32200. static retro_time_t quit_key_time = 0;
  32201. retro_time_t cur_time = current_time;
  32202. trig_quit_key = (cur_time - quit_key_time < QUIT_DELAY_USEC);
  32203. quit_key_time = cur_time;
  32204. if (!trig_quit_key)
  32205. {
  32206. float target_hz = 0.0;
  32207. rarch_environment_cb(
  32208. RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE, &target_hz);
  32209. runloop_msg_queue_push(msg_hash_to_str(MSG_PRESS_AGAIN_TO_QUIT), 1,
  32210. QUIT_DELAY_USEC * target_hz / 1000000,
  32211. true, NULL,
  32212. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  32213. }
  32214. }
  32215. if (TIME_TO_EXIT(trig_quit_key))
  32216. {
  32217. bool quit_runloop = false;
  32218. #ifdef HAVE_SCREENSHOTS
  32219. unsigned runloop_max_frames = p_rarch->runloop_max_frames;
  32220. if ((runloop_max_frames != 0)
  32221. && (frame_count >= runloop_max_frames)
  32222. && p_rarch->runloop_max_frames_screenshot)
  32223. {
  32224. const char *screenshot_path = NULL;
  32225. bool fullpath = false;
  32226. if (string_is_empty(p_rarch->runloop_max_frames_screenshot_path))
  32227. screenshot_path = path_get(RARCH_PATH_BASENAME);
  32228. else
  32229. {
  32230. fullpath = true;
  32231. screenshot_path = p_rarch->runloop_max_frames_screenshot_path;
  32232. }
  32233. RARCH_LOG("Taking a screenshot before exiting...\n");
  32234. /* Take a screenshot before we exit. */
  32235. if (!take_screenshot(settings->paths.directory_screenshot,
  32236. screenshot_path, false,
  32237. video_driver_cached_frame_has_valid_framebuffer(), fullpath, false))
  32238. {
  32239. RARCH_ERR("Could not take a screenshot before exiting.\n");
  32240. }
  32241. }
  32242. #endif
  32243. if (runloop_exec)
  32244. runloop_exec = false;
  32245. if (p_rarch->runloop_core_shutdown_initiated &&
  32246. settings->bools.load_dummy_on_core_shutdown)
  32247. {
  32248. content_ctx_info_t content_info;
  32249. content_info.argc = 0;
  32250. content_info.argv = NULL;
  32251. content_info.args = NULL;
  32252. content_info.environ_get = NULL;
  32253. if (task_push_start_dummy_core(&content_info))
  32254. {
  32255. /* Loads dummy core instead of exiting RetroArch completely.
  32256. * Aborts core shutdown if invoked. */
  32257. p_rarch->runloop_shutdown_initiated = false;
  32258. p_rarch->runloop_core_shutdown_initiated = false;
  32259. }
  32260. else
  32261. quit_runloop = true;
  32262. }
  32263. else
  32264. quit_runloop = true;
  32265. p_rarch->runloop_core_running = false;
  32266. if (quit_runloop)
  32267. {
  32268. old_quit_key = quit_key;
  32269. retroarch_main_quit();
  32270. return RUNLOOP_STATE_QUIT;
  32271. }
  32272. }
  32273. }
  32274. #if defined(HAVE_MENU) || defined(HAVE_GFX_WIDGETS)
  32275. gfx_animation_update(
  32276. &p_rarch->anim,
  32277. current_time,
  32278. settings->bools.menu_timedate_enable,
  32279. settings->floats.menu_ticker_speed,
  32280. p_rarch->video_driver_width,
  32281. p_rarch->video_driver_height);
  32282. #if defined(HAVE_GFX_WIDGETS)
  32283. if (widgets_active)
  32284. {
  32285. bool rarch_force_fullscreen = p_rarch->rarch_force_fullscreen;
  32286. bool video_is_fullscreen = settings->bools.video_fullscreen ||
  32287. rarch_force_fullscreen;
  32288. RUNLOOP_MSG_QUEUE_LOCK(p_rarch);
  32289. gfx_widgets_iterate(
  32290. &p_rarch->dispwidget_st,
  32291. &p_rarch->dispgfx,
  32292. p_rarch->video_driver_width,
  32293. p_rarch->video_driver_height,
  32294. video_is_fullscreen,
  32295. settings->paths.directory_assets,
  32296. settings->paths.path_font,
  32297. VIDEO_DRIVER_IS_THREADED_INTERNAL());
  32298. RUNLOOP_MSG_QUEUE_UNLOCK(p_rarch);
  32299. }
  32300. #endif
  32301. #ifdef HAVE_MENU
  32302. if (menu_is_alive)
  32303. {
  32304. enum menu_action action;
  32305. static input_bits_t old_input = {{0}};
  32306. static enum menu_action
  32307. old_action = MENU_ACTION_CANCEL;
  32308. struct menu_state *menu_st = &p_rarch->menu_driver_state;
  32309. bool focused = false;
  32310. input_bits_t trigger_input = current_bits;
  32311. global_t *global = &p_rarch->g_extern;
  32312. cbs->poll_cb();
  32313. bits_clear_bits(trigger_input.data, old_input.data,
  32314. ARRAY_SIZE(trigger_input.data));
  32315. action = (enum menu_action)menu_event(
  32316. p_rarch,
  32317. &current_bits, &trigger_input, display_kb);
  32318. focused = pause_nonactive ? is_focused : true;
  32319. focused = focused &&
  32320. !p_rarch->main_ui_companion_is_on_foreground;
  32321. if (global)
  32322. {
  32323. if (action == old_action)
  32324. {
  32325. retro_time_t press_time = current_time;
  32326. if (action == MENU_ACTION_NOOP)
  32327. global->menu.noop_press_time = press_time - global->menu.noop_start_time;
  32328. else
  32329. global->menu.action_press_time = press_time - global->menu.action_start_time;
  32330. }
  32331. else
  32332. {
  32333. if (action == MENU_ACTION_NOOP)
  32334. {
  32335. global->menu.noop_start_time = current_time;
  32336. global->menu.noop_press_time = 0;
  32337. if (global->menu_prev_action == old_action)
  32338. global->menu.action_start_time = global->menu.prev_start_time;
  32339. else
  32340. global->menu.action_start_time = current_time;
  32341. }
  32342. else
  32343. {
  32344. if ( global->menu_prev_action == action &&
  32345. global->menu.noop_press_time < 200000) /* 250ms */
  32346. {
  32347. global->menu.action_start_time = global->menu.prev_start_time;
  32348. global->menu.action_press_time = current_time - global->menu.action_start_time;
  32349. }
  32350. else
  32351. {
  32352. global->menu.prev_start_time = current_time;
  32353. global->menu_prev_action = action;
  32354. global->menu.action_press_time = 0;
  32355. }
  32356. }
  32357. }
  32358. }
  32359. /* Get current time */
  32360. menu_st->current_time_us = current_time;
  32361. /* Iterate the menu driver for one frame. */
  32362. if (menu_st->pending_quick_menu)
  32363. {
  32364. /* If the user had requested that the Quick Menu
  32365. * be spawned during the previous frame, do this now
  32366. * and exit the function to go to the next frame.
  32367. */
  32368. menu_entries_flush_stack(NULL, MENU_SETTINGS);
  32369. gfx_display_set_msg_force(true);
  32370. generic_action_ok_displaylist_push("", NULL,
  32371. "", 0, 0, 0, ACTION_OK_DL_CONTENT_SETTINGS);
  32372. menu_st->selection_ptr = 0;
  32373. menu_st->pending_quick_menu = false;
  32374. }
  32375. else if (!menu_driver_iterate(p_rarch, action, current_time))
  32376. {
  32377. if (p_rarch->rarch_error_on_init)
  32378. {
  32379. content_ctx_info_t content_info = {0};
  32380. task_push_start_dummy_core(&content_info);
  32381. }
  32382. else
  32383. retroarch_menu_running_finished(false);
  32384. }
  32385. if (focused || !p_rarch->runloop_idle)
  32386. {
  32387. bool rarch_is_inited = p_rarch->rarch_is_inited;
  32388. bool menu_pause_libretro = settings->bools.menu_pause_libretro;
  32389. bool libretro_running = !menu_pause_libretro
  32390. && rarch_is_inited
  32391. && (p_rarch->current_core_type != CORE_TYPE_DUMMY);
  32392. if (menu)
  32393. {
  32394. if (BIT64_GET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER)
  32395. != BIT64_GET(menu->state, MENU_STATE_RENDER_MESSAGEBOX))
  32396. BIT64_SET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER);
  32397. if (BIT64_GET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER))
  32398. p_rarch->dispgfx.framebuf_dirty = true;
  32399. if (BIT64_GET(menu->state, MENU_STATE_RENDER_MESSAGEBOX)
  32400. && !string_is_empty(menu->menu_state_msg))
  32401. {
  32402. if (menu->driver_ctx->render_messagebox)
  32403. menu->driver_ctx->render_messagebox(
  32404. menu->userdata,
  32405. menu->menu_state_msg);
  32406. if (p_rarch->main_ui_companion_is_on_foreground)
  32407. {
  32408. if ( p_rarch->ui_companion &&
  32409. p_rarch->ui_companion->render_messagebox)
  32410. p_rarch->ui_companion->render_messagebox(menu->menu_state_msg);
  32411. }
  32412. }
  32413. if (BIT64_GET(menu->state, MENU_STATE_BLIT))
  32414. {
  32415. if (menu->driver_ctx->render)
  32416. menu->driver_ctx->render(
  32417. menu->userdata,
  32418. p_rarch->video_driver_width,
  32419. p_rarch->video_driver_height,
  32420. p_rarch->runloop_idle);
  32421. }
  32422. if (p_rarch->menu_driver_alive && !p_rarch->runloop_idle)
  32423. if (menu_display_libretro(p_rarch,
  32424. libretro_running, current_time))
  32425. video_driver_cached_frame();
  32426. if (menu->driver_ctx->set_texture)
  32427. menu->driver_ctx->set_texture(menu->userdata);
  32428. menu->state = 0;
  32429. }
  32430. if (settings->bools.audio_enable_menu &&
  32431. !libretro_running)
  32432. audio_driver_menu_sample();
  32433. }
  32434. old_input = current_bits;
  32435. old_action = action;
  32436. if (!focused || p_rarch->runloop_idle)
  32437. return RUNLOOP_STATE_POLLED_AND_SLEEP;
  32438. }
  32439. else
  32440. #endif
  32441. #endif
  32442. {
  32443. if (p_rarch->runloop_idle)
  32444. {
  32445. cbs->poll_cb();
  32446. return RUNLOOP_STATE_POLLED_AND_SLEEP;
  32447. }
  32448. }
  32449. /* Check game focus toggle */
  32450. {
  32451. enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_TOGGLE;
  32452. HOTKEY_CHECK(RARCH_GAME_FOCUS_TOGGLE, CMD_EVENT_GAME_FOCUS_TOGGLE, true, &game_focus_cmd);
  32453. }
  32454. /* Check if we have pressed the UI companion toggle button */
  32455. HOTKEY_CHECK(RARCH_UI_COMPANION_TOGGLE, CMD_EVENT_UI_COMPANION_TOGGLE, true, NULL);
  32456. /* Check close content key */
  32457. HOTKEY_CHECK(RARCH_CLOSE_CONTENT_KEY, CMD_EVENT_CLOSE_CONTENT, true, NULL);
  32458. #ifdef HAVE_MENU
  32459. /* Check if we have pressed the menu toggle button */
  32460. {
  32461. static bool old_pressed = false;
  32462. char *menu_driver = settings->arrays.menu_driver;
  32463. bool pressed = BIT256_GET(
  32464. current_bits, RARCH_MENU_TOGGLE) &&
  32465. !string_is_equal(menu_driver, "null");
  32466. bool core_type_is_dummy = p_rarch->current_core_type == CORE_TYPE_DUMMY;
  32467. if (p_rarch->menu_keyboard_key_state[RETROK_F1] == 1)
  32468. {
  32469. if (p_rarch->menu_driver_alive)
  32470. {
  32471. if (rarch_is_initialized && !core_type_is_dummy)
  32472. {
  32473. retroarch_menu_running_finished(false);
  32474. p_rarch->menu_keyboard_key_state[RETROK_F1] =
  32475. ((p_rarch->menu_keyboard_key_state[RETROK_F1] & 1) << 1) | false;
  32476. }
  32477. }
  32478. }
  32479. else if ((!p_rarch->menu_keyboard_key_state[RETROK_F1] &&
  32480. (pressed && !old_pressed)) ||
  32481. core_type_is_dummy)
  32482. {
  32483. if (p_rarch->menu_driver_alive)
  32484. {
  32485. if (rarch_is_initialized && !core_type_is_dummy)
  32486. retroarch_menu_running_finished(false);
  32487. }
  32488. else
  32489. {
  32490. retroarch_menu_running();
  32491. }
  32492. }
  32493. else
  32494. p_rarch->menu_keyboard_key_state[RETROK_F1] =
  32495. ((p_rarch->menu_keyboard_key_state[RETROK_F1] & 1) << 1) | false;
  32496. old_pressed = pressed;
  32497. }
  32498. /* Check if we have pressed the FPS toggle button */
  32499. HOTKEY_CHECK(RARCH_FPS_TOGGLE, CMD_EVENT_FPS_TOGGLE, true, NULL);
  32500. /* Check if we have pressed the netplay host toggle button */
  32501. HOTKEY_CHECK(RARCH_NETPLAY_HOST_TOGGLE, CMD_EVENT_NETPLAY_HOST_TOGGLE, true, NULL);
  32502. if (p_rarch->menu_driver_alive)
  32503. {
  32504. if (!settings->bools.menu_throttle_framerate && !fastforward_ratio)
  32505. return RUNLOOP_STATE_MENU_ITERATE;
  32506. return RUNLOOP_STATE_END;
  32507. }
  32508. #endif
  32509. if (pause_nonactive)
  32510. focused = is_focused;
  32511. #ifdef HAVE_SCREENSHOTS
  32512. /* Check if we have pressed the screenshot toggle button */
  32513. HOTKEY_CHECK(RARCH_SCREENSHOT, CMD_EVENT_TAKE_SCREENSHOT, true, NULL);
  32514. #endif
  32515. /* Check if we have pressed the audio mute toggle button */
  32516. HOTKEY_CHECK(RARCH_MUTE, CMD_EVENT_AUDIO_MUTE_TOGGLE, true, NULL);
  32517. /* Check if we have pressed the OSK toggle button */
  32518. HOTKEY_CHECK(RARCH_OSK, CMD_EVENT_OSK_TOGGLE, true, NULL);
  32519. /* Check if we have pressed the recording toggle button */
  32520. HOTKEY_CHECK(RARCH_RECORDING_TOGGLE, CMD_EVENT_RECORDING_TOGGLE, true, NULL);
  32521. /* Check if we have pressed the streaming toggle button */
  32522. HOTKEY_CHECK(RARCH_STREAMING_TOGGLE, CMD_EVENT_STREAMING_TOGGLE, true, NULL);
  32523. /* Check if we have pressed the Run-Ahead toggle button */
  32524. HOTKEY_CHECK(RARCH_RUNAHEAD_TOGGLE, CMD_EVENT_RUNAHEAD_TOGGLE, true, NULL);
  32525. /* Check if we have pressed the AI Service toggle button */
  32526. HOTKEY_CHECK(RARCH_AI_SERVICE, CMD_EVENT_AI_SERVICE_TOGGLE, true, NULL);
  32527. if (BIT256_GET(current_bits, RARCH_VOLUME_UP))
  32528. command_event(CMD_EVENT_VOLUME_UP, NULL);
  32529. else if (BIT256_GET(current_bits, RARCH_VOLUME_DOWN))
  32530. command_event(CMD_EVENT_VOLUME_DOWN, NULL);
  32531. #ifdef HAVE_NETWORKING
  32532. /* Check Netplay */
  32533. HOTKEY_CHECK(RARCH_NETPLAY_GAME_WATCH, CMD_EVENT_NETPLAY_GAME_WATCH, true, NULL);
  32534. #endif
  32535. /* Check if we have pressed the pause button */
  32536. {
  32537. static bool old_frameadvance = false;
  32538. static bool old_pause_pressed = false;
  32539. bool frameadvance_pressed = false;
  32540. bool trig_frameadvance = false;
  32541. bool pause_pressed = BIT256_GET(current_bits, RARCH_PAUSE_TOGGLE);
  32542. #ifdef HAVE_CHEEVOS
  32543. if (cheevos_hardcore_active)
  32544. {
  32545. static int unpaused_frames = 0;
  32546. /* Frame advance is not allowed when achievement hardcore is active */
  32547. if (!p_rarch->runloop_paused)
  32548. {
  32549. /* Limit pause to approximately three times per second (depending on core framerate) */
  32550. if (unpaused_frames < 20)
  32551. {
  32552. ++unpaused_frames;
  32553. pause_pressed = false;
  32554. }
  32555. }
  32556. else
  32557. unpaused_frames = 0;
  32558. }
  32559. else
  32560. #endif
  32561. {
  32562. frameadvance_pressed = BIT256_GET(current_bits, RARCH_FRAMEADVANCE);
  32563. trig_frameadvance = frameadvance_pressed && !old_frameadvance;
  32564. /* FRAMEADVANCE will set us into pause mode. */
  32565. pause_pressed |= !p_rarch->runloop_paused
  32566. && trig_frameadvance;
  32567. }
  32568. /* Check if libretro pause key was pressed. If so, pause or
  32569. * unpause the libretro core. */
  32570. if (focused && pause_pressed && !old_pause_pressed)
  32571. command_event(CMD_EVENT_PAUSE_TOGGLE, NULL);
  32572. else if (focused && !old_focus)
  32573. command_event(CMD_EVENT_UNPAUSE, NULL);
  32574. else if (!focused && old_focus)
  32575. command_event(CMD_EVENT_PAUSE, NULL);
  32576. old_focus = focused;
  32577. old_pause_pressed = pause_pressed;
  32578. old_frameadvance = frameadvance_pressed;
  32579. if (p_rarch->runloop_paused)
  32580. {
  32581. bool toggle = !p_rarch->runloop_idle ? true : false;
  32582. HOTKEY_CHECK(RARCH_FULLSCREEN_TOGGLE_KEY,
  32583. CMD_EVENT_FULLSCREEN_TOGGLE, true, &toggle);
  32584. /* Check if it's not oneshot */
  32585. #ifdef HAVE_REWIND
  32586. if (!(trig_frameadvance || BIT256_GET(current_bits, RARCH_REWIND)))
  32587. #else
  32588. if (!trig_frameadvance)
  32589. #endif
  32590. focused = false;
  32591. }
  32592. }
  32593. #ifdef HAVE_ACCESSIBILITY
  32594. #ifdef HAVE_TRANSLATE
  32595. /* Copy over the retropad state to a buffer for the translate service
  32596. to send off if it's run. */
  32597. if (settings->bools.ai_service_enable)
  32598. {
  32599. p_rarch->ai_gamepad_state[0] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_B);
  32600. p_rarch->ai_gamepad_state[1] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_Y);
  32601. p_rarch->ai_gamepad_state[2] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_SELECT);
  32602. p_rarch->ai_gamepad_state[3] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_START);
  32603. p_rarch->ai_gamepad_state[4] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_UP);
  32604. p_rarch->ai_gamepad_state[5] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_DOWN);
  32605. p_rarch->ai_gamepad_state[6] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_LEFT);
  32606. p_rarch->ai_gamepad_state[7] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_RIGHT);
  32607. p_rarch->ai_gamepad_state[8] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_A);
  32608. p_rarch->ai_gamepad_state[9] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_X);
  32609. p_rarch->ai_gamepad_state[10] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_L);
  32610. p_rarch->ai_gamepad_state[11] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_R);
  32611. p_rarch->ai_gamepad_state[12] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_L2);
  32612. p_rarch->ai_gamepad_state[13] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_R2);
  32613. p_rarch->ai_gamepad_state[14] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_L3);
  32614. p_rarch->ai_gamepad_state[15] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_R3);
  32615. }
  32616. #endif
  32617. #endif
  32618. if (!focused)
  32619. {
  32620. cbs->poll_cb();
  32621. return RUNLOOP_STATE_POLLED_AND_SLEEP;
  32622. }
  32623. /* Check if we have pressed the fast forward button */
  32624. /* To avoid continuous switching if we hold the button down, we require
  32625. * that the button must go from pressed to unpressed back to pressed
  32626. * to be able to toggle between then.
  32627. */
  32628. {
  32629. static bool old_button_state = false;
  32630. static bool old_hold_button_state = false;
  32631. bool new_button_state = BIT256_GET(
  32632. current_bits, RARCH_FAST_FORWARD_KEY);
  32633. bool new_hold_button_state = BIT256_GET(
  32634. current_bits, RARCH_FAST_FORWARD_HOLD_KEY);
  32635. bool check2 = new_button_state && !old_button_state;
  32636. if (!check2)
  32637. check2 = old_hold_button_state != new_hold_button_state;
  32638. if (check2)
  32639. {
  32640. bool check1 = p_rarch->input_driver_nonblock_state;
  32641. p_rarch->input_driver_nonblock_state = !check1;
  32642. p_rarch->runloop_fastmotion = !check1;
  32643. if (check1)
  32644. p_rarch->fastforward_after_frames = 1;
  32645. driver_set_nonblock_state();
  32646. /* Reset frame time counter when toggling
  32647. * fast-forward off, if required */
  32648. if (!p_rarch->runloop_fastmotion &&
  32649. settings->bools.frame_time_counter_reset_after_fastforwarding)
  32650. p_rarch->video_driver_frame_time_count = 0;
  32651. }
  32652. old_button_state = new_button_state;
  32653. old_hold_button_state = new_hold_button_state;
  32654. /* Display fast-forward notification
  32655. * > Use widgets, if enabled */
  32656. #if defined(HAVE_GFX_WIDGETS)
  32657. if (widgets_active)
  32658. p_rarch->gfx_widgets_fast_forward =
  32659. settings->bools.notification_show_fast_forward ?
  32660. p_rarch->runloop_fastmotion : false;
  32661. else
  32662. #endif
  32663. {
  32664. /* > If widgets are disabled, display fast-forward
  32665. * status via OSD text for 1 frame every frame */
  32666. if (p_rarch->runloop_fastmotion &&
  32667. settings->bools.notification_show_fast_forward)
  32668. runloop_msg_queue_push(
  32669. msg_hash_to_str(MSG_FAST_FORWARD), 1, 1, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  32670. }
  32671. }
  32672. /* Check if we have pressed any of the state slot buttons */
  32673. {
  32674. static bool old_should_slot_increase = false;
  32675. static bool old_should_slot_decrease = false;
  32676. bool should_slot_increase = BIT256_GET(
  32677. current_bits, RARCH_STATE_SLOT_PLUS);
  32678. bool should_slot_decrease = BIT256_GET(
  32679. current_bits, RARCH_STATE_SLOT_MINUS);
  32680. bool check1 = true;
  32681. bool check2 = should_slot_increase && !old_should_slot_increase;
  32682. int addition = 1;
  32683. int state_slot = settings->ints.state_slot;
  32684. if (!check2)
  32685. {
  32686. check2 = should_slot_decrease && !old_should_slot_decrease;
  32687. check1 = state_slot > 0;
  32688. addition = -1;
  32689. }
  32690. /* Checks if the state increase/decrease keys have been pressed
  32691. * for this frame. */
  32692. if (check2)
  32693. {
  32694. int cur_state_slot = state_slot;
  32695. if (check1)
  32696. configuration_set_int(settings, settings->ints.state_slot,
  32697. cur_state_slot + addition);
  32698. update_savestate_slot(settings->ints.state_slot);
  32699. }
  32700. old_should_slot_increase = should_slot_increase;
  32701. old_should_slot_decrease = should_slot_decrease;
  32702. }
  32703. /* Check if we have pressed any of the savestate buttons */
  32704. HOTKEY_CHECK(RARCH_SAVE_STATE_KEY, CMD_EVENT_SAVE_STATE, true, NULL);
  32705. HOTKEY_CHECK(RARCH_LOAD_STATE_KEY, CMD_EVENT_LOAD_STATE, true, NULL);
  32706. #ifdef HAVE_CHEEVOS
  32707. if (!cheevos_hardcore_active)
  32708. #endif
  32709. {
  32710. /* Check if rewind toggle was being held. */
  32711. {
  32712. #ifdef HAVE_REWIND
  32713. char s[128];
  32714. bool rewinding = false;
  32715. unsigned t = 0;
  32716. s[0] = '\0';
  32717. rewinding = state_manager_check_rewind(
  32718. &p_rarch->rewind_st,
  32719. BIT256_GET(current_bits, RARCH_REWIND),
  32720. settings->uints.rewind_granularity,
  32721. p_rarch->runloop_paused,
  32722. s, sizeof(s), &t);
  32723. #if defined(HAVE_GFX_WIDGETS)
  32724. if (widgets_active)
  32725. p_rarch->gfx_widgets_rewinding = rewinding;
  32726. else
  32727. #endif
  32728. {
  32729. if (rewinding)
  32730. runloop_msg_queue_push(s, 0, t, true, NULL,
  32731. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  32732. }
  32733. #endif
  32734. }
  32735. {
  32736. /* Checks if slowmotion toggle/hold was being pressed and/or held. */
  32737. static bool old_slowmotion_button_state = false;
  32738. static bool old_slowmotion_hold_button_state = false;
  32739. bool new_slowmotion_button_state = BIT256_GET(
  32740. current_bits, RARCH_SLOWMOTION_KEY);
  32741. bool new_slowmotion_hold_button_state = BIT256_GET(
  32742. current_bits, RARCH_SLOWMOTION_HOLD_KEY);
  32743. if (new_slowmotion_button_state && !old_slowmotion_button_state)
  32744. p_rarch->runloop_slowmotion = !p_rarch->runloop_slowmotion;
  32745. else if (old_slowmotion_hold_button_state != new_slowmotion_hold_button_state)
  32746. p_rarch->runloop_slowmotion = new_slowmotion_hold_button_state;
  32747. if (p_rarch->runloop_slowmotion)
  32748. {
  32749. if (settings->uints.video_black_frame_insertion)
  32750. if (!p_rarch->runloop_idle)
  32751. video_driver_cached_frame();
  32752. #if defined(HAVE_GFX_WIDGETS)
  32753. if (!widgets_active)
  32754. #endif
  32755. {
  32756. #ifdef HAVE_REWIND
  32757. struct state_manager_rewind_state
  32758. *rewind_st = &p_rarch->rewind_st;
  32759. if (rewind_st->frame_is_reversed)
  32760. runloop_msg_queue_push(
  32761. msg_hash_to_str(MSG_SLOW_MOTION_REWIND), 1, 1, false, NULL,
  32762. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  32763. else
  32764. #endif
  32765. runloop_msg_queue_push(
  32766. msg_hash_to_str(MSG_SLOW_MOTION), 1, 1, false,
  32767. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  32768. }
  32769. }
  32770. old_slowmotion_button_state = new_slowmotion_button_state;
  32771. old_slowmotion_hold_button_state = new_slowmotion_hold_button_state;
  32772. }
  32773. }
  32774. /* Check movie record toggle */
  32775. HOTKEY_CHECK(RARCH_BSV_RECORD_TOGGLE, CMD_EVENT_BSV_RECORDING_TOGGLE, true, NULL);
  32776. /* Check shader prev/next */
  32777. HOTKEY_CHECK(RARCH_SHADER_NEXT, CMD_EVENT_SHADER_NEXT, true, NULL);
  32778. HOTKEY_CHECK(RARCH_SHADER_PREV, CMD_EVENT_SHADER_PREV, true, NULL);
  32779. /* Check if we have pressed any of the disk buttons */
  32780. HOTKEY_CHECK3(
  32781. RARCH_DISK_EJECT_TOGGLE, CMD_EVENT_DISK_EJECT_TOGGLE,
  32782. RARCH_DISK_NEXT, CMD_EVENT_DISK_NEXT,
  32783. RARCH_DISK_PREV, CMD_EVENT_DISK_PREV);
  32784. /* Check if we have pressed the reset button */
  32785. HOTKEY_CHECK(RARCH_RESET, CMD_EVENT_RESET, true, NULL);
  32786. /* Check cheats */
  32787. HOTKEY_CHECK3(
  32788. RARCH_CHEAT_INDEX_PLUS, CMD_EVENT_CHEAT_INDEX_PLUS,
  32789. RARCH_CHEAT_INDEX_MINUS, CMD_EVENT_CHEAT_INDEX_MINUS,
  32790. RARCH_CHEAT_TOGGLE, CMD_EVENT_CHEAT_TOGGLE);
  32791. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  32792. if (settings->bools.video_shader_watch_files)
  32793. {
  32794. static rarch_timer_t timer = {0};
  32795. static bool need_to_apply = false;
  32796. if (video_shader_check_for_changes())
  32797. {
  32798. need_to_apply = true;
  32799. if (!timer.timer_begin)
  32800. {
  32801. uint64_t current_usec = cpu_features_get_time_usec();
  32802. RARCH_TIMER_BEGIN_NEW_TIME_USEC(timer,
  32803. current_usec,
  32804. SHADER_FILE_WATCH_DELAY_MSEC * 1000);
  32805. timer.timer_begin = true;
  32806. timer.timer_end = false;
  32807. }
  32808. }
  32809. /* If a file is modified atomically (moved/renamed from a different file),
  32810. * we have no idea how long that might take.
  32811. * If we're trying to re-apply shaders immediately after changes are made
  32812. * to the original file(s), the filesystem might be in an in-between
  32813. * state where the new file hasn't been moved over yet and the original
  32814. * file was already deleted. This leaves us no choice but to wait an
  32815. * arbitrary amount of time and hope for the best.
  32816. */
  32817. if (need_to_apply)
  32818. {
  32819. RARCH_TIMER_TICK(timer, current_time);
  32820. if (!timer.timer_end && RARCH_TIMER_HAS_EXPIRED(timer))
  32821. {
  32822. RARCH_TIMER_END(timer);
  32823. need_to_apply = false;
  32824. command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL);
  32825. }
  32826. }
  32827. }
  32828. if ( settings->uints.video_shader_delay &&
  32829. !p_rarch->shader_delay_timer.timer_end)
  32830. {
  32831. if (!p_rarch->shader_delay_timer.timer_begin)
  32832. {
  32833. uint64_t current_usec = cpu_features_get_time_usec();
  32834. RARCH_TIMER_BEGIN_NEW_TIME_USEC(
  32835. p_rarch->shader_delay_timer,
  32836. current_usec,
  32837. settings->uints.video_shader_delay * 1000);
  32838. p_rarch->shader_delay_timer.timer_begin = true;
  32839. p_rarch->shader_delay_timer.timer_end = false;
  32840. }
  32841. else
  32842. {
  32843. RARCH_TIMER_TICK(p_rarch->shader_delay_timer, current_time);
  32844. if (RARCH_TIMER_HAS_EXPIRED(p_rarch->shader_delay_timer))
  32845. {
  32846. RARCH_TIMER_END(p_rarch->shader_delay_timer);
  32847. {
  32848. const char *preset = retroarch_get_shader_preset();
  32849. enum rarch_shader_type type = video_shader_parse_type(preset);
  32850. retroarch_apply_shader(type, preset, false);
  32851. }
  32852. }
  32853. }
  32854. }
  32855. #endif
  32856. return RUNLOOP_STATE_ITERATE;
  32857. }
  32858. /**
  32859. * runloop_iterate:
  32860. *
  32861. * Run Libretro core in RetroArch for one frame.
  32862. *
  32863. * Returns: 0 on success, 1 if we have to wait until
  32864. * button input in order to wake up the loop,
  32865. * -1 if we forcibly quit out of the RetroArch iteration loop.
  32866. **/
  32867. int runloop_iterate(void)
  32868. {
  32869. unsigned i;
  32870. struct rarch_state *p_rarch = &rarch_st;
  32871. settings_t *settings = p_rarch->configuration_settings;
  32872. float fastforward_ratio = settings->floats.fastforward_ratio;
  32873. unsigned video_frame_delay = settings->uints.video_frame_delay;
  32874. bool vrr_runloop_enable = settings->bools.vrr_runloop_enable;
  32875. unsigned max_users = p_rarch->input_driver_max_users;
  32876. retro_time_t current_time = cpu_features_get_time_usec();
  32877. bool core_paused = p_rarch->runloop_paused || (settings->bools.menu_pause_libretro && p_rarch->menu_driver_alive);
  32878. #ifdef HAVE_DISCORD
  32879. discord_state_t *discord_st = &p_rarch->discord_st;
  32880. if (discord_is_inited)
  32881. {
  32882. Discord_RunCallbacks();
  32883. Discord_UpdateConnection();
  32884. }
  32885. #endif
  32886. if (p_rarch->runloop_frame_time.callback)
  32887. {
  32888. /* Updates frame timing if frame timing callback is in use by the core.
  32889. * Limits frame time if fast forward ratio throttle is enabled. */
  32890. retro_usec_t runloop_last_frame_time = p_rarch->runloop_frame_time_last;
  32891. retro_time_t current = current_time;
  32892. bool is_locked_fps = (p_rarch->runloop_paused
  32893. || p_rarch->input_driver_nonblock_state)
  32894. | !!p_rarch->recording_data;
  32895. retro_time_t delta = (!runloop_last_frame_time || is_locked_fps)
  32896. ? p_rarch->runloop_frame_time.reference
  32897. : (current - runloop_last_frame_time);
  32898. if (is_locked_fps)
  32899. p_rarch->runloop_frame_time_last = 0;
  32900. else
  32901. {
  32902. float slowmotion_ratio =
  32903. settings->floats.slowmotion_ratio;
  32904. p_rarch->runloop_frame_time_last = current;
  32905. if (p_rarch->runloop_slowmotion)
  32906. delta /= slowmotion_ratio;
  32907. }
  32908. if (!core_paused)
  32909. p_rarch->runloop_frame_time.callback(delta);
  32910. }
  32911. /* Update audio buffer occupancy if buffer status
  32912. * callback is in use by the core */
  32913. if (p_rarch->runloop_audio_buffer_status.callback)
  32914. {
  32915. bool audio_buf_active = false;
  32916. unsigned audio_buf_occupancy = 0;
  32917. bool audio_buf_underrun = false;
  32918. if (!(p_rarch->runloop_paused ||
  32919. !p_rarch->audio_driver_active ||
  32920. !p_rarch->audio_driver_output_samples_buf) &&
  32921. p_rarch->current_audio->write_avail &&
  32922. p_rarch->audio_driver_context_audio_data &&
  32923. p_rarch->audio_driver_buffer_size)
  32924. {
  32925. size_t audio_buf_avail;
  32926. if ((audio_buf_avail = p_rarch->current_audio->write_avail(
  32927. p_rarch->audio_driver_context_audio_data)) > p_rarch->audio_driver_buffer_size)
  32928. audio_buf_avail = p_rarch->audio_driver_buffer_size;
  32929. audio_buf_occupancy = (unsigned)(100 - (audio_buf_avail * 100) /
  32930. p_rarch->audio_driver_buffer_size);
  32931. /* Elsewhere, we standardise on a 'low water mark'
  32932. * of 25% of the total audio buffer size - use
  32933. * the same metric here (can be made more sophisticated
  32934. * if required - i.e. determine buffer occupancy in
  32935. * terms of usec, and weigh this against the expected
  32936. * frame time) */
  32937. audio_buf_underrun = audio_buf_occupancy < 25;
  32938. audio_buf_active = true;
  32939. }
  32940. if (!core_paused)
  32941. p_rarch->runloop_audio_buffer_status.callback(
  32942. audio_buf_active, audio_buf_occupancy, audio_buf_underrun);
  32943. }
  32944. switch ((enum runloop_state)runloop_check_state(p_rarch,
  32945. settings, current_time))
  32946. {
  32947. case RUNLOOP_STATE_QUIT:
  32948. p_rarch->frame_limit_last_time = 0.0;
  32949. p_rarch->runloop_core_running = false;
  32950. command_event(CMD_EVENT_QUIT, NULL);
  32951. return -1;
  32952. case RUNLOOP_STATE_POLLED_AND_SLEEP:
  32953. #ifdef HAVE_NETWORKING
  32954. /* FIXME: This is an ugly way to tell Netplay this... */
  32955. netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL);
  32956. #endif
  32957. #if defined(HAVE_COCOATOUCH)
  32958. if (!p_rarch->main_ui_companion_is_on_foreground)
  32959. #endif
  32960. retro_sleep(10);
  32961. return 1;
  32962. case RUNLOOP_STATE_END:
  32963. #ifdef HAVE_NETWORKING
  32964. /* FIXME: This is an ugly way to tell Netplay this... */
  32965. if (settings->bools.menu_pause_libretro &&
  32966. netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)
  32967. )
  32968. netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL);
  32969. #endif
  32970. goto end;
  32971. case RUNLOOP_STATE_MENU_ITERATE:
  32972. #ifdef HAVE_NETWORKING
  32973. /* FIXME: This is an ugly way to tell Netplay this... */
  32974. netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL);
  32975. #endif
  32976. return 0;
  32977. case RUNLOOP_STATE_ITERATE:
  32978. p_rarch->runloop_core_running = true;
  32979. break;
  32980. }
  32981. #ifdef HAVE_THREADS
  32982. if (p_rarch->runloop_autosave)
  32983. autosave_lock();
  32984. #endif
  32985. #ifdef HAVE_BSV_MOVIE
  32986. /* Used for rewinding while playback/record. */
  32987. if (p_rarch->bsv_movie_state_handle)
  32988. p_rarch->bsv_movie_state_handle->frame_pos[p_rarch->bsv_movie_state_handle->frame_ptr]
  32989. = intfstream_tell(p_rarch->bsv_movie_state_handle->file);
  32990. #endif
  32991. if ( p_rarch->camera_cb.caps &&
  32992. p_rarch->camera_driver &&
  32993. p_rarch->camera_driver->poll &&
  32994. p_rarch->camera_data)
  32995. p_rarch->camera_driver->poll(p_rarch->camera_data,
  32996. p_rarch->camera_cb.frame_raw_framebuffer,
  32997. p_rarch->camera_cb.frame_opengl_texture);
  32998. /* Update binds for analog dpad modes. */
  32999. for (i = 0; i < max_users; i++)
  33000. {
  33001. enum analog_dpad_mode dpad_mode = (enum analog_dpad_mode)settings->uints.input_analog_dpad_mode[i];
  33002. if (dpad_mode != ANALOG_DPAD_NONE)
  33003. {
  33004. unsigned k;
  33005. struct retro_keybind *general_binds = input_config_binds[i];
  33006. struct retro_keybind *auto_binds = input_autoconf_binds[i];
  33007. unsigned x_plus = RARCH_ANALOG_RIGHT_X_PLUS;
  33008. unsigned y_plus = RARCH_ANALOG_RIGHT_Y_PLUS;
  33009. unsigned x_minus = RARCH_ANALOG_RIGHT_X_MINUS;
  33010. unsigned y_minus = RARCH_ANALOG_RIGHT_Y_MINUS;
  33011. /* Push analog to D-Pad mappings to binds. */
  33012. if ((dpad_mode) == ANALOG_DPAD_LSTICK)
  33013. {
  33014. x_plus = RARCH_ANALOG_LEFT_X_PLUS;
  33015. y_plus = RARCH_ANALOG_LEFT_Y_PLUS;
  33016. x_minus = RARCH_ANALOG_LEFT_X_MINUS;
  33017. y_minus = RARCH_ANALOG_LEFT_Y_MINUS;
  33018. }
  33019. for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
  33020. {
  33021. (auto_binds)[k].orig_joyaxis = (auto_binds)[k].joyaxis;
  33022. (general_binds)[k].orig_joyaxis = (general_binds)[k].joyaxis;
  33023. }
  33024. if (!INHERIT_JOYAXIS(auto_binds))
  33025. {
  33026. unsigned j = x_plus + 3;
  33027. /* Inherit joyaxis from analogs. */
  33028. for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
  33029. (auto_binds)[k].joyaxis = (auto_binds)[j--].joyaxis;
  33030. }
  33031. if (!INHERIT_JOYAXIS(general_binds))
  33032. {
  33033. unsigned j = x_plus + 3;
  33034. /* Inherit joyaxis from analogs. */
  33035. for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
  33036. (general_binds)[k].joyaxis = (general_binds)[j--].joyaxis;
  33037. }
  33038. }
  33039. }
  33040. if ((video_frame_delay > 0) && !p_rarch->input_driver_nonblock_state)
  33041. retro_sleep(video_frame_delay);
  33042. {
  33043. #ifdef HAVE_RUNAHEAD
  33044. unsigned run_ahead_num_frames = settings->uints.run_ahead_frames;
  33045. /* Run Ahead Feature replaces the call to core_run in this loop */
  33046. bool want_runahead = settings->bools.run_ahead_enabled && run_ahead_num_frames > 0;
  33047. #ifdef HAVE_NETWORKING
  33048. want_runahead = want_runahead && !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL);
  33049. #endif
  33050. if (want_runahead)
  33051. do_runahead(
  33052. p_rarch,
  33053. run_ahead_num_frames,
  33054. settings->bools.run_ahead_secondary_instance);
  33055. else
  33056. #endif
  33057. core_run();
  33058. }
  33059. /* Increment runtime tick counter after each call to
  33060. * core_run() or run_ahead() */
  33061. p_rarch->libretro_core_runtime_usec += rarch_core_runtime_tick(
  33062. p_rarch, current_time);
  33063. #ifdef HAVE_CHEEVOS
  33064. if (settings->bools.cheevos_enable)
  33065. rcheevos_test();
  33066. #endif
  33067. #ifdef HAVE_CHEATS
  33068. cheat_manager_apply_retro_cheats();
  33069. #endif
  33070. #ifdef HAVE_DISCORD
  33071. if (discord_is_inited && discord_st->ready)
  33072. discord_update(DISCORD_PRESENCE_GAME);
  33073. #endif
  33074. for (i = 0; i < max_users; i++)
  33075. {
  33076. unsigned j;
  33077. enum analog_dpad_mode dpad_mode = (enum analog_dpad_mode)settings->uints.input_analog_dpad_mode[i];
  33078. /* Restores analog D-pad binds temporarily overridden. */
  33079. if (dpad_mode != ANALOG_DPAD_NONE)
  33080. {
  33081. struct retro_keybind *general_binds = input_config_binds[i];
  33082. struct retro_keybind *auto_binds = input_autoconf_binds[i];
  33083. for (j = RETRO_DEVICE_ID_JOYPAD_UP; j <= RETRO_DEVICE_ID_JOYPAD_RIGHT; j++)
  33084. {
  33085. (auto_binds)[j].joyaxis = (auto_binds)[j].orig_joyaxis;
  33086. (general_binds)[j].joyaxis = (general_binds)[j].orig_joyaxis;
  33087. }
  33088. }
  33089. }
  33090. #ifdef HAVE_BSV_MOVIE
  33091. if (p_rarch->bsv_movie_state_handle)
  33092. {
  33093. p_rarch->bsv_movie_state_handle->frame_ptr =
  33094. (p_rarch->bsv_movie_state_handle->frame_ptr + 1)
  33095. & p_rarch->bsv_movie_state_handle->frame_mask;
  33096. p_rarch->bsv_movie_state_handle->first_rewind =
  33097. !p_rarch->bsv_movie_state_handle->did_rewind;
  33098. p_rarch->bsv_movie_state_handle->did_rewind = false;
  33099. }
  33100. #endif
  33101. #ifdef HAVE_THREADS
  33102. if (p_rarch->runloop_autosave)
  33103. autosave_unlock();
  33104. #endif
  33105. /* Condition for max speed x0.0 when vrr_runloop is off to skip that part */
  33106. if (!(fastforward_ratio || vrr_runloop_enable))
  33107. return 0;
  33108. end:
  33109. if (vrr_runloop_enable)
  33110. {
  33111. struct retro_system_av_info *av_info = &p_rarch->video_driver_av_info;
  33112. bool audio_sync = settings->bools.audio_sync;
  33113. /* Sync on video only, block audio later. */
  33114. if (p_rarch->fastforward_after_frames && audio_sync)
  33115. {
  33116. if (p_rarch->fastforward_after_frames == 1)
  33117. {
  33118. /* Nonblocking audio */
  33119. if (p_rarch->audio_driver_active &&
  33120. p_rarch->audio_driver_context_audio_data)
  33121. p_rarch->current_audio->set_nonblock_state(
  33122. p_rarch->audio_driver_context_audio_data, true);
  33123. p_rarch->audio_driver_chunk_size =
  33124. p_rarch->audio_driver_chunk_nonblock_size;
  33125. }
  33126. p_rarch->fastforward_after_frames++;
  33127. if (p_rarch->fastforward_after_frames == 6)
  33128. {
  33129. /* Blocking audio */
  33130. if (p_rarch->audio_driver_active &&
  33131. p_rarch->audio_driver_context_audio_data)
  33132. p_rarch->current_audio->set_nonblock_state(
  33133. p_rarch->audio_driver_context_audio_data,
  33134. audio_sync ? false : true);
  33135. p_rarch->audio_driver_chunk_size =
  33136. p_rarch->audio_driver_chunk_block_size;
  33137. p_rarch->fastforward_after_frames = 0;
  33138. }
  33139. }
  33140. /* Fast Forward for max speed x0.0 */
  33141. if (!fastforward_ratio && p_rarch->runloop_fastmotion)
  33142. return 0;
  33143. p_rarch->frame_limit_minimum_time =
  33144. (retro_time_t)roundf(1000000.0f / (av_info->timing.fps *
  33145. (p_rarch->runloop_fastmotion
  33146. ? fastforward_ratio : 1.0f)));
  33147. }
  33148. {
  33149. retro_time_t to_sleep_ms = (
  33150. (p_rarch->frame_limit_last_time + p_rarch->frame_limit_minimum_time)
  33151. - cpu_features_get_time_usec()) / 1000;
  33152. if (to_sleep_ms > 0)
  33153. {
  33154. unsigned sleep_ms = (unsigned)to_sleep_ms;
  33155. /* Combat jitter a bit. */
  33156. p_rarch->frame_limit_last_time += p_rarch->frame_limit_minimum_time;
  33157. if (sleep_ms > 0)
  33158. #if defined(HAVE_COCOATOUCH)
  33159. if (!p_rarch->main_ui_companion_is_on_foreground)
  33160. #endif
  33161. retro_sleep(sleep_ms);
  33162. return 1;
  33163. }
  33164. }
  33165. p_rarch->frame_limit_last_time = cpu_features_get_time_usec();
  33166. return 0;
  33167. }
  33168. rarch_system_info_t *runloop_get_system_info(void)
  33169. {
  33170. struct rarch_state *p_rarch = &rarch_st;
  33171. return &p_rarch->runloop_system;
  33172. }
  33173. struct retro_system_info *runloop_get_libretro_system_info(void)
  33174. {
  33175. struct rarch_state *p_rarch = &rarch_st;
  33176. return &p_rarch->runloop_system.info;
  33177. }
  33178. void retroarch_force_video_driver_fallback(const char *driver)
  33179. {
  33180. struct rarch_state *p_rarch = &rarch_st;
  33181. settings_t *settings = p_rarch->configuration_settings;
  33182. ui_msg_window_t *msg_window = NULL;
  33183. configuration_set_string(settings,
  33184. settings->arrays.video_driver,
  33185. driver);
  33186. command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
  33187. #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) && !defined(WINAPI_FAMILY)
  33188. /* UI companion driver is not inited yet, just call into it directly */
  33189. msg_window = &ui_msg_window_win32;
  33190. #endif
  33191. if (msg_window)
  33192. {
  33193. char text[PATH_MAX_LENGTH];
  33194. ui_msg_window_state window_state;
  33195. char *title = strdup(msg_hash_to_str(MSG_ERROR));
  33196. text[0] = '\0';
  33197. snprintf(text, sizeof(text),
  33198. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER_FALLBACK),
  33199. driver);
  33200. window_state.buttons = UI_MSG_WINDOW_OK;
  33201. window_state.text = strdup(text);
  33202. window_state.title = title;
  33203. window_state.window = NULL;
  33204. msg_window->error(&window_state);
  33205. free(title);
  33206. }
  33207. exit(1);
  33208. }
  33209. enum retro_language rarch_get_language_from_iso(const char *iso639)
  33210. {
  33211. unsigned i;
  33212. enum retro_language lang = RETRO_LANGUAGE_ENGLISH;
  33213. struct lang_pair
  33214. {
  33215. const char *iso639;
  33216. enum retro_language lang;
  33217. };
  33218. const struct lang_pair pairs[] =
  33219. {
  33220. {"en", RETRO_LANGUAGE_ENGLISH},
  33221. {"ja", RETRO_LANGUAGE_JAPANESE},
  33222. {"fr", RETRO_LANGUAGE_FRENCH},
  33223. {"es", RETRO_LANGUAGE_SPANISH},
  33224. {"de", RETRO_LANGUAGE_GERMAN},
  33225. {"it", RETRO_LANGUAGE_ITALIAN},
  33226. {"nl", RETRO_LANGUAGE_DUTCH},
  33227. {"pt_BR", RETRO_LANGUAGE_PORTUGUESE_BRAZIL},
  33228. {"pt_PT", RETRO_LANGUAGE_PORTUGUESE_PORTUGAL},
  33229. {"pt", RETRO_LANGUAGE_PORTUGUESE_PORTUGAL},
  33230. {"ru", RETRO_LANGUAGE_RUSSIAN},
  33231. {"ko", RETRO_LANGUAGE_KOREAN},
  33232. {"zh_CN", RETRO_LANGUAGE_CHINESE_SIMPLIFIED},
  33233. {"zh_SG", RETRO_LANGUAGE_CHINESE_SIMPLIFIED},
  33234. {"zh_HK", RETRO_LANGUAGE_CHINESE_TRADITIONAL},
  33235. {"zh_TW", RETRO_LANGUAGE_CHINESE_TRADITIONAL},
  33236. {"zh", RETRO_LANGUAGE_CHINESE_SIMPLIFIED},
  33237. {"eo", RETRO_LANGUAGE_ESPERANTO},
  33238. {"pl", RETRO_LANGUAGE_POLISH},
  33239. {"vi", RETRO_LANGUAGE_VIETNAMESE},
  33240. {"ar", RETRO_LANGUAGE_ARABIC},
  33241. {"el", RETRO_LANGUAGE_GREEK},
  33242. };
  33243. if (string_is_empty(iso639))
  33244. return lang;
  33245. for (i = 0; i < ARRAY_SIZE(pairs); i++)
  33246. {
  33247. if (strcasestr(iso639, pairs[i].iso639))
  33248. {
  33249. lang = pairs[i].lang;
  33250. break;
  33251. }
  33252. }
  33253. return lang;
  33254. }
  33255. void rarch_favorites_init(void)
  33256. {
  33257. struct rarch_state *p_rarch = &rarch_st;
  33258. settings_t *settings = p_rarch->configuration_settings;
  33259. int content_favorites_size = settings ? settings->ints.content_favorites_size : 0;
  33260. const char *path_content_favorites = settings ? settings->paths.path_content_favorites : NULL;
  33261. bool playlist_sort_alphabetical = settings ? settings->bools.playlist_sort_alphabetical : false;
  33262. playlist_config_t playlist_config;
  33263. enum playlist_sort_mode current_sort_mode;
  33264. playlist_config.capacity = COLLECTION_SIZE;
  33265. playlist_config.old_format = settings ? settings->bools.playlist_use_old_format : false;
  33266. playlist_config.compress = settings ? settings->bools.playlist_compression : false;
  33267. playlist_config.fuzzy_archive_match = settings ? settings->bools.playlist_fuzzy_archive_match : false;
  33268. playlist_config_set_base_content_directory(&playlist_config, NULL);
  33269. if (!settings)
  33270. return;
  33271. if (content_favorites_size >= 0)
  33272. playlist_config.capacity = (size_t)content_favorites_size;
  33273. rarch_favorites_deinit();
  33274. RARCH_LOG("[Playlist]: %s: [%s].\n",
  33275. msg_hash_to_str(MSG_LOADING_FAVORITES_FILE),
  33276. path_content_favorites);
  33277. playlist_config_set_path(&playlist_config, path_content_favorites);
  33278. g_defaults.content_favorites = playlist_init(&playlist_config);
  33279. /* Get current per-playlist sort mode */
  33280. current_sort_mode = playlist_get_sort_mode(g_defaults.content_favorites);
  33281. /* Ensure that playlist is sorted alphabetically,
  33282. * if required */
  33283. if ((playlist_sort_alphabetical && (current_sort_mode == PLAYLIST_SORT_MODE_DEFAULT)) ||
  33284. (current_sort_mode == PLAYLIST_SORT_MODE_ALPHABETICAL))
  33285. playlist_qsort(g_defaults.content_favorites);
  33286. }
  33287. void rarch_favorites_deinit(void)
  33288. {
  33289. if (!g_defaults.content_favorites)
  33290. return;
  33291. playlist_write_file(g_defaults.content_favorites);
  33292. playlist_free(g_defaults.content_favorites);
  33293. g_defaults.content_favorites = NULL;
  33294. }
  33295. /* Libretro core loader */
  33296. static void retro_run_null(void) { }
  33297. static void retro_frame_null(const void *data, unsigned width,
  33298. unsigned height, size_t pitch) { }
  33299. static void retro_input_poll_null(void) { }
  33300. static int16_t core_input_state_poll_late(unsigned port,
  33301. unsigned device, unsigned idx, unsigned id)
  33302. {
  33303. struct rarch_state *p_rarch = &rarch_st;
  33304. if (!p_rarch->current_core.input_polled)
  33305. input_driver_poll();
  33306. p_rarch->current_core.input_polled = true;
  33307. return input_state(port, device, idx, id);
  33308. }
  33309. static retro_input_state_t core_input_state_poll_return_cb(void)
  33310. {
  33311. struct rarch_state *p_rarch = &rarch_st;
  33312. const enum poll_type_override_t
  33313. core_poll_type_override = p_rarch->core_poll_type_override;
  33314. unsigned new_poll_type = (core_poll_type_override > POLL_TYPE_OVERRIDE_DONTCARE)
  33315. ? (core_poll_type_override - 1)
  33316. : p_rarch->current_core.poll_type;
  33317. if (new_poll_type == POLL_TYPE_LATE)
  33318. return core_input_state_poll_late;
  33319. return input_state;
  33320. }
  33321. static void core_input_state_poll_maybe(void)
  33322. {
  33323. struct rarch_state *p_rarch = &rarch_st;
  33324. const enum poll_type_override_t
  33325. core_poll_type_override = p_rarch->core_poll_type_override;
  33326. unsigned new_poll_type = (core_poll_type_override > POLL_TYPE_OVERRIDE_DONTCARE)
  33327. ? (core_poll_type_override - 1)
  33328. : p_rarch->current_core.poll_type;
  33329. if (new_poll_type == POLL_TYPE_NORMAL)
  33330. input_driver_poll();
  33331. }
  33332. /**
  33333. * core_init_libretro_cbs:
  33334. * @data : pointer to retro_callbacks object
  33335. *
  33336. * Initializes libretro callbacks, and binds the libretro callbacks
  33337. * to default callback functions.
  33338. **/
  33339. static bool core_init_libretro_cbs(
  33340. struct rarch_state *p_rarch,
  33341. struct retro_callbacks *cbs)
  33342. {
  33343. retro_input_state_t state_cb = core_input_state_poll_return_cb();
  33344. p_rarch->current_core.retro_set_video_refresh(video_driver_frame);
  33345. p_rarch->current_core.retro_set_audio_sample(audio_driver_sample);
  33346. p_rarch->current_core.retro_set_audio_sample_batch(audio_driver_sample_batch);
  33347. p_rarch->current_core.retro_set_input_state(state_cb);
  33348. p_rarch->current_core.retro_set_input_poll(core_input_state_poll_maybe);
  33349. core_set_default_callbacks(cbs);
  33350. #ifdef HAVE_NETWORKING
  33351. if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
  33352. return true;
  33353. core_set_netplay_callbacks();
  33354. #endif
  33355. return true;
  33356. }
  33357. /**
  33358. * core_set_default_callbacks:
  33359. * @data : pointer to retro_callbacks object
  33360. *
  33361. * Binds the libretro callbacks to default callback functions.
  33362. **/
  33363. static bool core_set_default_callbacks(struct retro_callbacks *cbs)
  33364. {
  33365. retro_input_state_t state_cb = core_input_state_poll_return_cb();
  33366. cbs->frame_cb = video_driver_frame;
  33367. cbs->sample_cb = audio_driver_sample;
  33368. cbs->sample_batch_cb = audio_driver_sample_batch;
  33369. cbs->state_cb = state_cb;
  33370. cbs->poll_cb = input_driver_poll;
  33371. return true;
  33372. }
  33373. #ifdef HAVE_REWIND
  33374. /**
  33375. * core_set_rewind_callbacks:
  33376. *
  33377. * Sets the audio sampling callbacks based on whether or not
  33378. * rewinding is currently activated.
  33379. **/
  33380. bool core_set_rewind_callbacks(void)
  33381. {
  33382. struct rarch_state *p_rarch = &rarch_st;
  33383. struct state_manager_rewind_state
  33384. *rewind_st = &p_rarch->rewind_st;
  33385. if (rewind_st->frame_is_reversed)
  33386. {
  33387. p_rarch->current_core.retro_set_audio_sample(audio_driver_sample_rewind);
  33388. p_rarch->current_core.retro_set_audio_sample_batch(audio_driver_sample_batch_rewind);
  33389. }
  33390. else
  33391. {
  33392. p_rarch->current_core.retro_set_audio_sample(audio_driver_sample);
  33393. p_rarch->current_core.retro_set_audio_sample_batch(audio_driver_sample_batch);
  33394. }
  33395. return true;
  33396. }
  33397. #endif
  33398. #ifdef HAVE_NETWORKING
  33399. /**
  33400. * core_set_netplay_callbacks:
  33401. *
  33402. * Set the I/O callbacks to use netplay's interceding callback system. Should
  33403. * only be called while initializing netplay.
  33404. **/
  33405. bool core_set_netplay_callbacks(void)
  33406. {
  33407. struct rarch_state *p_rarch = &rarch_st;
  33408. /* Force normal poll type for netplay. */
  33409. p_rarch->current_core.poll_type = POLL_TYPE_NORMAL;
  33410. /* And use netplay's interceding callbacks */
  33411. p_rarch->current_core.retro_set_video_refresh(video_frame_net);
  33412. p_rarch->current_core.retro_set_audio_sample(audio_sample_net);
  33413. p_rarch->current_core.retro_set_audio_sample_batch(audio_sample_batch_net);
  33414. p_rarch->current_core.retro_set_input_state(input_state_net);
  33415. return true;
  33416. }
  33417. /**
  33418. * core_unset_netplay_callbacks
  33419. *
  33420. * Unset the I/O callbacks from having used netplay's interceding callback
  33421. * system. Should only be called while uninitializing netplay.
  33422. */
  33423. bool core_unset_netplay_callbacks(void)
  33424. {
  33425. struct retro_callbacks cbs;
  33426. struct rarch_state *p_rarch = &rarch_st;
  33427. if (!core_set_default_callbacks(&cbs))
  33428. return false;
  33429. p_rarch->current_core.retro_set_video_refresh(cbs.frame_cb);
  33430. p_rarch->current_core.retro_set_audio_sample(cbs.sample_cb);
  33431. p_rarch->current_core.retro_set_audio_sample_batch(cbs.sample_batch_cb);
  33432. p_rarch->current_core.retro_set_input_state(cbs.state_cb);
  33433. return true;
  33434. }
  33435. #endif
  33436. bool core_set_cheat(retro_ctx_cheat_info_t *info)
  33437. {
  33438. struct rarch_state *p_rarch = &rarch_st;
  33439. p_rarch->current_core.retro_cheat_set(info->index, info->enabled, info->code);
  33440. return true;
  33441. }
  33442. bool core_reset_cheat(void)
  33443. {
  33444. struct rarch_state *p_rarch = &rarch_st;
  33445. p_rarch->current_core.retro_cheat_reset();
  33446. return true;
  33447. }
  33448. bool core_set_poll_type(unsigned type)
  33449. {
  33450. struct rarch_state *p_rarch = &rarch_st;
  33451. p_rarch->current_core.poll_type = type;
  33452. return true;
  33453. }
  33454. bool core_set_controller_port_device(retro_ctx_controller_info_t *pad)
  33455. {
  33456. struct rarch_state *p_rarch = &rarch_st;
  33457. if (!pad)
  33458. return false;
  33459. #ifdef HAVE_RUNAHEAD
  33460. remember_controller_port_device(p_rarch, pad->port, pad->device);
  33461. #endif
  33462. p_rarch->current_core.retro_set_controller_port_device(pad->port, pad->device);
  33463. return true;
  33464. }
  33465. bool core_get_memory(retro_ctx_memory_info_t *info)
  33466. {
  33467. struct rarch_state *p_rarch = &rarch_st;
  33468. if (!info)
  33469. return false;
  33470. info->size = p_rarch->current_core.retro_get_memory_size(info->id);
  33471. info->data = p_rarch->current_core.retro_get_memory_data(info->id);
  33472. return true;
  33473. }
  33474. bool core_load_game(retro_ctx_load_content_info_t *load_info)
  33475. {
  33476. bool contentless = false;
  33477. bool is_inited = false;
  33478. bool game_loaded = false;
  33479. struct rarch_state *p_rarch = &rarch_st;
  33480. video_driver_set_cached_frame_ptr(NULL);
  33481. #ifdef HAVE_RUNAHEAD
  33482. set_load_content_info(p_rarch, load_info);
  33483. clear_controller_port_map(p_rarch);
  33484. #endif
  33485. content_get_status(&contentless, &is_inited);
  33486. set_save_state_in_background(false);
  33487. if (load_info && load_info->special)
  33488. game_loaded = p_rarch->current_core.retro_load_game_special(
  33489. load_info->special->id, load_info->info, load_info->content->size);
  33490. else if (load_info && !string_is_empty(load_info->content->elems[0].data))
  33491. game_loaded = p_rarch->current_core.retro_load_game(load_info->info);
  33492. else if (contentless)
  33493. game_loaded = p_rarch->current_core.retro_load_game(NULL);
  33494. p_rarch->current_core.game_loaded = game_loaded;
  33495. return game_loaded;
  33496. }
  33497. bool core_get_system_info(struct retro_system_info *system)
  33498. {
  33499. struct rarch_state *p_rarch = &rarch_st;
  33500. if (!system)
  33501. return false;
  33502. p_rarch->current_core.retro_get_system_info(system);
  33503. return true;
  33504. }
  33505. bool core_unserialize(retro_ctx_serialize_info_t *info)
  33506. {
  33507. struct rarch_state *p_rarch = &rarch_st;
  33508. if (!info || !p_rarch->current_core.retro_unserialize(info->data_const, info->size))
  33509. return false;
  33510. #if HAVE_NETWORKING
  33511. netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, info);
  33512. #endif
  33513. return true;
  33514. }
  33515. bool core_serialize(retro_ctx_serialize_info_t *info)
  33516. {
  33517. struct rarch_state *p_rarch = &rarch_st;
  33518. if (!info || !p_rarch->current_core.retro_serialize(info->data, info->size))
  33519. return false;
  33520. return true;
  33521. }
  33522. bool core_serialize_size(retro_ctx_size_info_t *info)
  33523. {
  33524. struct rarch_state *p_rarch = &rarch_st;
  33525. if (!info)
  33526. return false;
  33527. info->size = p_rarch->current_core.retro_serialize_size();
  33528. return true;
  33529. }
  33530. uint64_t core_serialization_quirks(void)
  33531. {
  33532. struct rarch_state *p_rarch = &rarch_st;
  33533. return p_rarch->current_core.serialization_quirks_v;
  33534. }
  33535. bool core_reset(void)
  33536. {
  33537. struct rarch_state *p_rarch = &rarch_st;
  33538. video_driver_set_cached_frame_ptr(NULL);
  33539. p_rarch->current_core.retro_reset();
  33540. return true;
  33541. }
  33542. static bool core_unload_game(struct rarch_state *p_rarch)
  33543. {
  33544. video_driver_free_hw_context(p_rarch);
  33545. video_driver_set_cached_frame_ptr(NULL);
  33546. if (p_rarch->current_core.game_loaded)
  33547. {
  33548. RARCH_LOG("[Core]: Unloading game..\n");
  33549. p_rarch->current_core.retro_unload_game();
  33550. p_rarch->core_poll_type_override = POLL_TYPE_OVERRIDE_DONTCARE;
  33551. p_rarch->current_core.game_loaded = false;
  33552. }
  33553. audio_driver_stop(p_rarch);
  33554. return true;
  33555. }
  33556. bool core_run(void)
  33557. {
  33558. struct rarch_state
  33559. *p_rarch = &rarch_st;
  33560. struct retro_core_t *
  33561. current_core = &p_rarch->current_core;
  33562. const enum poll_type_override_t
  33563. core_poll_type_override = p_rarch->core_poll_type_override;
  33564. unsigned new_poll_type = (core_poll_type_override != POLL_TYPE_OVERRIDE_DONTCARE)
  33565. ? (core_poll_type_override - 1)
  33566. : current_core->poll_type;
  33567. bool early_polling = new_poll_type == POLL_TYPE_EARLY;
  33568. bool late_polling = new_poll_type == POLL_TYPE_LATE;
  33569. #ifdef HAVE_NETWORKING
  33570. bool netplay_preframe = netplay_driver_ctl(
  33571. RARCH_NETPLAY_CTL_PRE_FRAME, NULL);
  33572. if (!netplay_preframe)
  33573. {
  33574. /* Paused due to netplay. We must poll and display something so that a
  33575. * netplay peer pausing doesn't just hang. */
  33576. input_driver_poll();
  33577. video_driver_cached_frame();
  33578. return true;
  33579. }
  33580. #endif
  33581. if (early_polling)
  33582. input_driver_poll();
  33583. else if (late_polling)
  33584. current_core->input_polled = false;
  33585. current_core->retro_run();
  33586. if (late_polling && !current_core->input_polled)
  33587. input_driver_poll();
  33588. #ifdef HAVE_NETWORKING
  33589. netplay_driver_ctl(RARCH_NETPLAY_CTL_POST_FRAME, NULL);
  33590. #endif
  33591. return true;
  33592. }
  33593. static bool core_verify_api_version(struct rarch_state *p_rarch)
  33594. {
  33595. unsigned api_version = p_rarch->current_core.retro_api_version();
  33596. RARCH_LOG("%s: %u\n%s %s: %u\n",
  33597. msg_hash_to_str(MSG_VERSION_OF_LIBRETRO_API),
  33598. api_version,
  33599. FILE_PATH_LOG_INFO,
  33600. msg_hash_to_str(MSG_COMPILED_AGAINST_API),
  33601. RETRO_API_VERSION
  33602. );
  33603. if (api_version != RETRO_API_VERSION)
  33604. {
  33605. RARCH_WARN("%s\n", msg_hash_to_str(MSG_LIBRETRO_ABI_BREAK));
  33606. return false;
  33607. }
  33608. return true;
  33609. }
  33610. static bool core_load(
  33611. struct rarch_state *p_rarch,
  33612. unsigned poll_type_behavior)
  33613. {
  33614. p_rarch->current_core.poll_type = poll_type_behavior;
  33615. if (!core_verify_api_version(p_rarch))
  33616. return false;
  33617. if (!core_init_libretro_cbs(p_rarch,
  33618. &p_rarch->retro_ctx))
  33619. return false;
  33620. p_rarch->current_core.retro_get_system_av_info(
  33621. &p_rarch->video_driver_av_info);
  33622. return true;
  33623. }
  33624. bool core_has_set_input_descriptor(void)
  33625. {
  33626. struct rarch_state *p_rarch = &rarch_st;
  33627. return p_rarch->current_core.has_set_input_descriptors;
  33628. }
  33629. #if defined(HAVE_RUNAHEAD)
  33630. static void core_free_retro_game_info(struct retro_game_info *dest)
  33631. {
  33632. if (!dest)
  33633. return;
  33634. if (dest->path)
  33635. free((void*)dest->path);
  33636. if (dest->data)
  33637. free((void*)dest->data);
  33638. if (dest->meta)
  33639. free((void*)dest->meta);
  33640. dest->path = NULL;
  33641. dest->data = NULL;
  33642. dest->meta = NULL;
  33643. }
  33644. #endif
  33645. unsigned int retroarch_get_rotation(void)
  33646. {
  33647. struct rarch_state *p_rarch = &rarch_st;
  33648. settings_t *settings = p_rarch->configuration_settings;
  33649. unsigned video_rotation = settings->uints.video_rotation;
  33650. return video_rotation + p_rarch->runloop_system.rotation;
  33651. }
  33652. #ifdef HAVE_ACCESSIBILITY
  33653. static bool accessibility_speak_priority(
  33654. struct rarch_state *p_rarch,
  33655. const char* speak_text, int priority)
  33656. {
  33657. settings_t *settings = p_rarch->configuration_settings;
  33658. RARCH_LOG("Spoke: %s\n", speak_text);
  33659. if (is_accessibility_enabled(p_rarch))
  33660. {
  33661. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  33662. if (frontend && frontend->accessibility_speak)
  33663. {
  33664. int speed = settings->uints.accessibility_narrator_speech_speed;
  33665. return frontend->accessibility_speak(speed, speak_text,
  33666. priority);
  33667. }
  33668. RARCH_LOG("Platform not supported for accessibility.\n");
  33669. /* The following method is a fallback for other platforms to use the
  33670. AI Service url to do the TTS. However, since the playback is done
  33671. via the audio mixer, which only processes the audio while the
  33672. core is running, this playback method won't work. When the audio
  33673. mixer can handle playing streams while the core is paused, then
  33674. we can use this. */
  33675. #if 0
  33676. #if defined(HAVE_NETWORKING)
  33677. return accessibility_speak_ai_service(speak_text, voice, priority);
  33678. #endif
  33679. #endif
  33680. }
  33681. return true;
  33682. }
  33683. #ifdef HAVE_TRANSLATE
  33684. static bool is_narrator_running(struct rarch_state *p_rarch)
  33685. {
  33686. if (is_accessibility_enabled(p_rarch))
  33687. {
  33688. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  33689. if (frontend && frontend->is_narrator_running)
  33690. return frontend->is_narrator_running();
  33691. }
  33692. return true;
  33693. }
  33694. #endif
  33695. #endif
  33696. /* Creates folder and core options stub file for subsequent runs */
  33697. bool core_options_create_override(bool game_specific)
  33698. {
  33699. char options_path[PATH_MAX_LENGTH];
  33700. config_file_t *conf = NULL;
  33701. struct rarch_state *p_rarch = &rarch_st;
  33702. options_path[0] = '\0';
  33703. /* Sanity check - cannot create a folder-specific
  33704. * override if a game-specific override is
  33705. * already active */
  33706. if (!game_specific && p_rarch->runloop_game_options_active)
  33707. goto error;
  33708. /* Get options file path (either game-specific or folder-specific) */
  33709. if (game_specific)
  33710. {
  33711. if (!retroarch_validate_game_options(options_path,
  33712. sizeof(options_path), true))
  33713. goto error;
  33714. }
  33715. else
  33716. if (!retroarch_validate_folder_options(options_path,
  33717. sizeof(options_path), true))
  33718. goto error;
  33719. /* Open config file */
  33720. if (!(conf = config_file_new_from_path_to_string(options_path)))
  33721. if (!(conf = config_file_new_alloc()))
  33722. goto error;
  33723. /* Write config file */
  33724. core_option_manager_flush(conf, p_rarch->runloop_core_options);
  33725. if (config_file_write(conf, options_path, true))
  33726. {
  33727. runloop_msg_queue_push(
  33728. msg_hash_to_str(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY),
  33729. 1, 100, true,
  33730. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  33731. path_set(RARCH_PATH_CORE_OPTIONS, options_path);
  33732. p_rarch->runloop_game_options_active = game_specific;
  33733. p_rarch->runloop_folder_options_active = !game_specific;
  33734. }
  33735. else
  33736. goto error;
  33737. config_file_free(conf);
  33738. return true;
  33739. error:
  33740. runloop_msg_queue_push(
  33741. msg_hash_to_str(MSG_ERROR_SAVING_CORE_OPTIONS_FILE),
  33742. 1, 100, true,
  33743. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  33744. if (conf)
  33745. config_file_free(conf);
  33746. return false;
  33747. }
  33748. bool core_options_remove_override(bool game_specific)
  33749. {
  33750. char new_options_path[PATH_MAX_LENGTH];
  33751. struct rarch_state *p_rarch = &rarch_st;
  33752. core_option_manager_t *coreopts = p_rarch->runloop_core_options;
  33753. settings_t *settings = p_rarch->configuration_settings;
  33754. bool per_core_options = !settings->bools.global_core_options;
  33755. const char *path_core_options = settings->paths.path_core_options;
  33756. const char *current_options_path = NULL;
  33757. config_file_t *conf = NULL;
  33758. bool folder_options_active = false;
  33759. new_options_path[0] = '\0';
  33760. /* Sanity check 1 - if there are no core options
  33761. * or no overrides are active, there is nothing to do */
  33762. if (!coreopts ||
  33763. (!p_rarch->runloop_game_options_active &&
  33764. !p_rarch->runloop_folder_options_active))
  33765. return true;
  33766. /* Sanity check 2 - can only remove an override
  33767. * if the specified type is currently active */
  33768. if (game_specific && !p_rarch->runloop_game_options_active)
  33769. goto error;
  33770. /* Get current options file path */
  33771. current_options_path = path_get(RARCH_PATH_CORE_OPTIONS);
  33772. if (string_is_empty(current_options_path))
  33773. goto error;
  33774. /* Remove current options file, if required */
  33775. if (path_is_valid(current_options_path))
  33776. filestream_delete(current_options_path);
  33777. /* Reload any existing 'parent' options file
  33778. * > If we have removed a game-specific config,
  33779. * check whether a folder-specific config
  33780. * exists */
  33781. if (game_specific &&
  33782. retroarch_validate_folder_options(new_options_path,
  33783. sizeof(new_options_path), false) &&
  33784. path_is_valid(new_options_path))
  33785. folder_options_active = true;
  33786. /* > If a folder-specific config does not exist,
  33787. * or we removed it, check whether we have a
  33788. * top-level config file */
  33789. if (!folder_options_active)
  33790. {
  33791. /* Try core-specific options, if enabled */
  33792. if (per_core_options)
  33793. {
  33794. const char *core_name = p_rarch->runloop_system.info.library_name;
  33795. per_core_options = retroarch_validate_per_core_options(
  33796. new_options_path, sizeof(new_options_path), true,
  33797. core_name, core_name);
  33798. }
  33799. /* ...otherwise use global options */
  33800. if (!per_core_options)
  33801. {
  33802. if (!string_is_empty(path_core_options))
  33803. strlcpy(new_options_path,
  33804. path_core_options, sizeof(new_options_path));
  33805. else if (!path_is_empty(RARCH_PATH_CONFIG))
  33806. fill_pathname_resolve_relative(
  33807. new_options_path, path_get(RARCH_PATH_CONFIG),
  33808. FILE_PATH_CORE_OPTIONS_CONFIG, sizeof(new_options_path));
  33809. }
  33810. }
  33811. if (string_is_empty(new_options_path))
  33812. goto error;
  33813. /* > If we have a valid file, load it */
  33814. if (folder_options_active ||
  33815. path_is_valid(new_options_path))
  33816. {
  33817. size_t i, j;
  33818. if (!(conf = config_file_new_from_path_to_string(new_options_path)))
  33819. goto error;
  33820. for (i = 0; i < coreopts->size; i++)
  33821. {
  33822. struct core_option *option = NULL;
  33823. struct config_entry_list *entry = NULL;
  33824. option = (struct core_option*)&coreopts->opts[i];
  33825. if (!option)
  33826. continue;
  33827. entry = config_get_entry(conf, option->key);
  33828. if (!entry || string_is_empty(entry->value))
  33829. continue;
  33830. /* Set current config value from file entry */
  33831. for (j = 0; j < option->vals->size; j++)
  33832. {
  33833. if (string_is_equal(option->vals->elems[j].data, entry->value))
  33834. {
  33835. option->index = j;
  33836. break;
  33837. }
  33838. }
  33839. }
  33840. coreopts->updated = true;
  33841. config_file_free(conf);
  33842. #ifdef HAVE_CHEEVOS
  33843. rcheevos_validate_config_settings();
  33844. #endif
  33845. }
  33846. /* Update runloop status */
  33847. if (folder_options_active)
  33848. {
  33849. path_set(RARCH_PATH_CORE_OPTIONS, new_options_path);
  33850. p_rarch->runloop_game_options_active = false;
  33851. p_rarch->runloop_folder_options_active = true;
  33852. }
  33853. else
  33854. {
  33855. path_clear(RARCH_PATH_CORE_OPTIONS);
  33856. p_rarch->runloop_game_options_active = false;
  33857. p_rarch->runloop_folder_options_active = false;
  33858. strlcpy(coreopts->conf_path, new_options_path,
  33859. sizeof(coreopts->conf_path));
  33860. }
  33861. runloop_msg_queue_push(
  33862. msg_hash_to_str(MSG_CORE_OPTIONS_FILE_REMOVED_SUCCESSFULLY),
  33863. 1, 100, true,
  33864. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  33865. return true;
  33866. error:
  33867. runloop_msg_queue_push(
  33868. msg_hash_to_str(MSG_ERROR_REMOVING_CORE_OPTIONS_FILE),
  33869. 1, 100, true,
  33870. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  33871. if (conf)
  33872. config_file_free(conf);
  33873. return false;
  33874. }
  33875. void core_options_reset(void)
  33876. {
  33877. struct rarch_state *p_rarch = &rarch_st;
  33878. core_option_manager_t *coreopts = p_rarch->runloop_core_options;
  33879. size_t i;
  33880. /* If there are no core options, there
  33881. * is nothing to do */
  33882. if (!coreopts || (coreopts->size < 1))
  33883. return;
  33884. for (i = 0; i < coreopts->size; i++)
  33885. coreopts->opts[i].index = coreopts->opts[i].default_index;
  33886. coreopts->updated = true;
  33887. #ifdef HAVE_CHEEVOS
  33888. rcheevos_validate_config_settings();
  33889. #endif
  33890. runloop_msg_queue_push(
  33891. msg_hash_to_str(MSG_CORE_OPTIONS_RESET),
  33892. 1, 100, true,
  33893. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  33894. }
  33895. void menu_content_environment_get(int *argc, char *argv[],
  33896. void *args, void *params_data)
  33897. {
  33898. struct rarch_state *p_rarch = &rarch_st;
  33899. struct rarch_main_wrap *wrap_args = (struct rarch_main_wrap*)params_data;
  33900. rarch_system_info_t *sys_info = &p_rarch->runloop_system;
  33901. if (!wrap_args)
  33902. return;
  33903. wrap_args->no_content = sys_info->load_no_content;
  33904. if (!retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_VERBOSITY, NULL))
  33905. wrap_args->verbose = verbosity_is_enabled();
  33906. wrap_args->touched = true;
  33907. wrap_args->config_path = NULL;
  33908. wrap_args->sram_path = NULL;
  33909. wrap_args->state_path = NULL;
  33910. wrap_args->content_path = NULL;
  33911. if (!path_is_empty(RARCH_PATH_CONFIG))
  33912. wrap_args->config_path = path_get(RARCH_PATH_CONFIG);
  33913. if (!string_is_empty(p_rarch->dir_savefile))
  33914. wrap_args->sram_path = p_rarch->dir_savefile;
  33915. if (!string_is_empty(p_rarch->dir_savestate))
  33916. wrap_args->state_path = p_rarch->dir_savestate;
  33917. if (!path_is_empty(RARCH_PATH_CONTENT))
  33918. wrap_args->content_path = path_get(RARCH_PATH_CONTENT);
  33919. if (!retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL))
  33920. wrap_args->libretro_path = string_is_empty(path_get(RARCH_PATH_CORE)) ? NULL :
  33921. path_get(RARCH_PATH_CORE);
  33922. }
  33923. frontend_ctx_driver_t *frontend_get_ptr(void)
  33924. {
  33925. struct rarch_state *p_rarch = &rarch_st;
  33926. return p_rarch->current_frontend_ctx;
  33927. }
  33928. int frontend_driver_parse_drive_list(void *data, bool load_content)
  33929. {
  33930. struct rarch_state *p_rarch = &rarch_st;
  33931. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  33932. if (!frontend || !frontend->parse_drive_list)
  33933. return -1;
  33934. return frontend->parse_drive_list(data, load_content);
  33935. }
  33936. void frontend_driver_content_loaded(void)
  33937. {
  33938. struct rarch_state *p_rarch = &rarch_st;
  33939. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  33940. if (!frontend || !frontend->content_loaded)
  33941. return;
  33942. frontend->content_loaded();
  33943. }
  33944. bool frontend_driver_has_fork(void)
  33945. {
  33946. struct rarch_state *p_rarch = &rarch_st;
  33947. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  33948. if (!frontend || !frontend->set_fork)
  33949. return false;
  33950. return true;
  33951. }
  33952. bool frontend_driver_set_fork(enum frontend_fork fork_mode)
  33953. {
  33954. struct rarch_state *p_rarch = &rarch_st;
  33955. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  33956. if (!frontend_driver_has_fork())
  33957. return false;
  33958. return frontend->set_fork(fork_mode);
  33959. }
  33960. void frontend_driver_process_args(int *argc, char *argv[])
  33961. {
  33962. struct rarch_state *p_rarch = &rarch_st;
  33963. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  33964. if (frontend && frontend->process_args)
  33965. frontend->process_args(argc, argv);
  33966. }
  33967. bool frontend_driver_is_inited(void)
  33968. {
  33969. struct rarch_state *p_rarch = &rarch_st;
  33970. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  33971. if (!frontend)
  33972. return false;
  33973. return true;
  33974. }
  33975. void frontend_driver_init_first(void *args)
  33976. {
  33977. struct rarch_state *p_rarch = &rarch_st;
  33978. p_rarch->current_frontend_ctx = (frontend_ctx_driver_t*)
  33979. frontend_ctx_init_first();
  33980. if (p_rarch->current_frontend_ctx && p_rarch->current_frontend_ctx->init)
  33981. p_rarch->current_frontend_ctx->init(args);
  33982. }
  33983. void frontend_driver_free(void)
  33984. {
  33985. struct rarch_state *p_rarch = &rarch_st;
  33986. if (p_rarch)
  33987. p_rarch->current_frontend_ctx = NULL;
  33988. }
  33989. environment_get_t frontend_driver_environment_get_ptr(void)
  33990. {
  33991. struct rarch_state *p_rarch = &rarch_st;
  33992. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  33993. if (frontend)
  33994. return frontend->environment_get;
  33995. return NULL;
  33996. }
  33997. bool frontend_driver_has_get_video_driver_func(void)
  33998. {
  33999. struct rarch_state *p_rarch = &rarch_st;
  34000. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34001. if (!frontend || !frontend->get_video_driver)
  34002. return false;
  34003. return true;
  34004. }
  34005. const struct video_driver *frontend_driver_get_video_driver(void)
  34006. {
  34007. struct rarch_state *p_rarch = &rarch_st;
  34008. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34009. if (!frontend || !frontend->get_video_driver)
  34010. return NULL;
  34011. return frontend->get_video_driver();
  34012. }
  34013. void frontend_driver_exitspawn(char *s, size_t len, char *args)
  34014. {
  34015. struct rarch_state *p_rarch = &rarch_st;
  34016. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34017. if (frontend && frontend->exitspawn)
  34018. frontend->exitspawn(s, len, args);
  34019. }
  34020. void frontend_driver_deinit(void *args)
  34021. {
  34022. struct rarch_state *p_rarch = &rarch_st;
  34023. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34024. if (frontend && frontend->deinit)
  34025. frontend->deinit(args);
  34026. }
  34027. void frontend_driver_shutdown(bool a)
  34028. {
  34029. struct rarch_state *p_rarch = &rarch_st;
  34030. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34031. if (frontend && frontend->shutdown)
  34032. frontend->shutdown(a);
  34033. }
  34034. enum frontend_architecture frontend_driver_get_cpu_architecture(void)
  34035. {
  34036. struct rarch_state *p_rarch = &rarch_st;
  34037. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34038. if (!frontend || !frontend->get_architecture)
  34039. return FRONTEND_ARCH_NONE;
  34040. return frontend->get_architecture();
  34041. }
  34042. const void *frontend_driver_get_cpu_architecture_str(
  34043. char *architecture, size_t size)
  34044. {
  34045. struct rarch_state *p_rarch = &rarch_st;
  34046. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34047. enum frontend_architecture arch = frontend_driver_get_cpu_architecture();
  34048. switch (arch)
  34049. {
  34050. case FRONTEND_ARCH_X86:
  34051. strcpy_literal(architecture, "x86");
  34052. break;
  34053. case FRONTEND_ARCH_X86_64:
  34054. strcpy_literal(architecture, "x64");
  34055. break;
  34056. case FRONTEND_ARCH_PPC:
  34057. strcpy_literal(architecture, "PPC");
  34058. break;
  34059. case FRONTEND_ARCH_ARM:
  34060. strcpy_literal(architecture, "ARM");
  34061. break;
  34062. case FRONTEND_ARCH_ARMV7:
  34063. strcpy_literal(architecture, "ARMv7");
  34064. break;
  34065. case FRONTEND_ARCH_ARMV8:
  34066. strcpy_literal(architecture, "ARMv8");
  34067. break;
  34068. case FRONTEND_ARCH_MIPS:
  34069. strcpy_literal(architecture, "MIPS");
  34070. break;
  34071. case FRONTEND_ARCH_TILE:
  34072. strcpy_literal(architecture, "Tilera");
  34073. break;
  34074. case FRONTEND_ARCH_NONE:
  34075. default:
  34076. strcpy_literal(architecture, "N/A");
  34077. break;
  34078. }
  34079. return frontend;
  34080. }
  34081. uint64_t frontend_driver_get_total_memory(void)
  34082. {
  34083. struct rarch_state *p_rarch = &rarch_st;
  34084. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34085. if (!frontend || !frontend->get_total_mem)
  34086. return 0;
  34087. return frontend->get_total_mem();
  34088. }
  34089. uint64_t frontend_driver_get_free_memory(void)
  34090. {
  34091. struct rarch_state *p_rarch = &rarch_st;
  34092. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34093. if (!frontend || !frontend->get_free_mem)
  34094. return 0;
  34095. return frontend->get_free_mem();
  34096. }
  34097. void frontend_driver_install_signal_handler(void)
  34098. {
  34099. struct rarch_state *p_rarch = &rarch_st;
  34100. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34101. if (frontend && frontend->install_signal_handler)
  34102. frontend->install_signal_handler();
  34103. }
  34104. int frontend_driver_get_signal_handler_state(void)
  34105. {
  34106. struct rarch_state *p_rarch = &rarch_st;
  34107. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34108. if (!frontend || !frontend->get_signal_handler_state)
  34109. return -1;
  34110. return frontend->get_signal_handler_state();
  34111. }
  34112. void frontend_driver_set_signal_handler_state(int value)
  34113. {
  34114. struct rarch_state *p_rarch = &rarch_st;
  34115. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34116. if (frontend && frontend->set_signal_handler_state)
  34117. frontend->set_signal_handler_state(value);
  34118. }
  34119. void frontend_driver_attach_console(void)
  34120. {
  34121. struct rarch_state *p_rarch = &rarch_st;
  34122. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34123. if (frontend && frontend->attach_console)
  34124. frontend->attach_console();
  34125. }
  34126. void frontend_driver_set_screen_brightness(int value)
  34127. {
  34128. struct rarch_state *p_rarch = &rarch_st;
  34129. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34130. if (frontend && frontend->set_screen_brightness)
  34131. frontend->set_screen_brightness(value);
  34132. }
  34133. bool frontend_driver_can_set_screen_brightness()
  34134. {
  34135. struct rarch_state *p_rarch = &rarch_st;
  34136. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34137. return (frontend && frontend->set_screen_brightness);
  34138. }
  34139. void frontend_driver_detach_console(void)
  34140. {
  34141. struct rarch_state *p_rarch = &rarch_st;
  34142. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34143. if (frontend && frontend->detach_console)
  34144. frontend->detach_console();
  34145. }
  34146. void frontend_driver_destroy_signal_handler_state(void)
  34147. {
  34148. struct rarch_state *p_rarch = &rarch_st;
  34149. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34150. if (frontend && frontend->destroy_signal_handler_state)
  34151. frontend->destroy_signal_handler_state();
  34152. }
  34153. bool frontend_driver_can_watch_for_changes(void)
  34154. {
  34155. struct rarch_state *p_rarch = &rarch_st;
  34156. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34157. if (!frontend || !frontend->watch_path_for_changes)
  34158. return false;
  34159. return true;
  34160. }
  34161. void frontend_driver_watch_path_for_changes(
  34162. struct string_list *list, int flags,
  34163. path_change_data_t **change_data)
  34164. {
  34165. struct rarch_state *p_rarch = &rarch_st;
  34166. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34167. if (frontend && frontend->watch_path_for_changes)
  34168. frontend->watch_path_for_changes(list, flags, change_data);
  34169. }
  34170. bool frontend_driver_check_for_path_changes(path_change_data_t *change_data)
  34171. {
  34172. struct rarch_state *p_rarch = &rarch_st;
  34173. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34174. if (!frontend || !frontend->check_for_path_changes)
  34175. return false;
  34176. return frontend->check_for_path_changes(change_data);
  34177. }
  34178. void frontend_driver_set_sustained_performance_mode(bool on)
  34179. {
  34180. struct rarch_state *p_rarch = &rarch_st;
  34181. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34182. if (frontend && frontend->set_sustained_performance_mode)
  34183. frontend->set_sustained_performance_mode(on);
  34184. }
  34185. const char* frontend_driver_get_cpu_model_name(void)
  34186. {
  34187. struct rarch_state *p_rarch = &rarch_st;
  34188. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34189. if (!frontend || !frontend->get_cpu_model_name)
  34190. return NULL;
  34191. return frontend->get_cpu_model_name();
  34192. }
  34193. enum retro_language frontend_driver_get_user_language(void)
  34194. {
  34195. struct rarch_state *p_rarch = &rarch_st;
  34196. frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
  34197. if (!frontend || !frontend->get_user_language)
  34198. return RETRO_LANGUAGE_ENGLISH;
  34199. return frontend->get_user_language();
  34200. }