openxr_api.cpp 123 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759
  1. /**************************************************************************/
  2. /* openxr_api.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "openxr_api.h"
  31. #include "openxr_interface.h"
  32. #include "openxr_util.h"
  33. #include "core/config/engine.h"
  34. #include "core/config/project_settings.h"
  35. #include "core/os/memory.h"
  36. #include "core/version.h"
  37. #include "openxr_platform_inc.h"
  38. #ifdef VULKAN_ENABLED
  39. #include "extensions/platform/openxr_vulkan_extension.h"
  40. #endif
  41. #ifdef METAL_ENABLED
  42. #include "extensions/platform/openxr_metal_extension.h"
  43. #endif
  44. #if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
  45. #include "extensions/platform/openxr_opengl_extension.h"
  46. #endif
  47. #ifdef D3D12_ENABLED
  48. #include "extensions/platform/openxr_d3d12_extension.h"
  49. #endif
  50. #include "extensions/openxr_composition_layer_depth_extension.h"
  51. #include "extensions/openxr_debug_utils_extension.h"
  52. #include "extensions/openxr_eye_gaze_interaction.h"
  53. #include "extensions/openxr_fb_display_refresh_rate_extension.h"
  54. #include "extensions/openxr_fb_foveation_extension.h"
  55. #include "extensions/openxr_fb_update_swapchain_extension.h"
  56. #include "extensions/openxr_hand_tracking_extension.h"
  57. #ifndef DISABLE_DEPRECATED
  58. #include "extensions/openxr_extension_wrapper_extension.h"
  59. #endif // DISABLE_DEPRECATED
  60. #ifdef ANDROID_ENABLED
  61. #define OPENXR_LOADER_NAME "libopenxr_loader.so"
  62. #endif
  63. ////////////////////////////////////
  64. // OpenXRAPI::OpenXRSwapChainInfo
  65. Vector<OpenXRAPI::OpenXRSwapChainInfo> OpenXRAPI::OpenXRSwapChainInfo::free_queue;
  66. bool OpenXRAPI::OpenXRSwapChainInfo::create(XrSwapchainCreateFlags p_create_flags, XrSwapchainUsageFlags p_usage_flags, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size) {
  67. OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
  68. ERR_FAIL_NULL_V(openxr_api, false);
  69. XrSession xr_session = openxr_api->get_session();
  70. ERR_FAIL_COND_V(xr_session == XR_NULL_HANDLE, false);
  71. OpenXRGraphicsExtensionWrapper *xr_graphics_extension = openxr_api->get_graphics_extension();
  72. ERR_FAIL_NULL_V(xr_graphics_extension, false);
  73. // We already have a swapchain?
  74. ERR_FAIL_COND_V(swapchain != XR_NULL_HANDLE, false);
  75. XrResult result;
  76. void *next_pointer = nullptr;
  77. for (OpenXRExtensionWrapper *wrapper : openxr_api->get_registered_extension_wrappers()) {
  78. void *np = wrapper->set_swapchain_create_info_and_get_next_pointer(next_pointer);
  79. if (np != nullptr) {
  80. next_pointer = np;
  81. }
  82. }
  83. XrSwapchainCreateInfo swapchain_create_info = {
  84. XR_TYPE_SWAPCHAIN_CREATE_INFO, // type
  85. next_pointer, // next
  86. p_create_flags, // createFlags
  87. p_usage_flags, // usageFlags
  88. p_swapchain_format, // format
  89. p_sample_count, // sampleCount
  90. p_width, // width
  91. p_height, // height
  92. 1, // faceCount
  93. p_array_size, // arraySize
  94. 1 // mipCount
  95. };
  96. XrSwapchain new_swapchain;
  97. result = openxr_api->xrCreateSwapchain(xr_session, &swapchain_create_info, &new_swapchain);
  98. if (XR_FAILED(result)) {
  99. print_line("OpenXR: Failed to get swapchain [", openxr_api->get_error_string(result), "]");
  100. return false;
  101. }
  102. if (!xr_graphics_extension->get_swapchain_image_data(new_swapchain, p_swapchain_format, p_width, p_height, p_sample_count, p_array_size, &swapchain_graphics_data)) {
  103. openxr_api->xrDestroySwapchain(new_swapchain);
  104. return false;
  105. }
  106. swapchain = new_swapchain;
  107. return true;
  108. }
  109. void OpenXRAPI::OpenXRSwapChainInfo::queue_free() {
  110. if (image_acquired) {
  111. release();
  112. }
  113. if (swapchain != XR_NULL_HANDLE) {
  114. free_queue.push_back(*this);
  115. swapchain_graphics_data = nullptr;
  116. swapchain = XR_NULL_HANDLE;
  117. }
  118. }
  119. void OpenXRAPI::OpenXRSwapChainInfo::free_queued() {
  120. for (OpenXRAPI::OpenXRSwapChainInfo &swapchain_info : free_queue) {
  121. swapchain_info.free();
  122. }
  123. free_queue.clear();
  124. }
  125. void OpenXRAPI::OpenXRSwapChainInfo::free() {
  126. OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
  127. ERR_FAIL_NULL(openxr_api);
  128. if (image_acquired) {
  129. release();
  130. }
  131. if (openxr_api->get_graphics_extension() && swapchain_graphics_data != nullptr) {
  132. openxr_api->get_graphics_extension()->cleanup_swapchain_graphics_data(&swapchain_graphics_data);
  133. }
  134. if (swapchain != XR_NULL_HANDLE) {
  135. openxr_api->xrDestroySwapchain(swapchain);
  136. swapchain = XR_NULL_HANDLE;
  137. }
  138. }
  139. bool OpenXRAPI::OpenXRSwapChainInfo::acquire(bool &p_should_render) {
  140. ERR_FAIL_COND_V(image_acquired, true); // This was not released when it should be, error out and reuse...
  141. OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
  142. ERR_FAIL_NULL_V(openxr_api, false);
  143. XrResult result;
  144. if (!skip_acquire_swapchain) {
  145. XrSwapchainImageAcquireInfo swapchain_image_acquire_info = {
  146. XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, // type
  147. nullptr // next
  148. };
  149. result = openxr_api->xrAcquireSwapchainImage(swapchain, &swapchain_image_acquire_info, &image_index);
  150. if (!XR_UNQUALIFIED_SUCCESS(result)) {
  151. // Make sure end_frame knows we need to submit an empty frame
  152. p_should_render = false;
  153. if (XR_FAILED(result)) {
  154. // Unexpected failure, log this!
  155. print_line("OpenXR: failed to acquire swapchain image [", openxr_api->get_error_string(result), "]");
  156. return false;
  157. } else {
  158. // In this scenario we silently fail, the XR runtime is simply not ready yet to acquire the swapchain.
  159. return false;
  160. }
  161. }
  162. }
  163. XrSwapchainImageWaitInfo swapchain_image_wait_info = {
  164. XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, // type
  165. nullptr, // next
  166. 1000000000 // 1s timeout in nanoseconds
  167. };
  168. // Wait for a maximum of 10 seconds before calling it a critical failure...
  169. for (int retry = 0; retry < 10; retry++) {
  170. result = openxr_api->xrWaitSwapchainImage(swapchain, &swapchain_image_wait_info);
  171. if (result != XR_TIMEOUT_EXPIRED) {
  172. break;
  173. }
  174. WARN_PRINT("OpenXR: timed out waiting for swapchain image.");
  175. }
  176. if (!XR_UNQUALIFIED_SUCCESS(result)) {
  177. // Make sure end_frame knows we need to submit an empty frame
  178. p_should_render = false;
  179. if (XR_FAILED(result)) {
  180. // Unexpected failure, log this!
  181. print_line("OpenXR: failed to wait for swapchain image [", openxr_api->get_error_string(result), "]");
  182. return false;
  183. } else {
  184. WARN_PRINT("OpenXR: couldn't to wait for swapchain but not a complete error [" + openxr_api->get_error_string(result) + "]");
  185. // Make sure to skip trying to acquire the swapchain image in the next frame
  186. skip_acquire_swapchain = true;
  187. return false;
  188. }
  189. } else {
  190. skip_acquire_swapchain = false;
  191. }
  192. image_acquired = true;
  193. return true;
  194. }
  195. bool OpenXRAPI::OpenXRSwapChainInfo::release() {
  196. if (!image_acquired) {
  197. // Already released or never acquired.
  198. return true;
  199. }
  200. image_acquired = false; // Regardless if we succeed or not, consider this released.
  201. OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
  202. ERR_FAIL_NULL_V(openxr_api, false);
  203. XrSwapchainImageReleaseInfo swapchain_image_release_info = {
  204. XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, // type
  205. nullptr // next
  206. };
  207. XrResult result = openxr_api->xrReleaseSwapchainImage(swapchain, &swapchain_image_release_info);
  208. if (XR_FAILED(result)) {
  209. print_line("OpenXR: failed to release swapchain image! [", openxr_api->get_error_string(result), "]");
  210. return false;
  211. }
  212. return true;
  213. }
  214. RID OpenXRAPI::OpenXRSwapChainInfo::get_image() {
  215. OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
  216. if (image_acquired && openxr_api && openxr_api->get_graphics_extension()) {
  217. return OpenXRAPI::get_singleton()->get_graphics_extension()->get_texture(swapchain_graphics_data, image_index);
  218. } else {
  219. return RID();
  220. }
  221. }
  222. RID OpenXRAPI::OpenXRSwapChainInfo::get_density_map() {
  223. OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
  224. if (image_acquired && openxr_api && openxr_api->get_graphics_extension()) {
  225. return openxr_api->get_graphics_extension()->get_density_map(swapchain_graphics_data, image_index);
  226. } else {
  227. return RID();
  228. }
  229. }
  230. ////////////////////////////////////
  231. // OpenXRAPI
  232. OpenXRAPI *OpenXRAPI::singleton = nullptr;
  233. Vector<OpenXRExtensionWrapper *> OpenXRAPI::registered_extension_wrappers;
  234. bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) {
  235. if (XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT) {
  236. if (Engine::get_singleton()->is_editor_hint() && p_check_run_in_editor) {
  237. // For now, don't start OpenXR when the editor starts up. In the future, this may change
  238. // if we want to integrate more XR features into the editor experience.
  239. return false;
  240. } else {
  241. return GLOBAL_GET("xr/openxr/enabled");
  242. }
  243. } else {
  244. return XRServer::get_xr_mode() == XRServer::XRMODE_ON;
  245. }
  246. }
  247. String OpenXRAPI::get_default_action_map_resource_name() {
  248. String name = GLOBAL_GET("xr/openxr/default_action_map");
  249. return name;
  250. }
  251. String OpenXRAPI::get_error_string(XrResult result) const {
  252. if (XR_SUCCEEDED(result)) {
  253. return String("Succeeded");
  254. }
  255. if (instance == XR_NULL_HANDLE) {
  256. Array args = { Variant(result) };
  257. return String("Error code {0}").format(args);
  258. }
  259. char resultString[XR_MAX_RESULT_STRING_SIZE];
  260. xrResultToString(instance, result, resultString);
  261. return String(resultString);
  262. }
  263. String OpenXRAPI::get_swapchain_format_name(int64_t p_swapchain_format) const {
  264. // This is rendering engine dependent...
  265. if (graphics_extension) {
  266. return graphics_extension->get_swapchain_format_name(p_swapchain_format);
  267. }
  268. return String("Swapchain format ") + String::num_int64(int64_t(p_swapchain_format));
  269. }
  270. void OpenXRAPI::set_object_name(XrObjectType p_object_type, uint64_t p_object_handle, const String &p_object_name) {
  271. OpenXRDebugUtilsExtension *debug_utils = OpenXRDebugUtilsExtension::get_singleton();
  272. if (!debug_utils || !debug_utils->get_active()) {
  273. // Not enabled/active? Ignore.
  274. return;
  275. }
  276. debug_utils->set_object_name(p_object_type, p_object_handle, p_object_name.utf8().get_data());
  277. }
  278. void OpenXRAPI::begin_debug_label_region(const String &p_label_name) {
  279. OpenXRDebugUtilsExtension *debug_utils = OpenXRDebugUtilsExtension::get_singleton();
  280. if (!debug_utils || !debug_utils->get_active()) {
  281. // Not enabled/active? Ignore.
  282. return;
  283. }
  284. debug_utils->begin_debug_label_region(p_label_name.utf8().get_data());
  285. }
  286. void OpenXRAPI::end_debug_label_region() {
  287. OpenXRDebugUtilsExtension *debug_utils = OpenXRDebugUtilsExtension::get_singleton();
  288. if (!debug_utils || !debug_utils->get_active()) {
  289. // Not enabled/active? Ignore.
  290. return;
  291. }
  292. debug_utils->end_debug_label_region();
  293. }
  294. void OpenXRAPI::insert_debug_label(const String &p_label_name) {
  295. OpenXRDebugUtilsExtension *debug_utils = OpenXRDebugUtilsExtension::get_singleton();
  296. if (!debug_utils || !debug_utils->get_active()) {
  297. // Not enabled/active? Ignore.
  298. return;
  299. }
  300. debug_utils->insert_debug_label(p_label_name.utf8().get_data());
  301. }
  302. bool OpenXRAPI::load_layer_properties() {
  303. // This queries additional layers that are available and can be initialized when we create our OpenXR instance
  304. if (!layer_properties.is_empty()) {
  305. // already retrieved this
  306. return true;
  307. }
  308. // Note, instance is not yet setup so we can't use get_error_string to retrieve our error
  309. uint32_t num_layer_properties = 0;
  310. XrResult result = xrEnumerateApiLayerProperties(0, &num_layer_properties, nullptr);
  311. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate number of api layer properties");
  312. layer_properties.resize(num_layer_properties);
  313. for (XrApiLayerProperties &layer : layer_properties) {
  314. layer.type = XR_TYPE_API_LAYER_PROPERTIES;
  315. layer.next = nullptr;
  316. }
  317. result = xrEnumerateApiLayerProperties(num_layer_properties, &num_layer_properties, layer_properties.ptr());
  318. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate api layer properties");
  319. for (const XrApiLayerProperties &layer : layer_properties) {
  320. print_verbose(vformat("OpenXR: Found OpenXR layer %s.", layer.layerName));
  321. }
  322. return true;
  323. }
  324. bool OpenXRAPI::load_supported_extensions() {
  325. // This queries supported extensions that are available and can be initialized when we create our OpenXR instance
  326. if (!supported_extensions.is_empty()) {
  327. // already retrieved this
  328. return true;
  329. }
  330. // Note, instance is not yet setup so we can't use get_error_string to retrieve our error
  331. uint32_t num_supported_extensions = 0;
  332. XrResult result = xrEnumerateInstanceExtensionProperties(nullptr, 0, &num_supported_extensions, nullptr);
  333. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate number of extension properties");
  334. supported_extensions.resize(num_supported_extensions);
  335. // set our types
  336. for (XrExtensionProperties &extension : supported_extensions) {
  337. extension.type = XR_TYPE_EXTENSION_PROPERTIES;
  338. extension.next = nullptr;
  339. }
  340. result = xrEnumerateInstanceExtensionProperties(nullptr, num_supported_extensions, &num_supported_extensions, supported_extensions.ptr());
  341. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate extension properties");
  342. for (const XrExtensionProperties &extension : supported_extensions) {
  343. print_verbose(vformat("OpenXR: Found OpenXR extension %s.", extension.extensionName));
  344. }
  345. return true;
  346. }
  347. bool OpenXRAPI::is_extension_supported(const String &p_extension) const {
  348. for (const XrExtensionProperties &extension : supported_extensions) {
  349. if (extension.extensionName == p_extension) {
  350. return true;
  351. }
  352. }
  353. return false;
  354. }
  355. bool OpenXRAPI::is_extension_enabled(const String &p_extension) const {
  356. CharString extension = p_extension.ascii();
  357. for (int i = 0; i < enabled_extensions.size(); i++) {
  358. if (strcmp(enabled_extensions[i].ptr(), extension.ptr()) == 0) {
  359. return true;
  360. }
  361. }
  362. return false;
  363. }
  364. bool OpenXRAPI::is_top_level_path_supported(const String &p_toplevel_path) {
  365. String required_extension = OpenXRInteractionProfileMetadata::get_singleton()->get_top_level_extension(p_toplevel_path);
  366. // If unsupported is returned we likely have a misspelled interaction profile path in our action map. Always output that as an error.
  367. ERR_FAIL_COND_V_MSG(required_extension == XR_PATH_UNSUPPORTED_NAME, false, "OpenXR: Unsupported toplevel path " + p_toplevel_path);
  368. if (required_extension == "") {
  369. // no extension needed, core top level are always "supported", they just won't be used if not really supported
  370. return true;
  371. }
  372. if (!is_extension_enabled(required_extension)) {
  373. // It is very likely we have top level paths for which the extension is not available so don't flood the logs with unnecessary spam.
  374. print_verbose("OpenXR: Top level path " + p_toplevel_path + " requires extension " + required_extension);
  375. return false;
  376. }
  377. return true;
  378. }
  379. bool OpenXRAPI::is_interaction_profile_supported(const String &p_ip_path) {
  380. String required_extension = OpenXRInteractionProfileMetadata::get_singleton()->get_interaction_profile_extension(p_ip_path);
  381. // If unsupported is returned we likely have a misspelled interaction profile path in our action map. Always output that as an error.
  382. ERR_FAIL_COND_V_MSG(required_extension == XR_PATH_UNSUPPORTED_NAME, false, "OpenXR: Unsupported interaction profile " + p_ip_path);
  383. if (required_extension == "") {
  384. // no extension needed, core interaction profiles are always "supported", they just won't be used if not really supported
  385. return true;
  386. }
  387. if (!is_extension_enabled(required_extension)) {
  388. // It is very likely we have interaction profiles for which the extension is not available so don't flood the logs with unnecessary spam.
  389. print_verbose("OpenXR: Interaction profile " + p_ip_path + " requires extension " + required_extension);
  390. return false;
  391. }
  392. return true;
  393. }
  394. bool OpenXRAPI::interaction_profile_supports_io_path(const String &p_ip_path, const String &p_io_path) {
  395. if (!is_interaction_profile_supported(p_ip_path)) {
  396. return false;
  397. }
  398. const OpenXRInteractionProfileMetadata::IOPath *io_path = OpenXRInteractionProfileMetadata::get_singleton()->get_io_path(p_ip_path, p_io_path);
  399. // If the io_path is not part of our metadata we've likely got a misspelled name or a bad action map, report
  400. ERR_FAIL_NULL_V_MSG(io_path, false, "OpenXR: Unsupported io path " + String(p_ip_path) + String(p_io_path));
  401. if (io_path->openxr_extension_name == "") {
  402. // no extension needed, core io paths are always "supported", they just won't be used if not really supported
  403. return true;
  404. }
  405. if (!is_extension_enabled(io_path->openxr_extension_name)) {
  406. // It is very likely we have io paths for which the extension is not available so don't flood the logs with unnecessary spam.
  407. print_verbose("OpenXR: IO path " + String(p_ip_path) + String(p_io_path) + " requires extension " + io_path->openxr_extension_name);
  408. return false;
  409. }
  410. return true;
  411. }
  412. void OpenXRAPI::copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len) {
  413. CharString char_string = p_string.utf8();
  414. int len = char_string.length();
  415. if (len < p_buffer_len - 1) {
  416. // was having weird CI issues with strcpy so....
  417. memcpy(p_buffer, char_string.get_data(), len);
  418. p_buffer[len] = '\0';
  419. } else {
  420. memcpy(p_buffer, char_string.get_data(), p_buffer_len - 1);
  421. p_buffer[p_buffer_len - 1] = '\0';
  422. }
  423. }
  424. PackedStringArray OpenXRAPI::get_all_requested_extensions() {
  425. // This returns all extensions we will request regardless of whether they are available.
  426. // This is mostly used by the editor to filter features not enabled through project settings.
  427. PackedStringArray requested_extensions;
  428. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  429. const HashMap<String, bool *> &wrapper_request_extensions = wrapper->get_requested_extensions();
  430. for (const KeyValue<String, bool *> &requested_extension : wrapper_request_extensions) {
  431. if (!requested_extensions.has(requested_extension.key)) {
  432. requested_extensions.push_back(requested_extension.key);
  433. }
  434. }
  435. }
  436. return requested_extensions;
  437. }
  438. bool OpenXRAPI::create_instance() {
  439. // Create our OpenXR instance, this will query any registered extension wrappers for extensions we need to enable.
  440. // We can request an extension multiple times if there are dependencies
  441. struct RequestExtension {
  442. String name;
  443. bool *enabled;
  444. };
  445. // Find all extensions we wish to enable.
  446. Vector<RequestExtension> requested_extensions;
  447. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  448. const HashMap<String, bool *> &wrapper_request_extensions = wrapper->get_requested_extensions();
  449. for (const KeyValue<String, bool *> &requested_extension : wrapper_request_extensions) {
  450. requested_extensions.push_back({ requested_extension.key, requested_extension.value });
  451. }
  452. }
  453. // Check which extensions are supported.
  454. enabled_extensions.clear();
  455. for (RequestExtension &requested_extension : requested_extensions) {
  456. if (!is_extension_supported(requested_extension.name)) {
  457. if (requested_extension.enabled == nullptr) {
  458. // Null means this is a mandatory extension so we fail.
  459. ERR_FAIL_V_MSG(false, String("OpenXR: OpenXR Runtime does not support ") + requested_extension.name + String(" extension!"));
  460. } else {
  461. // Set this extension as not supported.
  462. *requested_extension.enabled = false;
  463. }
  464. } else {
  465. if (requested_extension.enabled != nullptr) {
  466. // Set this extension as supported.
  467. *requested_extension.enabled = true;
  468. }
  469. // And record that we want to enable it (dependent extensions may be requested multiple times).
  470. CharString ext_name = requested_extension.name.ascii();
  471. if (!enabled_extensions.has(ext_name)) {
  472. enabled_extensions.push_back(ext_name);
  473. }
  474. }
  475. }
  476. Vector<const char *> extension_ptrs;
  477. for (int i = 0; i < enabled_extensions.size(); i++) {
  478. print_verbose(String("OpenXR: Enabling extension ") + String(enabled_extensions[i].get_data()));
  479. extension_ptrs.push_back(enabled_extensions[i].get_data());
  480. }
  481. // Create our OpenXR instance
  482. XrApplicationInfo application_info{
  483. "Godot Engine", // applicationName, if we're running a game we'll update this down below.
  484. 1, // applicationVersion, we don't currently have this
  485. "Godot Engine", // engineName
  486. GODOT_VERSION_MAJOR * 10000 + GODOT_VERSION_MINOR * 100 + GODOT_VERSION_PATCH, // engineVersion 4.0 -> 40000, 4.0.1 -> 40001, 4.1 -> 40100, etc.
  487. XR_API_VERSION_1_0 // apiVersion
  488. };
  489. void *next_pointer = nullptr;
  490. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  491. void *np = wrapper->set_instance_create_info_and_get_next_pointer(next_pointer);
  492. if (np != nullptr) {
  493. next_pointer = np;
  494. }
  495. }
  496. XrInstanceCreateInfo instance_create_info = {
  497. XR_TYPE_INSTANCE_CREATE_INFO, // type
  498. next_pointer, // next
  499. 0, // createFlags
  500. application_info, // applicationInfo
  501. 0, // enabledApiLayerCount, need to find out if we need support for this?
  502. nullptr, // enabledApiLayerNames
  503. uint32_t(extension_ptrs.size()), // enabledExtensionCount
  504. extension_ptrs.ptr() // enabledExtensionNames
  505. };
  506. // Get our project name
  507. String project_name = GLOBAL_GET("application/config/name");
  508. if (!project_name.is_empty()) {
  509. copy_string_to_char_buffer(project_name, instance_create_info.applicationInfo.applicationName, XR_MAX_APPLICATION_NAME_SIZE);
  510. }
  511. XrResult result = xrCreateInstance(&instance_create_info, &instance);
  512. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "Failed to create XR instance.");
  513. // from this point on we can use get_error_string to get more info about our errors...
  514. XrInstanceProperties instanceProps = {
  515. XR_TYPE_INSTANCE_PROPERTIES, // type;
  516. nullptr, // next
  517. 0, // runtimeVersion, from here will be set by our get call
  518. "" // runtimeName
  519. };
  520. OPENXR_API_INIT_XR_FUNC_V(xrGetInstanceProperties);
  521. result = xrGetInstanceProperties(instance, &instanceProps);
  522. if (XR_FAILED(result)) {
  523. // not fatal probably
  524. print_line("OpenXR: Failed to get XR instance properties [", get_error_string(result), "]");
  525. runtime_name = "";
  526. runtime_version = "";
  527. } else {
  528. runtime_name = instanceProps.runtimeName;
  529. runtime_version = OpenXRUtil::make_xr_version_string(instanceProps.runtimeVersion);
  530. print_line("OpenXR: Running on OpenXR runtime: ", runtime_name, " ", runtime_version);
  531. }
  532. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  533. wrapper->on_instance_created(instance);
  534. }
  535. return true;
  536. }
  537. bool OpenXRAPI::get_system_info() {
  538. // Retrieve basic OpenXR system info based on the form factor we desire
  539. // Retrieve the system for our form factor, fails if form factor is not available
  540. XrSystemGetInfo system_get_info = {
  541. XR_TYPE_SYSTEM_GET_INFO, // type;
  542. nullptr, // next
  543. form_factor // formFactor
  544. };
  545. XrResult result = xrGetSystem(instance, &system_get_info, &system_id);
  546. if (XR_FAILED(result)) {
  547. print_line("OpenXR: Failed to get system for our form factor [", get_error_string(result), "]");
  548. return false;
  549. }
  550. // obtain info about our system, writing this out completely to make CI on Linux happy..
  551. void *next_pointer = nullptr;
  552. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  553. void *np = wrapper->set_system_properties_and_get_next_pointer(next_pointer);
  554. if (np != nullptr) {
  555. next_pointer = np;
  556. }
  557. }
  558. XrSystemProperties system_properties = {
  559. XR_TYPE_SYSTEM_PROPERTIES, // type
  560. next_pointer, // next
  561. 0, // systemId, from here will be set by our get call
  562. 0, // vendorId
  563. "", // systemName
  564. {
  565. 0, // maxSwapchainImageHeight
  566. 0, // maxSwapchainImageWidth
  567. 0, // maxLayerCount
  568. }, // graphicsProperties
  569. {
  570. false, // orientationTracking
  571. false // positionTracking
  572. } // trackingProperties
  573. };
  574. result = xrGetSystemProperties(instance, system_id, &system_properties);
  575. if (XR_FAILED(result)) {
  576. print_line("OpenXR: Failed to get System properties [", get_error_string(result), "]");
  577. return false;
  578. }
  579. // remember this state, we'll use it later
  580. system_name = String(system_properties.systemName);
  581. vendor_id = system_properties.vendorId;
  582. graphics_properties = system_properties.graphicsProperties;
  583. tracking_properties = system_properties.trackingProperties;
  584. return true;
  585. }
  586. bool OpenXRAPI::load_supported_view_configuration_types() {
  587. // This queries the supported configuration types, likely there will only be one choosing between Mono (phone AR) and Stereo (HMDs)
  588. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  589. supported_view_configuration_types.clear();
  590. uint32_t num_view_configuration_types = 0;
  591. XrResult result = xrEnumerateViewConfigurations(instance, system_id, 0, &num_view_configuration_types, nullptr);
  592. if (XR_FAILED(result)) {
  593. print_line("OpenXR: Failed to get view configuration count [", get_error_string(result), "]");
  594. return false;
  595. }
  596. supported_view_configuration_types.resize(num_view_configuration_types);
  597. result = xrEnumerateViewConfigurations(instance, system_id, num_view_configuration_types, &num_view_configuration_types, supported_view_configuration_types.ptr());
  598. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerateview configurations");
  599. ERR_FAIL_COND_V_MSG(num_view_configuration_types == 0, false, "OpenXR: Failed to enumerateview configurations"); // JIC there should be at least 1!
  600. for (const XrViewConfigurationType &view_configuration_type : supported_view_configuration_types) {
  601. print_verbose(vformat("OpenXR: Found supported view configuration %s.", OpenXRUtil::get_view_configuration_name(view_configuration_type)));
  602. }
  603. // Check value we loaded at startup...
  604. if (!is_view_configuration_supported(view_configuration)) {
  605. print_verbose(vformat("OpenXR: %s isn't supported, defaulting to %s.", OpenXRUtil::get_view_configuration_name(view_configuration), OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[0])));
  606. view_configuration = supported_view_configuration_types[0];
  607. }
  608. return true;
  609. }
  610. bool OpenXRAPI::load_supported_environmental_blend_modes() {
  611. // This queries the supported environmental blend modes.
  612. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  613. supported_environment_blend_modes.clear();
  614. uint32_t num_supported_environment_blend_modes = 0;
  615. XrResult result = xrEnumerateEnvironmentBlendModes(instance, system_id, view_configuration, 0, &num_supported_environment_blend_modes, nullptr);
  616. if (XR_FAILED(result)) {
  617. print_line("OpenXR: Failed to get supported environmental blend mode count [", get_error_string(result), "]");
  618. return false;
  619. }
  620. supported_environment_blend_modes.resize(num_supported_environment_blend_modes);
  621. result = xrEnumerateEnvironmentBlendModes(instance, system_id, view_configuration, num_supported_environment_blend_modes, &num_supported_environment_blend_modes, supported_environment_blend_modes.ptrw());
  622. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate environmental blend modes");
  623. ERR_FAIL_COND_V_MSG(num_supported_environment_blend_modes == 0, false, "OpenXR: Failed to enumerate environmental blend modes"); // JIC there should be at least 1!
  624. for (const XrEnvironmentBlendMode &supported_environment_blend_mode : supported_environment_blend_modes) {
  625. print_verbose(vformat("OpenXR: Found environmental blend mode %s.", OpenXRUtil::get_environment_blend_mode_name(supported_environment_blend_mode)));
  626. }
  627. return true;
  628. }
  629. bool OpenXRAPI::is_view_configuration_supported(XrViewConfigurationType p_configuration_type) const {
  630. return supported_view_configuration_types.has(p_configuration_type);
  631. }
  632. bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType p_configuration_type) {
  633. // This loads our view configuration for each view so for a stereo HMD, we'll get two entries (that are likely identical)
  634. // The returned data supplies us with the recommended render target size
  635. if (!is_view_configuration_supported(p_configuration_type)) {
  636. print_line("OpenXR: View configuration ", OpenXRUtil::get_view_configuration_name(view_configuration), " is not supported.");
  637. return false;
  638. }
  639. if (!view_configuration_views.is_empty()) {
  640. // free previous results
  641. view_configuration_views.clear();
  642. }
  643. uint32_t view_count = 0;
  644. XrResult result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, 0, &view_count, nullptr);
  645. if (XR_FAILED(result)) {
  646. print_line("OpenXR: Failed to get view configuration count [", get_error_string(result), "]");
  647. return false;
  648. }
  649. view_configuration_views.resize(view_count);
  650. for (XrViewConfigurationView &view_configuration_view : view_configuration_views) {
  651. view_configuration_view.type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
  652. view_configuration_view.next = nullptr;
  653. }
  654. result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, view_count, &view_count, view_configuration_views.ptr());
  655. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate view configurations");
  656. for (const XrViewConfigurationView &view_configuration_view : view_configuration_views) {
  657. print_verbose("OpenXR: Found supported view configuration view");
  658. print_verbose(String(" - width: ") + itos(view_configuration_view.maxImageRectWidth));
  659. print_verbose(String(" - height: ") + itos(view_configuration_view.maxImageRectHeight));
  660. print_verbose(String(" - sample count: ") + itos(view_configuration_view.maxSwapchainSampleCount));
  661. print_verbose(String(" - recommended render width: ") + itos(view_configuration_view.recommendedImageRectWidth));
  662. print_verbose(String(" - recommended render height: ") + itos(view_configuration_view.recommendedImageRectHeight));
  663. print_verbose(String(" - recommended render sample count: ") + itos(view_configuration_view.recommendedSwapchainSampleCount));
  664. }
  665. return true;
  666. }
  667. void OpenXRAPI::destroy_instance() {
  668. view_configuration_views.clear();
  669. supported_view_configuration_types.clear();
  670. supported_environment_blend_modes.clear();
  671. if (instance != XR_NULL_HANDLE) {
  672. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  673. wrapper->on_instance_destroyed();
  674. }
  675. xrDestroyInstance(instance);
  676. instance = XR_NULL_HANDLE;
  677. }
  678. enabled_extensions.clear();
  679. if (graphics_extension != nullptr) {
  680. unregister_extension_wrapper(graphics_extension);
  681. memdelete(graphics_extension);
  682. graphics_extension = nullptr;
  683. }
  684. }
  685. bool OpenXRAPI::create_session() {
  686. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  687. ERR_FAIL_COND_V(session != XR_NULL_HANDLE, false);
  688. void *next_pointer = nullptr;
  689. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  690. void *np = wrapper->set_session_create_and_get_next_pointer(next_pointer);
  691. if (np != nullptr) {
  692. next_pointer = np;
  693. }
  694. }
  695. XrSessionCreateInfo session_create_info = {
  696. XR_TYPE_SESSION_CREATE_INFO, // type
  697. next_pointer, // next
  698. 0, // createFlags
  699. system_id // systemId
  700. };
  701. XrResult result = xrCreateSession(instance, &session_create_info, &session);
  702. if (XR_FAILED(result)) {
  703. print_line("OpenXR: Failed to create session [", get_error_string(result), "]");
  704. return false;
  705. }
  706. set_object_name(XR_OBJECT_TYPE_SESSION, uint64_t(session), "Main Godot OpenXR Session");
  707. begin_debug_label_region("Godot session active");
  708. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  709. wrapper->on_session_created(session);
  710. }
  711. // Check our environment blend mode. This needs to happen after we call `on_session_created()`
  712. // on the extension wrappers, so they can emulate alpha blend mode.
  713. if (!set_environment_blend_mode(environment_blend_mode)) {
  714. print_verbose(String("OpenXR: ") + OpenXRUtil::get_environment_blend_mode_name(environment_blend_mode) + String(" isn't supported, defaulting to ") + OpenXRUtil::get_environment_blend_mode_name(supported_environment_blend_modes[0]));
  715. set_environment_blend_mode(supported_environment_blend_modes[0]);
  716. }
  717. return true;
  718. }
  719. bool OpenXRAPI::load_supported_reference_spaces() {
  720. // loads the supported reference spaces for our OpenXR session
  721. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  722. supported_reference_spaces.clear();
  723. uint32_t num_reference_spaces = 0;
  724. XrResult result = xrEnumerateReferenceSpaces(session, 0, &num_reference_spaces, nullptr);
  725. if (XR_FAILED(result)) {
  726. print_line("OpenXR: Failed to get reference space count [", get_error_string(result), "]");
  727. return false;
  728. }
  729. supported_reference_spaces.resize(num_reference_spaces);
  730. result = xrEnumerateReferenceSpaces(session, num_reference_spaces, &num_reference_spaces, supported_reference_spaces.ptr());
  731. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate reference spaces");
  732. ERR_FAIL_COND_V_MSG(num_reference_spaces == 0, false, "OpenXR: Failed to enumerate reference spaces");
  733. for (const XrReferenceSpaceType &supported_reference_space : supported_reference_spaces) {
  734. print_verbose(vformat("OpenXR: Found supported reference space %s.", OpenXRUtil::get_reference_space_name(supported_reference_space)));
  735. }
  736. return true;
  737. }
  738. bool OpenXRAPI::is_reference_space_supported(XrReferenceSpaceType p_reference_space) {
  739. return supported_reference_spaces.has(p_reference_space);
  740. }
  741. bool OpenXRAPI::setup_play_space() {
  742. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  743. XrPosef identityPose = {
  744. { 0.0, 0.0, 0.0, 1.0 },
  745. { 0.0, 0.0, 0.0 }
  746. };
  747. XrReferenceSpaceType new_reference_space;
  748. XrSpace new_play_space = XR_NULL_HANDLE;
  749. bool will_emulate_local_floor = false;
  750. if (custom_play_space != XR_NULL_HANDLE) {
  751. new_play_space = custom_play_space;
  752. // We use this to mark custom reference spaces.
  753. new_reference_space = XR_REFERENCE_SPACE_TYPE_MAX_ENUM;
  754. } else if (is_reference_space_supported(requested_reference_space)) {
  755. new_reference_space = requested_reference_space;
  756. } else if (requested_reference_space == XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT && is_reference_space_supported(XR_REFERENCE_SPACE_TYPE_STAGE)) {
  757. print_verbose("OpenXR: LOCAL_FLOOR space isn't supported, emulating using STAGE and LOCAL spaces.");
  758. new_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
  759. will_emulate_local_floor = true;
  760. if (local_floor_emulation.local_space == XR_NULL_HANDLE) {
  761. XrReferenceSpaceCreateInfo create_info = {
  762. XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
  763. nullptr, // next
  764. XR_REFERENCE_SPACE_TYPE_LOCAL, // referenceSpaceType
  765. identityPose, // poseInReferenceSpace
  766. };
  767. XrResult result = xrCreateReferenceSpace(session, &create_info, &local_floor_emulation.local_space);
  768. if (XR_FAILED(result)) {
  769. print_line("OpenXR: Failed to create LOCAL space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
  770. will_emulate_local_floor = false;
  771. }
  772. set_object_name(XR_OBJECT_TYPE_SPACE, uint64_t(local_floor_emulation.local_space), "Emulation local space");
  773. }
  774. if (local_floor_emulation.stage_space == XR_NULL_HANDLE) {
  775. XrReferenceSpaceCreateInfo create_info = {
  776. XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
  777. nullptr, // next
  778. XR_REFERENCE_SPACE_TYPE_STAGE, // referenceSpaceType
  779. identityPose, // poseInReferenceSpace
  780. };
  781. XrResult result = xrCreateReferenceSpace(session, &create_info, &local_floor_emulation.stage_space);
  782. if (XR_FAILED(result)) {
  783. print_line("OpenXR: Failed to create STAGE space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
  784. will_emulate_local_floor = false;
  785. }
  786. set_object_name(XR_OBJECT_TYPE_SPACE, uint64_t(local_floor_emulation.stage_space), "Emulation stage space");
  787. }
  788. if (!will_emulate_local_floor) {
  789. if (local_floor_emulation.local_space != XR_NULL_HANDLE) {
  790. xrDestroySpace(local_floor_emulation.local_space);
  791. local_floor_emulation.local_space = XR_NULL_HANDLE;
  792. }
  793. if (local_floor_emulation.stage_space != XR_NULL_HANDLE) {
  794. xrDestroySpace(local_floor_emulation.stage_space);
  795. local_floor_emulation.stage_space = XR_NULL_HANDLE;
  796. }
  797. }
  798. } else {
  799. // Fallback on LOCAL, which all OpenXR runtimes are required to support.
  800. print_verbose(String("OpenXR: ") + OpenXRUtil::get_reference_space_name(requested_reference_space) + String(" isn't supported, defaulting to LOCAL space."));
  801. new_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
  802. }
  803. if (new_play_space == XR_NULL_HANDLE) {
  804. void *next_pointer = nullptr;
  805. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  806. void *np = wrapper->set_reference_space_create_info_and_get_next_pointer(
  807. new_reference_space, next_pointer);
  808. if (np != nullptr) {
  809. next_pointer = np;
  810. }
  811. }
  812. XrReferenceSpaceCreateInfo play_space_create_info = {
  813. XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
  814. next_pointer, // next
  815. new_reference_space, // referenceSpaceType
  816. identityPose, // poseInReferenceSpace
  817. };
  818. XrResult result = xrCreateReferenceSpace(session, &play_space_create_info, &new_play_space);
  819. if (XR_FAILED(result)) {
  820. print_line("OpenXR: Failed to create play space [", get_error_string(result), "]");
  821. return false;
  822. }
  823. }
  824. // If we've previously created a play space, clean it up first.
  825. // But if it was a custom reference space, we don't touch it - it's the job of the extension that
  826. // created it to clean it up.
  827. if (play_space != XR_NULL_HANDLE && reference_space != XR_REFERENCE_SPACE_TYPE_MAX_ENUM) {
  828. // TODO Investigate if destroying our play space here is safe,
  829. // it may still be used in the rendering thread.
  830. xrDestroySpace(play_space);
  831. }
  832. play_space = new_play_space;
  833. reference_space = new_reference_space;
  834. set_object_name(XR_OBJECT_TYPE_SPACE, uint64_t(play_space), "Play space");
  835. local_floor_emulation.enabled = will_emulate_local_floor;
  836. local_floor_emulation.should_reset_floor_height = will_emulate_local_floor;
  837. // Update render state so this play space is used rendering the upcoming frame.
  838. set_render_play_space(play_space);
  839. return true;
  840. }
  841. bool OpenXRAPI::setup_view_space() {
  842. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  843. if (!is_reference_space_supported(XR_REFERENCE_SPACE_TYPE_VIEW)) {
  844. print_line("OpenXR: reference space XR_REFERENCE_SPACE_TYPE_VIEW is not supported.");
  845. return false;
  846. }
  847. XrPosef identityPose = {
  848. { 0.0, 0.0, 0.0, 1.0 },
  849. { 0.0, 0.0, 0.0 }
  850. };
  851. void *next_pointer = nullptr;
  852. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  853. void *np = wrapper->set_reference_space_create_info_and_get_next_pointer(XR_REFERENCE_SPACE_TYPE_VIEW, next_pointer);
  854. if (np != nullptr) {
  855. next_pointer = np;
  856. }
  857. }
  858. XrReferenceSpaceCreateInfo view_space_create_info = {
  859. XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
  860. next_pointer, // next
  861. XR_REFERENCE_SPACE_TYPE_VIEW, // referenceSpaceType
  862. identityPose // poseInReferenceSpace
  863. };
  864. XrResult result = xrCreateReferenceSpace(session, &view_space_create_info, &view_space);
  865. if (XR_FAILED(result)) {
  866. print_line("OpenXR: Failed to create view space [", get_error_string(result), "]");
  867. return false;
  868. }
  869. set_object_name(XR_OBJECT_TYPE_SPACE, uint64_t(view_space), "View space");
  870. return true;
  871. }
  872. bool OpenXRAPI::reset_emulated_floor_height() {
  873. ERR_FAIL_COND_V(!local_floor_emulation.enabled, false);
  874. ERR_FAIL_COND_V(local_floor_emulation.local_space == XR_NULL_HANDLE, false);
  875. ERR_FAIL_COND_V(local_floor_emulation.stage_space == XR_NULL_HANDLE, false);
  876. XrResult result;
  877. XrSpaceLocation stage_location = {
  878. XR_TYPE_SPACE_LOCATION, // type
  879. nullptr, // next
  880. 0, // locationFlags
  881. { { 0.0, 0.0, 0.0, 1.0 }, { 0.0, 0.0, 0.0 } }, // pose
  882. };
  883. result = xrLocateSpace(local_floor_emulation.stage_space, local_floor_emulation.local_space, get_predicted_display_time(), &stage_location);
  884. if (XR_FAILED(result)) {
  885. print_line("OpenXR: Failed to locate STAGE space in LOCAL space, in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
  886. return false;
  887. }
  888. XrPosef pose = {
  889. { 0.0, 0.0, 0.0, 1.0 },
  890. { 0.0, stage_location.pose.position.y, 0.0 }
  891. };
  892. XrReferenceSpaceCreateInfo create_info = {
  893. XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
  894. nullptr, // next
  895. XR_REFERENCE_SPACE_TYPE_LOCAL, // referenceSpaceType
  896. pose, // poseInReferenceSpace
  897. };
  898. XrSpace new_play_space;
  899. void *next_pointer = nullptr;
  900. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  901. void *np = wrapper->set_reference_space_create_info_and_get_next_pointer(
  902. create_info.referenceSpaceType, next_pointer);
  903. if (np != nullptr) {
  904. next_pointer = np;
  905. }
  906. }
  907. create_info.next = next_pointer;
  908. result = xrCreateReferenceSpace(session, &create_info, &new_play_space);
  909. if (XR_FAILED(result)) {
  910. print_line("OpenXR: Failed to recreate emulated LOCAL_FLOOR play space with latest floor estimate [", get_error_string(result), "]");
  911. return false;
  912. }
  913. xrDestroySpace(play_space);
  914. play_space = new_play_space;
  915. // If we've made it this far, it means we can properly emulate LOCAL_FLOOR, so we'll
  916. // report that as the reference space to the outside world.
  917. reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
  918. // Update render state so this play space is used rendering the upcoming frame.
  919. set_render_play_space(play_space);
  920. return true;
  921. }
  922. bool OpenXRAPI::load_supported_swapchain_formats() {
  923. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  924. supported_swapchain_formats.clear();
  925. uint32_t num_swapchain_formats = 0;
  926. XrResult result = xrEnumerateSwapchainFormats(session, 0, &num_swapchain_formats, nullptr);
  927. if (XR_FAILED(result)) {
  928. print_line("OpenXR: Failed to get swapchain format count [", get_error_string(result), "]");
  929. return false;
  930. }
  931. supported_swapchain_formats.resize(num_swapchain_formats);
  932. result = xrEnumerateSwapchainFormats(session, num_swapchain_formats, &num_swapchain_formats, supported_swapchain_formats.ptrw());
  933. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate swapchain formats");
  934. for (int64_t swapchain_format : supported_swapchain_formats) {
  935. print_verbose(String("OpenXR: Found supported swapchain format ") + get_swapchain_format_name(swapchain_format));
  936. }
  937. return true;
  938. }
  939. bool OpenXRAPI::is_swapchain_format_supported(int64_t p_swapchain_format) {
  940. return supported_swapchain_formats.has(p_swapchain_format);
  941. }
  942. bool OpenXRAPI::obtain_swapchain_formats() {
  943. ERR_FAIL_NULL_V(graphics_extension, false);
  944. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  945. {
  946. // Build a vector with swapchain formats we want to use, from best fit to worst
  947. Vector<int64_t> usable_swapchain_formats;
  948. color_swapchain_format = 0;
  949. graphics_extension->get_usable_swapchain_formats(usable_swapchain_formats);
  950. // now find out which one is supported
  951. for (int i = 0; i < usable_swapchain_formats.size() && color_swapchain_format == 0; i++) {
  952. if (is_swapchain_format_supported(usable_swapchain_formats[i])) {
  953. color_swapchain_format = usable_swapchain_formats[i];
  954. }
  955. }
  956. ERR_FAIL_COND_V_MSG(color_swapchain_format == 0, false, "OpenXR: No usable color swap chain format available!");
  957. print_verbose(String("Using color swap chain format:") + get_swapchain_format_name(color_swapchain_format));
  958. }
  959. {
  960. // Build a vector with swapchain formats we want to use, from best fit to worst
  961. Vector<int64_t> usable_swapchain_formats;
  962. depth_swapchain_format = 0;
  963. graphics_extension->get_usable_depth_formats(usable_swapchain_formats);
  964. // now find out which one is supported
  965. for (int i = 0; i < usable_swapchain_formats.size() && depth_swapchain_format == 0; i++) {
  966. if (is_swapchain_format_supported(usable_swapchain_formats[i])) {
  967. depth_swapchain_format = usable_swapchain_formats[i];
  968. }
  969. }
  970. ERR_FAIL_COND_V_MSG(depth_swapchain_format == 0, false, "OpenXR: No usable depth swap chain format available!");
  971. print_verbose(String("Using depth swap chain format:") + get_swapchain_format_name(depth_swapchain_format));
  972. }
  973. return true;
  974. }
  975. bool OpenXRAPI::create_main_swapchains(Size2i p_size) {
  976. ERR_NOT_ON_RENDER_THREAD_V(false);
  977. ERR_FAIL_NULL_V(graphics_extension, false);
  978. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  979. /*
  980. TODO: We need to improve on this, for now we're taking our old approach of creating our main swapchains and substituting
  981. those for the ones Godot normally creates.
  982. This however means we can only use swapchains for our main XR view.
  983. It would have been nicer if we could override the swapchain creation in Godot with ours but we have a timing issue here.
  984. We can't create XR swapchains until after our XR session is fully instantiated, yet Godot creates its swapchain much earlier.
  985. We only creates a swapchain for the main output here.
  986. Additional swapchains may be created through our composition layer extension.
  987. Finally an area we need to expand upon is that Foveated rendering is only enabled for the swap chain we create,
  988. as we render 3D content into internal buffers that are copied into the swapchain, we do now have (basic) VRS support
  989. */
  990. render_state.main_swapchain_size = p_size;
  991. uint32_t sample_count = 1;
  992. // We start with our color swapchain...
  993. if (color_swapchain_format != 0) {
  994. if (!render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].create(0, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, color_swapchain_format, render_state.main_swapchain_size.width, render_state.main_swapchain_size.height, sample_count, view_configuration_views.size())) {
  995. return false;
  996. }
  997. set_object_name(XR_OBJECT_TYPE_SWAPCHAIN, uint64_t(render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_swapchain()), "Main color swapchain");
  998. }
  999. // We create our depth swapchain if:
  1000. // - we've enabled submitting depth buffer
  1001. // - we support our depth layer extension
  1002. // - we have our spacewarp extension (not yet implemented)
  1003. if (depth_swapchain_format != 0 && submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) {
  1004. if (!render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].create(0, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, depth_swapchain_format, render_state.main_swapchain_size.width, render_state.main_swapchain_size.height, sample_count, view_configuration_views.size())) {
  1005. return false;
  1006. }
  1007. set_object_name(XR_OBJECT_TYPE_SWAPCHAIN, uint64_t(render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].get_swapchain()), "Main depth swapchain");
  1008. }
  1009. // We create our velocity swapchain if:
  1010. // - we have our spacewarp extension (not yet implemented)
  1011. {
  1012. // TBD
  1013. }
  1014. for (uint32_t i = 0; i < render_state.views.size(); i++) {
  1015. render_state.views[i].type = XR_TYPE_VIEW;
  1016. render_state.views[i].next = nullptr;
  1017. render_state.projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
  1018. render_state.projection_views[i].next = nullptr;
  1019. render_state.projection_views[i].subImage.swapchain = render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_swapchain();
  1020. render_state.projection_views[i].subImage.imageArrayIndex = i;
  1021. render_state.projection_views[i].subImage.imageRect.offset.x = 0;
  1022. render_state.projection_views[i].subImage.imageRect.offset.y = 0;
  1023. render_state.projection_views[i].subImage.imageRect.extent.width = render_state.main_swapchain_size.width;
  1024. render_state.projection_views[i].subImage.imageRect.extent.height = render_state.main_swapchain_size.height;
  1025. if (render_state.submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available() && !render_state.depth_views.is_empty()) {
  1026. render_state.projection_views[i].next = &render_state.depth_views[i];
  1027. render_state.depth_views[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR;
  1028. render_state.depth_views[i].next = nullptr;
  1029. render_state.depth_views[i].subImage.swapchain = render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].get_swapchain();
  1030. render_state.depth_views[i].subImage.imageArrayIndex = i;
  1031. render_state.depth_views[i].subImage.imageRect.offset.x = 0;
  1032. render_state.depth_views[i].subImage.imageRect.offset.y = 0;
  1033. render_state.depth_views[i].subImage.imageRect.extent.width = render_state.main_swapchain_size.width;
  1034. render_state.depth_views[i].subImage.imageRect.extent.height = render_state.main_swapchain_size.height;
  1035. // OpenXR spec says that: minDepth < maxDepth.
  1036. render_state.depth_views[i].minDepth = 0.0;
  1037. render_state.depth_views[i].maxDepth = 1.0;
  1038. // But we can reverse near and far for reverse-Z.
  1039. render_state.depth_views[i].nearZ = 100.0; // Near and far Z will be set to the correct values in fill_projection_matrix
  1040. render_state.depth_views[i].farZ = 0.01;
  1041. }
  1042. };
  1043. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1044. wrapper->on_main_swapchains_created();
  1045. }
  1046. return true;
  1047. }
  1048. void OpenXRAPI::destroy_session() {
  1049. // TODO need to figure out if we're still rendering our current frame
  1050. // in a separate rendering thread and if so,
  1051. // if we need to wait for completion.
  1052. // We could be pulling the rug from underneath rendering...
  1053. if (running) {
  1054. if (session != XR_NULL_HANDLE) {
  1055. xrEndSession(session);
  1056. }
  1057. running = false;
  1058. render_state.running = false;
  1059. }
  1060. render_state.views.clear();
  1061. render_state.projection_views.clear();
  1062. render_state.depth_views.clear();
  1063. free_main_swapchains();
  1064. OpenXRSwapChainInfo::free_queued();
  1065. supported_swapchain_formats.clear();
  1066. // destroy our spaces
  1067. if (play_space != XR_NULL_HANDLE) {
  1068. xrDestroySpace(play_space);
  1069. play_space = XR_NULL_HANDLE;
  1070. render_state.play_space = XR_NULL_HANDLE;
  1071. }
  1072. if (view_space != XR_NULL_HANDLE) {
  1073. xrDestroySpace(view_space);
  1074. view_space = XR_NULL_HANDLE;
  1075. }
  1076. if (local_floor_emulation.local_space != XR_NULL_HANDLE) {
  1077. xrDestroySpace(local_floor_emulation.local_space);
  1078. local_floor_emulation.local_space = XR_NULL_HANDLE;
  1079. }
  1080. if (local_floor_emulation.stage_space != XR_NULL_HANDLE) {
  1081. xrDestroySpace(local_floor_emulation.stage_space);
  1082. local_floor_emulation.stage_space = XR_NULL_HANDLE;
  1083. }
  1084. local_floor_emulation.enabled = false;
  1085. local_floor_emulation.should_reset_floor_height = false;
  1086. supported_reference_spaces.clear();
  1087. if (session != XR_NULL_HANDLE) {
  1088. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1089. wrapper->on_session_destroyed();
  1090. }
  1091. end_debug_label_region();
  1092. xrDestroySession(session);
  1093. session = XR_NULL_HANDLE;
  1094. }
  1095. }
  1096. bool OpenXRAPI::on_state_idle() {
  1097. print_verbose("On state idle");
  1098. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1099. wrapper->on_state_idle();
  1100. }
  1101. return true;
  1102. }
  1103. bool OpenXRAPI::on_state_ready() {
  1104. print_verbose("On state ready");
  1105. // begin session
  1106. XrSessionBeginInfo session_begin_info = {
  1107. XR_TYPE_SESSION_BEGIN_INFO, // type
  1108. nullptr, // next
  1109. view_configuration // primaryViewConfigurationType
  1110. };
  1111. XrResult result = xrBeginSession(session, &session_begin_info);
  1112. if (XR_FAILED(result)) {
  1113. print_line("OpenXR: Failed to begin session [", get_error_string(result), "]");
  1114. return false;
  1115. }
  1116. // we're running
  1117. running = true;
  1118. set_render_session_running(true);
  1119. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1120. wrapper->on_state_ready();
  1121. }
  1122. if (xr_interface) {
  1123. xr_interface->on_state_ready();
  1124. }
  1125. return true;
  1126. }
  1127. bool OpenXRAPI::on_state_synchronized() {
  1128. print_verbose("On state synchronized");
  1129. // Just in case, see if we already have active trackers...
  1130. List<RID> trackers;
  1131. tracker_owner.get_owned_list(&trackers);
  1132. for (const RID &tracker : trackers) {
  1133. tracker_check_profile(tracker);
  1134. }
  1135. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1136. wrapper->on_state_synchronized();
  1137. }
  1138. return true;
  1139. }
  1140. bool OpenXRAPI::on_state_visible() {
  1141. print_verbose("On state visible");
  1142. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1143. wrapper->on_state_visible();
  1144. }
  1145. if (xr_interface) {
  1146. xr_interface->on_state_visible();
  1147. }
  1148. return true;
  1149. }
  1150. bool OpenXRAPI::on_state_focused() {
  1151. print_verbose("On state focused");
  1152. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1153. wrapper->on_state_focused();
  1154. }
  1155. if (xr_interface) {
  1156. xr_interface->on_state_focused();
  1157. }
  1158. return true;
  1159. }
  1160. bool OpenXRAPI::on_state_stopping() {
  1161. print_verbose("On state stopping");
  1162. if (xr_interface) {
  1163. xr_interface->on_state_stopping();
  1164. }
  1165. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1166. wrapper->on_state_stopping();
  1167. }
  1168. if (running) {
  1169. XrResult result = xrEndSession(session);
  1170. if (XR_FAILED(result)) {
  1171. // we only report this..
  1172. print_line("OpenXR: Failed to end session [", get_error_string(result), "]");
  1173. }
  1174. running = false;
  1175. set_render_session_running(false);
  1176. }
  1177. return true;
  1178. }
  1179. bool OpenXRAPI::on_state_loss_pending() {
  1180. print_verbose("On state loss pending");
  1181. if (xr_interface) {
  1182. xr_interface->on_state_loss_pending();
  1183. }
  1184. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1185. wrapper->on_state_loss_pending();
  1186. }
  1187. return true;
  1188. }
  1189. bool OpenXRAPI::on_state_exiting() {
  1190. print_verbose("On state existing");
  1191. if (xr_interface) {
  1192. xr_interface->on_state_exiting();
  1193. }
  1194. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1195. wrapper->on_state_exiting();
  1196. }
  1197. return true;
  1198. }
  1199. void OpenXRAPI::set_form_factor(XrFormFactor p_form_factor) {
  1200. ERR_FAIL_COND(is_initialized());
  1201. form_factor = p_form_factor;
  1202. }
  1203. uint32_t OpenXRAPI::get_view_count() {
  1204. return view_configuration_views.size();
  1205. }
  1206. void OpenXRAPI::set_view_configuration(XrViewConfigurationType p_view_configuration) {
  1207. ERR_FAIL_COND(is_initialized());
  1208. view_configuration = p_view_configuration;
  1209. }
  1210. bool OpenXRAPI::set_requested_reference_space(XrReferenceSpaceType p_requested_reference_space) {
  1211. if (custom_play_space != XR_NULL_HANDLE) {
  1212. return false;
  1213. }
  1214. requested_reference_space = p_requested_reference_space;
  1215. play_space_is_dirty = true;
  1216. return true;
  1217. }
  1218. void OpenXRAPI::set_custom_play_space(XrSpace p_custom_space) {
  1219. custom_play_space = p_custom_space;
  1220. play_space_is_dirty = true;
  1221. }
  1222. void OpenXRAPI::set_submit_depth_buffer(bool p_submit_depth_buffer) {
  1223. ERR_FAIL_COND(is_initialized());
  1224. submit_depth_buffer = p_submit_depth_buffer;
  1225. }
  1226. bool OpenXRAPI::is_initialized() {
  1227. return (instance != XR_NULL_HANDLE);
  1228. }
  1229. bool OpenXRAPI::is_running() {
  1230. if (instance == XR_NULL_HANDLE) {
  1231. return false;
  1232. }
  1233. if (session == XR_NULL_HANDLE) {
  1234. return false;
  1235. }
  1236. return running;
  1237. }
  1238. bool OpenXRAPI::openxr_loader_init() {
  1239. #ifdef ANDROID_ENABLED
  1240. ERR_FAIL_COND_V_MSG(openxr_loader_library_handle != nullptr, false, "OpenXR Loader library is already loaded.");
  1241. {
  1242. Error error_code = OS::get_singleton()->open_dynamic_library(OPENXR_LOADER_NAME, openxr_loader_library_handle);
  1243. ERR_FAIL_COND_V_MSG(error_code != OK, false, "OpenXR loader not found.");
  1244. }
  1245. {
  1246. Error error_code = OS::get_singleton()->get_dynamic_library_symbol_handle(openxr_loader_library_handle, "xrGetInstanceProcAddr", (void *&)xrGetInstanceProcAddr);
  1247. ERR_FAIL_COND_V_MSG(error_code != OK, false, "Symbol xrGetInstanceProcAddr not found in OpenXR Loader library.");
  1248. }
  1249. #endif
  1250. // Resolve the symbols that don't require an instance
  1251. OPENXR_API_INIT_XR_FUNC_V(xrCreateInstance);
  1252. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateApiLayerProperties);
  1253. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateInstanceExtensionProperties);
  1254. return true;
  1255. }
  1256. bool OpenXRAPI::resolve_instance_openxr_symbols() {
  1257. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  1258. OPENXR_API_INIT_XR_FUNC_V(xrAcquireSwapchainImage);
  1259. OPENXR_API_INIT_XR_FUNC_V(xrApplyHapticFeedback);
  1260. OPENXR_API_INIT_XR_FUNC_V(xrAttachSessionActionSets);
  1261. OPENXR_API_INIT_XR_FUNC_V(xrBeginFrame);
  1262. OPENXR_API_INIT_XR_FUNC_V(xrBeginSession);
  1263. OPENXR_API_INIT_XR_FUNC_V(xrCreateAction);
  1264. OPENXR_API_INIT_XR_FUNC_V(xrCreateActionSet);
  1265. OPENXR_API_INIT_XR_FUNC_V(xrCreateActionSpace);
  1266. OPENXR_API_INIT_XR_FUNC_V(xrCreateReferenceSpace);
  1267. OPENXR_API_INIT_XR_FUNC_V(xrCreateSession);
  1268. OPENXR_API_INIT_XR_FUNC_V(xrCreateSwapchain);
  1269. OPENXR_API_INIT_XR_FUNC_V(xrDestroyAction);
  1270. OPENXR_API_INIT_XR_FUNC_V(xrDestroyActionSet);
  1271. OPENXR_API_INIT_XR_FUNC_V(xrDestroyInstance);
  1272. OPENXR_API_INIT_XR_FUNC_V(xrDestroySession);
  1273. OPENXR_API_INIT_XR_FUNC_V(xrDestroySpace);
  1274. OPENXR_API_INIT_XR_FUNC_V(xrDestroySwapchain);
  1275. OPENXR_API_INIT_XR_FUNC_V(xrEndFrame);
  1276. OPENXR_API_INIT_XR_FUNC_V(xrEndSession);
  1277. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateEnvironmentBlendModes);
  1278. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateReferenceSpaces);
  1279. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateSwapchainFormats);
  1280. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateViewConfigurations);
  1281. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateViewConfigurationViews);
  1282. OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateBoolean);
  1283. OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateFloat);
  1284. OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateVector2f);
  1285. OPENXR_API_INIT_XR_FUNC_V(xrGetCurrentInteractionProfile);
  1286. OPENXR_API_INIT_XR_FUNC_V(xrGetReferenceSpaceBoundsRect);
  1287. OPENXR_API_INIT_XR_FUNC_V(xrGetSystem);
  1288. OPENXR_API_INIT_XR_FUNC_V(xrGetSystemProperties);
  1289. OPENXR_API_INIT_XR_FUNC_V(xrLocateViews);
  1290. OPENXR_API_INIT_XR_FUNC_V(xrLocateSpace);
  1291. OPENXR_API_INIT_XR_FUNC_V(xrPathToString);
  1292. OPENXR_API_INIT_XR_FUNC_V(xrPollEvent);
  1293. OPENXR_API_INIT_XR_FUNC_V(xrReleaseSwapchainImage);
  1294. OPENXR_API_INIT_XR_FUNC_V(xrResultToString);
  1295. OPENXR_API_INIT_XR_FUNC_V(xrStringToPath);
  1296. OPENXR_API_INIT_XR_FUNC_V(xrSuggestInteractionProfileBindings);
  1297. OPENXR_API_INIT_XR_FUNC_V(xrSyncActions);
  1298. OPENXR_API_INIT_XR_FUNC_V(xrWaitFrame);
  1299. OPENXR_API_INIT_XR_FUNC_V(xrWaitSwapchainImage);
  1300. return true;
  1301. }
  1302. XrResult OpenXRAPI::try_get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr) {
  1303. return xrGetInstanceProcAddr(instance, p_name, p_addr);
  1304. }
  1305. XrResult OpenXRAPI::get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr) {
  1306. XrResult result = try_get_instance_proc_addr(p_name, p_addr);
  1307. if (result != XR_SUCCESS) {
  1308. String error_message = String("Symbol ") + p_name + " not found in OpenXR instance.";
  1309. ERR_FAIL_V_MSG(result, error_message.utf8().get_data());
  1310. }
  1311. return result;
  1312. }
  1313. bool OpenXRAPI::initialize(const String &p_rendering_driver) {
  1314. ERR_FAIL_COND_V_MSG(instance != XR_NULL_HANDLE, false, "OpenXR instance was already created");
  1315. if (!openxr_loader_init()) {
  1316. return false;
  1317. }
  1318. if (p_rendering_driver == "vulkan") {
  1319. #ifdef VULKAN_ENABLED
  1320. graphics_extension = memnew(OpenXRVulkanExtension);
  1321. register_extension_wrapper(graphics_extension);
  1322. #else
  1323. // shouldn't be possible...
  1324. ERR_FAIL_V(false);
  1325. #endif
  1326. } else if (p_rendering_driver == "metal") {
  1327. #ifdef METAL_ENABLED
  1328. graphics_extension = memnew(OpenXRMetalExtension);
  1329. register_extension_wrapper(graphics_extension);
  1330. #else
  1331. // shouldn't be possible...
  1332. ERR_FAIL_V(false);
  1333. #endif
  1334. } else if (p_rendering_driver == "opengl3") {
  1335. #if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
  1336. graphics_extension = memnew(OpenXROpenGLExtension);
  1337. register_extension_wrapper(graphics_extension);
  1338. #else
  1339. // shouldn't be possible...
  1340. ERR_FAIL_V(false);
  1341. #endif
  1342. } else if (p_rendering_driver == "d3d12") {
  1343. #ifdef D3D12_ENABLED
  1344. graphics_extension = memnew(OpenXRD3D12Extension);
  1345. register_extension_wrapper(graphics_extension);
  1346. #else
  1347. // shouldn't be possible...
  1348. ERR_FAIL_V(false);
  1349. #endif
  1350. } else {
  1351. ERR_FAIL_V_MSG(false, "OpenXR: Unsupported rendering device.");
  1352. }
  1353. // Also register our rendering extensions
  1354. register_extension_wrapper(memnew(OpenXRFBUpdateSwapchainExtension(p_rendering_driver)));
  1355. register_extension_wrapper(memnew(OpenXRFBFoveationExtension(p_rendering_driver)));
  1356. // initialize
  1357. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1358. wrapper->on_before_instance_created();
  1359. }
  1360. if (!load_layer_properties()) {
  1361. destroy_instance();
  1362. return false;
  1363. }
  1364. if (!load_supported_extensions()) {
  1365. destroy_instance();
  1366. return false;
  1367. }
  1368. if (!create_instance()) {
  1369. destroy_instance();
  1370. return false;
  1371. }
  1372. if (!resolve_instance_openxr_symbols()) {
  1373. destroy_instance();
  1374. return false;
  1375. }
  1376. if (!get_system_info()) {
  1377. destroy_instance();
  1378. return false;
  1379. }
  1380. if (!load_supported_view_configuration_types()) {
  1381. destroy_instance();
  1382. return false;
  1383. }
  1384. if (!load_supported_view_configuration_views(view_configuration)) {
  1385. destroy_instance();
  1386. return false;
  1387. }
  1388. if (!load_supported_environmental_blend_modes()) {
  1389. destroy_instance();
  1390. return false;
  1391. }
  1392. return true;
  1393. }
  1394. bool OpenXRAPI::initialize_session() {
  1395. if (!create_session()) {
  1396. destroy_session();
  1397. return false;
  1398. }
  1399. if (!load_supported_reference_spaces()) {
  1400. destroy_session();
  1401. return false;
  1402. }
  1403. if (!setup_view_space()) {
  1404. destroy_session();
  1405. return false;
  1406. }
  1407. if (!load_supported_swapchain_formats()) {
  1408. destroy_session();
  1409. return false;
  1410. }
  1411. if (!obtain_swapchain_formats()) {
  1412. destroy_session();
  1413. return false;
  1414. }
  1415. allocate_view_buffers(view_configuration_views.size(), submit_depth_buffer);
  1416. return true;
  1417. }
  1418. void OpenXRAPI::finish() {
  1419. destroy_session();
  1420. destroy_instance();
  1421. }
  1422. void OpenXRAPI::set_xr_interface(OpenXRInterface *p_xr_interface) {
  1423. xr_interface = p_xr_interface;
  1424. }
  1425. void OpenXRAPI::register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) {
  1426. registered_extension_wrappers.push_back(p_extension_wrapper);
  1427. }
  1428. void OpenXRAPI::unregister_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) {
  1429. registered_extension_wrappers.erase(p_extension_wrapper);
  1430. }
  1431. const Vector<OpenXRExtensionWrapper *> &OpenXRAPI::get_registered_extension_wrappers() {
  1432. return registered_extension_wrappers;
  1433. }
  1434. void OpenXRAPI::register_extension_metadata() {
  1435. for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) {
  1436. extension_wrapper->on_register_metadata();
  1437. }
  1438. }
  1439. void OpenXRAPI::cleanup_extension_wrappers() {
  1440. for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) {
  1441. #ifndef DISABLE_DEPRECATED
  1442. // Fix crash when the extension wrapper comes from GDExtension.
  1443. OpenXRExtensionWrapperExtension *gdextension_extension_wrapper = dynamic_cast<OpenXRExtensionWrapperExtension *>(extension_wrapper);
  1444. if (gdextension_extension_wrapper) {
  1445. memdelete(gdextension_extension_wrapper);
  1446. } else
  1447. #endif
  1448. {
  1449. memdelete(extension_wrapper);
  1450. }
  1451. }
  1452. registered_extension_wrappers.clear();
  1453. }
  1454. XrHandTrackerEXT OpenXRAPI::get_hand_tracker(int p_hand_index) {
  1455. ERR_FAIL_INDEX_V(p_hand_index, OpenXRHandTrackingExtension::HandTrackedHands::OPENXR_MAX_TRACKED_HANDS, XR_NULL_HANDLE);
  1456. OpenXRHandTrackingExtension *hand_tracking = OpenXRHandTrackingExtension::get_singleton();
  1457. ERR_FAIL_NULL_V(hand_tracking, XR_NULL_HANDLE);
  1458. OpenXRHandTrackingExtension::HandTrackedHands hand = static_cast<OpenXRHandTrackingExtension::HandTrackedHands>(p_hand_index);
  1459. return hand_tracking->get_hand_tracker(hand)->hand_tracker;
  1460. }
  1461. Size2 OpenXRAPI::get_recommended_target_size() {
  1462. RenderingServer *rendering_server = RenderingServer::get_singleton();
  1463. ERR_FAIL_COND_V(view_configuration_views.is_empty(), Size2());
  1464. Size2 target_size;
  1465. if (rendering_server && rendering_server->is_on_render_thread()) {
  1466. target_size.width = view_configuration_views[0].recommendedImageRectWidth * render_state.render_target_size_multiplier;
  1467. target_size.height = view_configuration_views[0].recommendedImageRectHeight * render_state.render_target_size_multiplier;
  1468. } else {
  1469. target_size.width = view_configuration_views[0].recommendedImageRectWidth * render_target_size_multiplier;
  1470. target_size.height = view_configuration_views[0].recommendedImageRectHeight * render_target_size_multiplier;
  1471. }
  1472. return target_size;
  1473. }
  1474. XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
  1475. XrResult result;
  1476. if (!running) {
  1477. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  1478. }
  1479. // Get display time
  1480. XrTime display_time = get_predicted_display_time();
  1481. if (display_time == 0) {
  1482. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  1483. }
  1484. XrSpaceVelocity velocity = {
  1485. XR_TYPE_SPACE_VELOCITY, // type
  1486. nullptr, // next
  1487. 0, // velocityFlags
  1488. { 0.0, 0.0, 0.0 }, // linearVelocity
  1489. { 0.0, 0.0, 0.0 } // angularVelocity
  1490. };
  1491. XrSpaceLocation location = {
  1492. XR_TYPE_SPACE_LOCATION, // type
  1493. &velocity, // next
  1494. 0, // locationFlags
  1495. {
  1496. { 0.0, 0.0, 0.0, 0.0 }, // orientation
  1497. { 0.0, 0.0, 0.0 } // position
  1498. } // pose
  1499. };
  1500. result = xrLocateSpace(view_space, play_space, display_time, &location);
  1501. if (XR_FAILED(result)) {
  1502. print_line("OpenXR: Failed to locate view space in play space [", get_error_string(result), "]");
  1503. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  1504. }
  1505. XRPose::TrackingConfidence confidence = transform_from_location(location, r_transform);
  1506. parse_velocities(velocity, r_linear_velocity, r_angular_velocity);
  1507. if (head_pose_confidence != confidence) {
  1508. // prevent error spam
  1509. head_pose_confidence = confidence;
  1510. if (head_pose_confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) {
  1511. print_line("OpenXR head space location not valid (check tracking?)");
  1512. } else if (head_pose_confidence == XRPose::XR_TRACKING_CONFIDENCE_LOW) {
  1513. print_verbose("OpenVR Head pose now tracking with low confidence");
  1514. } else {
  1515. print_verbose("OpenVR Head pose now tracking with high confidence");
  1516. }
  1517. }
  1518. return confidence;
  1519. }
  1520. bool OpenXRAPI::get_view_transform(uint32_t p_view, Transform3D &r_transform) {
  1521. ERR_NOT_ON_RENDER_THREAD_V(false);
  1522. if (!render_state.running) {
  1523. return false;
  1524. }
  1525. // we don't have valid view info
  1526. if (render_state.views.is_empty() || !render_state.view_pose_valid) {
  1527. return false;
  1528. }
  1529. // Note, the timing of this is set right before rendering, which is what we need here.
  1530. r_transform = transform_from_pose(render_state.views[p_view].pose);
  1531. return true;
  1532. }
  1533. bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, Projection &p_camera_matrix) {
  1534. ERR_NOT_ON_RENDER_THREAD_V(false);
  1535. ERR_FAIL_NULL_V(graphics_extension, false);
  1536. if (!render_state.running) {
  1537. return false;
  1538. }
  1539. // we don't have valid view info
  1540. if (render_state.views.is_empty() || !render_state.view_pose_valid) {
  1541. return false;
  1542. }
  1543. // if we're using depth views, make sure we update our near and far there...
  1544. if (!render_state.depth_views.is_empty()) {
  1545. for (XrCompositionLayerDepthInfoKHR &depth_view : render_state.depth_views) {
  1546. // As we are using reverse-Z these need to be flipped.
  1547. depth_view.nearZ = p_z_far;
  1548. depth_view.farZ = p_z_near;
  1549. }
  1550. }
  1551. render_state.z_near = p_z_near;
  1552. render_state.z_far = p_z_far;
  1553. // now update our projection
  1554. return graphics_extension->create_projection_fov(render_state.views[p_view].fov, p_z_near, p_z_far, p_camera_matrix);
  1555. }
  1556. Vector2 OpenXRAPI::get_eye_focus(uint32_t p_view, float p_aspect) {
  1557. ERR_FAIL_NULL_V(graphics_extension, Vector2());
  1558. if (!render_state.running) {
  1559. return Vector2();
  1560. }
  1561. // xrWaitFrame not run yet
  1562. if (render_state.predicted_display_time == 0) {
  1563. return Vector2();
  1564. }
  1565. // we don't have valid view info
  1566. if (render_state.views.is_empty() || !render_state.view_pose_valid) {
  1567. return Vector2();
  1568. }
  1569. Projection cm;
  1570. if (!graphics_extension->create_projection_fov(render_state.views[p_view].fov, 0.1, 1000.0, cm)) {
  1571. return Vector2();
  1572. }
  1573. // Default focus to center...
  1574. Vector3 focus = cm.xform(Vector3(0.0, 0.0, 999.9));
  1575. // Lets check for eye tracking...
  1576. OpenXREyeGazeInteractionExtension *eye_gaze_interaction = OpenXREyeGazeInteractionExtension::get_singleton();
  1577. if (eye_gaze_interaction && eye_gaze_interaction->supports_eye_gaze_interaction()) {
  1578. Vector3 eye_gaze_pose;
  1579. if (eye_gaze_interaction->get_eye_gaze_pose(1.0, eye_gaze_pose)) {
  1580. Transform3D view_transform = transform_from_pose(render_state.views[p_view].pose);
  1581. eye_gaze_pose = view_transform.xform_inv(eye_gaze_pose);
  1582. focus = cm.xform(eye_gaze_pose);
  1583. }
  1584. }
  1585. return Vector2(focus.x, focus.y);
  1586. }
  1587. bool OpenXRAPI::poll_events() {
  1588. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  1589. XrEventDataBuffer runtimeEvent;
  1590. runtimeEvent.type = XR_TYPE_EVENT_DATA_BUFFER;
  1591. runtimeEvent.next = nullptr;
  1592. // runtimeEvent.varying = ...
  1593. XrResult pollResult = xrPollEvent(instance, &runtimeEvent);
  1594. while (pollResult == XR_SUCCESS) {
  1595. bool handled = false;
  1596. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1597. handled |= wrapper->on_event_polled(runtimeEvent);
  1598. }
  1599. switch (runtimeEvent.type) {
  1600. case XR_TYPE_EVENT_DATA_EVENTS_LOST: {
  1601. XrEventDataEventsLost *event = (XrEventDataEventsLost *)&runtimeEvent;
  1602. // We probably didn't poll fast enough, just output warning
  1603. WARN_PRINT("OpenXR EVENT: " + itos(event->lostEventCount) + " event data lost!");
  1604. } break;
  1605. case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: {
  1606. XrEventDataInstanceLossPending *event = (XrEventDataInstanceLossPending *)&runtimeEvent;
  1607. // TODO We get this event if we're about to loose our OpenXR instance.
  1608. // We should queue exiting Godot at this point.
  1609. print_verbose(String("OpenXR EVENT: instance loss pending at ") + itos(event->lossTime));
  1610. return false;
  1611. } break;
  1612. case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: {
  1613. XrEventDataSessionStateChanged *event = (XrEventDataSessionStateChanged *)&runtimeEvent;
  1614. session_state = event->state;
  1615. if (session_state >= XR_SESSION_STATE_MAX_ENUM) {
  1616. print_verbose(String("OpenXR EVENT: session state changed to UNKNOWN - ") + itos(session_state));
  1617. } else {
  1618. print_verbose(String("OpenXR EVENT: session state changed to ") + OpenXRUtil::get_session_state_name(session_state));
  1619. switch (session_state) {
  1620. case XR_SESSION_STATE_IDLE:
  1621. on_state_idle();
  1622. break;
  1623. case XR_SESSION_STATE_READY:
  1624. on_state_ready();
  1625. break;
  1626. case XR_SESSION_STATE_SYNCHRONIZED:
  1627. on_state_synchronized();
  1628. break;
  1629. case XR_SESSION_STATE_VISIBLE:
  1630. on_state_visible();
  1631. break;
  1632. case XR_SESSION_STATE_FOCUSED:
  1633. on_state_focused();
  1634. break;
  1635. case XR_SESSION_STATE_STOPPING:
  1636. on_state_stopping();
  1637. break;
  1638. case XR_SESSION_STATE_LOSS_PENDING:
  1639. on_state_loss_pending();
  1640. break;
  1641. case XR_SESSION_STATE_EXITING:
  1642. on_state_exiting();
  1643. break;
  1644. default:
  1645. break;
  1646. }
  1647. }
  1648. } break;
  1649. case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING: {
  1650. XrEventDataReferenceSpaceChangePending *event = (XrEventDataReferenceSpaceChangePending *)&runtimeEvent;
  1651. print_verbose(String("OpenXR EVENT: reference space type ") + OpenXRUtil::get_reference_space_name(event->referenceSpaceType) + " change pending!");
  1652. if (local_floor_emulation.enabled) {
  1653. local_floor_emulation.should_reset_floor_height = true;
  1654. }
  1655. if (xr_interface) {
  1656. xr_interface->on_reference_space_change_pending();
  1657. }
  1658. } break;
  1659. case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED: {
  1660. print_verbose("OpenXR EVENT: interaction profile changed!");
  1661. XrEventDataInteractionProfileChanged *event = (XrEventDataInteractionProfileChanged *)&runtimeEvent;
  1662. List<RID> trackers;
  1663. tracker_owner.get_owned_list(&trackers);
  1664. for (const RID &tracker : trackers) {
  1665. tracker_check_profile(tracker, event->session);
  1666. }
  1667. } break;
  1668. default:
  1669. if (!handled) {
  1670. print_verbose(String("OpenXR Unhandled event type ") + OpenXRUtil::get_structure_type_name(runtimeEvent.type));
  1671. }
  1672. break;
  1673. }
  1674. runtimeEvent.type = XR_TYPE_EVENT_DATA_BUFFER;
  1675. pollResult = xrPollEvent(instance, &runtimeEvent);
  1676. }
  1677. if (pollResult == XR_EVENT_UNAVAILABLE) {
  1678. // processed all events in the queue
  1679. return true;
  1680. } else {
  1681. ERR_FAIL_V_MSG(false, "OpenXR: Failed to poll events!");
  1682. }
  1683. }
  1684. void OpenXRAPI::_allocate_view_buffers(uint32_t p_view_count, bool p_submit_depth_buffer) {
  1685. // Must be called from rendering thread!
  1686. ERR_NOT_ON_RENDER_THREAD;
  1687. OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
  1688. ERR_FAIL_NULL(openxr_api);
  1689. openxr_api->render_state.submit_depth_buffer = p_submit_depth_buffer;
  1690. // Allocate buffers we'll be populating with view information.
  1691. openxr_api->render_state.views.resize(p_view_count);
  1692. openxr_api->render_state.projection_views.resize(p_view_count);
  1693. if (p_submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) {
  1694. openxr_api->render_state.depth_views.resize(p_view_count);
  1695. }
  1696. }
  1697. void OpenXRAPI::_set_render_session_running(bool p_is_running) {
  1698. // Must be called from rendering thread!
  1699. ERR_NOT_ON_RENDER_THREAD;
  1700. OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
  1701. ERR_FAIL_NULL(openxr_api);
  1702. openxr_api->render_state.running = p_is_running;
  1703. }
  1704. void OpenXRAPI::_set_render_display_info(XrTime p_predicted_display_time, bool p_should_render) {
  1705. // Must be called from rendering thread!
  1706. ERR_NOT_ON_RENDER_THREAD;
  1707. OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
  1708. ERR_FAIL_NULL(openxr_api);
  1709. openxr_api->render_state.predicted_display_time = p_predicted_display_time;
  1710. openxr_api->render_state.should_render = p_should_render;
  1711. }
  1712. void OpenXRAPI::_set_render_play_space(uint64_t p_play_space) {
  1713. // Must be called from rendering thread!
  1714. ERR_NOT_ON_RENDER_THREAD;
  1715. OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
  1716. ERR_FAIL_NULL(openxr_api);
  1717. openxr_api->render_state.play_space = XrSpace(p_play_space);
  1718. }
  1719. void OpenXRAPI::_set_render_state_multiplier(double p_render_target_size_multiplier) {
  1720. // Must be called from rendering thread!
  1721. ERR_NOT_ON_RENDER_THREAD;
  1722. OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
  1723. ERR_FAIL_NULL(openxr_api);
  1724. openxr_api->render_state.render_target_size_multiplier = p_render_target_size_multiplier;
  1725. }
  1726. void OpenXRAPI::_set_render_state_render_region(const Rect2i &p_render_region) {
  1727. ERR_NOT_ON_RENDER_THREAD;
  1728. OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
  1729. ERR_FAIL_NULL(openxr_api);
  1730. openxr_api->render_state.render_region = p_render_region;
  1731. }
  1732. bool OpenXRAPI::process() {
  1733. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  1734. if (!poll_events()) {
  1735. return false;
  1736. }
  1737. if (!running) {
  1738. return false;
  1739. }
  1740. // We call xrWaitFrame as early as possible, this will allow OpenXR to get
  1741. // proper timing info between this point, and when we're ready to start rendering.
  1742. // As the name suggests, OpenXR can pause the thread to minimize the time between
  1743. // retrieving tracking data and using that tracking data to render.
  1744. // OpenXR thus works best if rendering is performed on a separate thread.
  1745. void *frame_wait_info_next_pointer = nullptr;
  1746. for (OpenXRExtensionWrapper *extension : frame_info_extensions) {
  1747. void *np = extension->set_frame_wait_info_and_get_next_pointer(frame_wait_info_next_pointer);
  1748. if (np != nullptr) {
  1749. frame_wait_info_next_pointer = np;
  1750. }
  1751. }
  1752. XrFrameWaitInfo frame_wait_info = { XR_TYPE_FRAME_WAIT_INFO, frame_wait_info_next_pointer };
  1753. frame_state.predictedDisplayTime = 0;
  1754. frame_state.predictedDisplayPeriod = 0;
  1755. frame_state.shouldRender = false;
  1756. XrResult result = xrWaitFrame(session, &frame_wait_info, &frame_state);
  1757. if (XR_FAILED(result)) {
  1758. print_line("OpenXR: xrWaitFrame() was not successful [", get_error_string(result), "]");
  1759. // reset just in case
  1760. frame_state.predictedDisplayTime = 0;
  1761. frame_state.predictedDisplayPeriod = 0;
  1762. frame_state.shouldRender = false;
  1763. set_render_display_info(0, false);
  1764. return false;
  1765. }
  1766. if (frame_state.predictedDisplayPeriod > 500000000) {
  1767. // display period more then 0.5 seconds? must be wrong data
  1768. print_verbose(String("OpenXR resetting invalid display period ") + rtos(frame_state.predictedDisplayPeriod));
  1769. frame_state.predictedDisplayPeriod = 0;
  1770. }
  1771. set_render_display_info(frame_state.predictedDisplayTime, frame_state.shouldRender);
  1772. // This is before setup_play_space() to ensure that it happens on the frame after
  1773. // the play space has been created.
  1774. if (unlikely(local_floor_emulation.should_reset_floor_height && !play_space_is_dirty)) {
  1775. reset_emulated_floor_height();
  1776. local_floor_emulation.should_reset_floor_height = false;
  1777. }
  1778. if (unlikely(play_space_is_dirty)) {
  1779. setup_play_space();
  1780. play_space_is_dirty = false;
  1781. }
  1782. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1783. wrapper->on_process();
  1784. }
  1785. return true;
  1786. }
  1787. void OpenXRAPI::free_main_swapchains() {
  1788. for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) {
  1789. render_state.main_swapchains[i].queue_free();
  1790. }
  1791. }
  1792. void OpenXRAPI::pre_render() {
  1793. ERR_FAIL_COND(session == XR_NULL_HANDLE);
  1794. // Must be called from rendering thread!
  1795. ERR_NOT_ON_RENDER_THREAD;
  1796. if (!render_state.running) {
  1797. return;
  1798. }
  1799. // Process any swapchains that were queued to be freed
  1800. OpenXRSwapChainInfo::free_queued();
  1801. Size2i swapchain_size = get_recommended_target_size();
  1802. if (swapchain_size != render_state.main_swapchain_size) {
  1803. // Out with the old.
  1804. free_main_swapchains();
  1805. // In with the new.
  1806. create_main_swapchains(swapchain_size);
  1807. }
  1808. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1809. wrapper->on_pre_render();
  1810. }
  1811. void *view_locate_info_next_pointer = nullptr;
  1812. for (OpenXRExtensionWrapper *extension : frame_info_extensions) {
  1813. void *np = extension->set_view_locate_info_and_get_next_pointer(view_locate_info_next_pointer);
  1814. if (np != nullptr) {
  1815. view_locate_info_next_pointer = np;
  1816. }
  1817. }
  1818. // Get our view info for the frame we're about to render, note from the OpenXR manual:
  1819. // "Repeatedly calling xrLocateViews with the same time may not necessarily return the same result. Instead the prediction gets increasingly accurate as the function is called closer to the given time for which a prediction is made"
  1820. // We're calling this "relatively" early, the positioning we're obtaining here will be used to do our frustum culling,
  1821. // occlusion culling, etc. There is however a technique that we can investigate in the future where after our entire
  1822. // Vulkan command buffer is build, but right before vkSubmitQueue is called, we call xrLocateViews one more time and
  1823. // update the view and projection matrix once more with a slightly more accurate predication and then submit the
  1824. // command queues.
  1825. // That is not possible yet but worth investigating in the future.
  1826. XrViewLocateInfo view_locate_info = {
  1827. XR_TYPE_VIEW_LOCATE_INFO, // type
  1828. view_locate_info_next_pointer, // next
  1829. view_configuration, // viewConfigurationType
  1830. render_state.predicted_display_time, // displayTime
  1831. render_state.play_space // space
  1832. };
  1833. XrViewState view_state = {
  1834. XR_TYPE_VIEW_STATE, // type
  1835. nullptr, // next
  1836. 0 // viewStateFlags
  1837. };
  1838. uint32_t view_count_output;
  1839. XrResult result = xrLocateViews(session, &view_locate_info, &view_state, render_state.views.size(), &view_count_output, render_state.views.ptr());
  1840. if (XR_FAILED(result)) {
  1841. print_line("OpenXR: Couldn't locate views [", get_error_string(result), "]");
  1842. return;
  1843. }
  1844. bool pose_valid = true;
  1845. for (uint64_t i = 0; i < view_count_output; i++) {
  1846. if ((view_state.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) == 0 ||
  1847. (view_state.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT) == 0) {
  1848. pose_valid = false;
  1849. }
  1850. }
  1851. if (render_state.view_pose_valid != pose_valid) {
  1852. render_state.view_pose_valid = pose_valid;
  1853. if (!render_state.view_pose_valid) {
  1854. print_verbose("OpenXR View pose became invalid");
  1855. } else {
  1856. print_verbose("OpenXR View pose became valid");
  1857. }
  1858. }
  1859. // We should get our frame no from the rendering server, but this will do.
  1860. begin_debug_label_region(String("Session Frame ") + String::num_uint64(++render_state.frame));
  1861. // let's start our frame..
  1862. XrFrameBeginInfo frame_begin_info = {
  1863. XR_TYPE_FRAME_BEGIN_INFO, // type
  1864. nullptr // next
  1865. };
  1866. result = xrBeginFrame(session, &frame_begin_info);
  1867. if (XR_FAILED(result)) {
  1868. print_line("OpenXR: failed to begin frame [", get_error_string(result), "]");
  1869. return;
  1870. }
  1871. // Reset this, we haven't found a viewport for output yet
  1872. render_state.has_xr_viewport = false;
  1873. }
  1874. bool OpenXRAPI::pre_draw_viewport(RID p_render_target) {
  1875. // Must be called from rendering thread!
  1876. ERR_NOT_ON_RENDER_THREAD_V(false);
  1877. // We found an XR viewport!
  1878. render_state.has_xr_viewport = true;
  1879. if (instance == XR_NULL_HANDLE || session == XR_NULL_HANDLE || !render_state.running || !render_state.view_pose_valid || !render_state.should_render) {
  1880. return false;
  1881. }
  1882. // Acquire our images
  1883. for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) {
  1884. if (!render_state.main_swapchains[i].is_image_acquired() && render_state.main_swapchains[i].get_swapchain() != XR_NULL_HANDLE) {
  1885. if (!render_state.main_swapchains[i].acquire(render_state.should_render)) {
  1886. return false;
  1887. }
  1888. }
  1889. }
  1890. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1891. wrapper->on_pre_draw_viewport(p_render_target);
  1892. }
  1893. return true;
  1894. }
  1895. XrSwapchain OpenXRAPI::get_color_swapchain() {
  1896. ERR_NOT_ON_RENDER_THREAD_V(XR_NULL_HANDLE);
  1897. return render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_swapchain();
  1898. }
  1899. RID OpenXRAPI::get_color_texture() {
  1900. ERR_NOT_ON_RENDER_THREAD_V(RID());
  1901. return render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_image();
  1902. }
  1903. RID OpenXRAPI::get_depth_texture() {
  1904. ERR_NOT_ON_RENDER_THREAD_V(RID());
  1905. // Note, image will not be acquired if we didn't have a suitable swap chain format.
  1906. if (render_state.submit_depth_buffer && render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].is_image_acquired()) {
  1907. return render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].get_image();
  1908. } else {
  1909. return RID();
  1910. }
  1911. }
  1912. RID OpenXRAPI::get_density_map_texture() {
  1913. ERR_NOT_ON_RENDER_THREAD_V(RID());
  1914. OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
  1915. if (fov_ext && fov_ext->is_enabled()) {
  1916. return render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_density_map();
  1917. }
  1918. return RID();
  1919. }
  1920. void OpenXRAPI::set_velocity_texture(RID p_render_target) {
  1921. velocity_texture = p_render_target;
  1922. }
  1923. RID OpenXRAPI::get_velocity_texture() {
  1924. return velocity_texture;
  1925. }
  1926. void OpenXRAPI::set_velocity_depth_texture(RID p_render_target) {
  1927. velocity_depth_texture = p_render_target;
  1928. }
  1929. RID OpenXRAPI::get_velocity_depth_texture() {
  1930. return velocity_depth_texture;
  1931. }
  1932. void OpenXRAPI::set_velocity_target_size(const Size2i &p_target_size) {
  1933. velocity_target_size = p_target_size;
  1934. }
  1935. Size2i OpenXRAPI::get_velocity_target_size() {
  1936. return velocity_target_size;
  1937. }
  1938. const XrCompositionLayerProjection *OpenXRAPI::get_projection_layer() const {
  1939. ERR_NOT_ON_RENDER_THREAD_V(nullptr);
  1940. return &render_state.projection_layer;
  1941. }
  1942. void OpenXRAPI::post_draw_viewport(RID p_render_target) {
  1943. // Must be called from rendering thread!
  1944. ERR_NOT_ON_RENDER_THREAD;
  1945. if (instance == XR_NULL_HANDLE || session == XR_NULL_HANDLE || !render_state.running || !render_state.view_pose_valid || !render_state.should_render) {
  1946. return;
  1947. }
  1948. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1949. wrapper->on_post_draw_viewport(p_render_target);
  1950. }
  1951. }
  1952. void OpenXRAPI::end_frame() {
  1953. XrResult result;
  1954. ERR_FAIL_COND(session == XR_NULL_HANDLE);
  1955. // Must be called from rendering thread!
  1956. ERR_NOT_ON_RENDER_THREAD;
  1957. if (!render_state.running) {
  1958. return;
  1959. }
  1960. if (render_state.should_render && render_state.view_pose_valid) {
  1961. if (!render_state.has_xr_viewport) {
  1962. print_line("OpenXR: No viewport was marked with use_xr, there is no rendered output!");
  1963. } else if (!render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].is_image_acquired()) {
  1964. print_line("OpenXR: No swapchain could be acquired to render to!");
  1965. }
  1966. }
  1967. Rect2i new_render_region = (render_state.render_region != Rect2i()) ? render_state.render_region : Rect2i(Point2i(0, 0), render_state.main_swapchain_size);
  1968. for (XrCompositionLayerProjectionView &projection_view : render_state.projection_views) {
  1969. projection_view.subImage.imageRect.offset.x = new_render_region.position.x;
  1970. projection_view.subImage.imageRect.offset.y = new_render_region.position.y;
  1971. projection_view.subImage.imageRect.extent.width = new_render_region.size.width;
  1972. projection_view.subImage.imageRect.extent.height = new_render_region.size.height;
  1973. }
  1974. if (render_state.submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available() && !render_state.depth_views.is_empty()) {
  1975. for (XrCompositionLayerDepthInfoKHR &depth_view : render_state.depth_views) {
  1976. depth_view.subImage.imageRect.offset.x = new_render_region.position.x;
  1977. depth_view.subImage.imageRect.offset.y = new_render_region.position.y;
  1978. depth_view.subImage.imageRect.extent.width = new_render_region.size.width;
  1979. depth_view.subImage.imageRect.extent.height = new_render_region.size.height;
  1980. }
  1981. }
  1982. // must have:
  1983. // - should_render set to true
  1984. // - a valid view pose for projection_views[eye].pose to submit layer
  1985. // - an image to render
  1986. if (!render_state.should_render || !render_state.view_pose_valid || !render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].is_image_acquired()) {
  1987. // submit 0 layers when we shouldn't render
  1988. XrFrameEndInfo frame_end_info = {
  1989. XR_TYPE_FRAME_END_INFO, // type
  1990. nullptr, // next
  1991. render_state.predicted_display_time, // displayTime
  1992. environment_blend_mode, // environmentBlendMode
  1993. 0, // layerCount
  1994. nullptr // layers
  1995. };
  1996. result = xrEndFrame(session, &frame_end_info);
  1997. if (XR_FAILED(result)) {
  1998. print_line("OpenXR: rendering skipped and failed to end frame! [", get_error_string(result), "]");
  1999. return;
  2000. }
  2001. end_debug_label_region(); // Session frame #
  2002. // neither eye is rendered
  2003. return;
  2004. }
  2005. // release our swapchain image if we acquired it
  2006. for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) {
  2007. if (render_state.main_swapchains[i].is_image_acquired()) {
  2008. render_state.main_swapchains[i].release();
  2009. }
  2010. }
  2011. for (uint32_t eye = 0; eye < render_state.views.size(); eye++) {
  2012. render_state.projection_views[eye].fov = render_state.views[eye].fov;
  2013. render_state.projection_views[eye].pose = render_state.views[eye].pose;
  2014. }
  2015. Vector<OrderedCompositionLayer> ordered_layers_list;
  2016. bool projection_layer_is_first = true;
  2017. // Add composition layers from providers
  2018. for (OpenXRExtensionWrapper *extension : composition_layer_providers) {
  2019. for (int i = 0; i < extension->get_composition_layer_count(); i++) {
  2020. OrderedCompositionLayer layer = {
  2021. extension->get_composition_layer(i),
  2022. extension->get_composition_layer_order(i),
  2023. };
  2024. if (layer.composition_layer) {
  2025. ordered_layers_list.push_back(layer);
  2026. if (layer.sort_order == 0) {
  2027. WARN_PRINT_ONCE_ED("Composition layer returned sort order 0, it may be overwritten by projection layer.");
  2028. } else if (layer.sort_order < 0) {
  2029. projection_layer_is_first = false;
  2030. }
  2031. }
  2032. }
  2033. }
  2034. XrCompositionLayerFlags layer_flags = XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
  2035. if (!projection_layer_is_first || environment_blend_mode != XR_ENVIRONMENT_BLEND_MODE_OPAQUE) {
  2036. layer_flags |= XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
  2037. }
  2038. render_state.projection_layer.layerFlags = layer_flags;
  2039. render_state.projection_layer.space = render_state.play_space;
  2040. render_state.projection_layer.viewCount = (uint32_t)render_state.projection_views.size();
  2041. render_state.projection_layer.views = render_state.projection_views.ptr();
  2042. if (projection_views_extensions.size() > 0) {
  2043. for (uint32_t v = 0; v < render_state.projection_views.size(); v++) {
  2044. void *next_pointer = nullptr;
  2045. for (OpenXRExtensionWrapper *wrapper : projection_views_extensions) {
  2046. void *np = wrapper->set_projection_views_and_get_next_pointer(v, next_pointer);
  2047. if (np != nullptr) {
  2048. next_pointer = np;
  2049. }
  2050. }
  2051. render_state.projection_views[v].next = next_pointer;
  2052. }
  2053. }
  2054. ordered_layers_list.push_back({ (const XrCompositionLayerBaseHeader *)&render_state.projection_layer, 0 });
  2055. // Sort our layers.
  2056. ordered_layers_list.sort_custom<OrderedCompositionLayer>();
  2057. // Now make a list we can pass on to OpenXR.
  2058. Vector<const XrCompositionLayerBaseHeader *> layers_list;
  2059. for (OrderedCompositionLayer &ordered_layer : ordered_layers_list) {
  2060. layers_list.push_back(ordered_layer.composition_layer);
  2061. }
  2062. void *frame_end_info_next_pointer = nullptr;
  2063. for (OpenXRExtensionWrapper *extension : frame_info_extensions) {
  2064. void *np = extension->set_frame_end_info_and_get_next_pointer(frame_end_info_next_pointer);
  2065. if (np != nullptr) {
  2066. frame_end_info_next_pointer = np;
  2067. }
  2068. }
  2069. XrFrameEndInfo frame_end_info = {
  2070. XR_TYPE_FRAME_END_INFO, // type
  2071. frame_end_info_next_pointer, // next
  2072. render_state.predicted_display_time, // displayTime
  2073. environment_blend_mode, // environmentBlendMode
  2074. static_cast<uint32_t>(layers_list.size()), // layerCount
  2075. layers_list.ptr() // layers
  2076. };
  2077. result = xrEndFrame(session, &frame_end_info);
  2078. if (XR_FAILED(result)) {
  2079. print_line("OpenXR: failed to end frame! [", get_error_string(result), "]");
  2080. return;
  2081. }
  2082. end_debug_label_region(); // Session frame #
  2083. }
  2084. float OpenXRAPI::get_display_refresh_rate() const {
  2085. OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
  2086. if (drrext) {
  2087. return drrext->get_refresh_rate();
  2088. }
  2089. return 0.0;
  2090. }
  2091. void OpenXRAPI::set_display_refresh_rate(float p_refresh_rate) {
  2092. OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
  2093. if (drrext != nullptr) {
  2094. drrext->set_refresh_rate(p_refresh_rate);
  2095. }
  2096. }
  2097. Array OpenXRAPI::get_available_display_refresh_rates() const {
  2098. OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
  2099. if (drrext != nullptr) {
  2100. return drrext->get_available_refresh_rates();
  2101. }
  2102. return Array();
  2103. }
  2104. double OpenXRAPI::get_render_target_size_multiplier() const {
  2105. return render_target_size_multiplier;
  2106. }
  2107. void OpenXRAPI::set_render_target_size_multiplier(double multiplier) {
  2108. render_target_size_multiplier = multiplier;
  2109. set_render_state_multiplier(multiplier);
  2110. }
  2111. Rect2i OpenXRAPI::get_render_region() const {
  2112. return render_region;
  2113. }
  2114. void OpenXRAPI::set_render_region(const Rect2i &p_render_region) {
  2115. render_region = p_render_region;
  2116. set_render_state_render_region(p_render_region);
  2117. }
  2118. bool OpenXRAPI::is_foveation_supported() const {
  2119. OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
  2120. return fov_ext != nullptr && fov_ext->is_enabled();
  2121. }
  2122. int OpenXRAPI::get_foveation_level() const {
  2123. OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
  2124. if (fov_ext != nullptr && fov_ext->is_enabled()) {
  2125. switch (fov_ext->get_foveation_level()) {
  2126. case XR_FOVEATION_LEVEL_NONE_FB:
  2127. return 0;
  2128. case XR_FOVEATION_LEVEL_LOW_FB:
  2129. return 1;
  2130. case XR_FOVEATION_LEVEL_MEDIUM_FB:
  2131. return 2;
  2132. case XR_FOVEATION_LEVEL_HIGH_FB:
  2133. return 3;
  2134. default:
  2135. return 0;
  2136. }
  2137. }
  2138. return 0;
  2139. }
  2140. void OpenXRAPI::set_foveation_level(int p_foveation_level) {
  2141. ERR_FAIL_UNSIGNED_INDEX(p_foveation_level, 4);
  2142. OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
  2143. if (fov_ext != nullptr && fov_ext->is_enabled()) {
  2144. XrFoveationLevelFB levels[] = { XR_FOVEATION_LEVEL_NONE_FB, XR_FOVEATION_LEVEL_LOW_FB, XR_FOVEATION_LEVEL_MEDIUM_FB, XR_FOVEATION_LEVEL_HIGH_FB };
  2145. fov_ext->set_foveation_level(levels[p_foveation_level]);
  2146. }
  2147. }
  2148. bool OpenXRAPI::get_foveation_dynamic() const {
  2149. OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
  2150. if (fov_ext != nullptr && fov_ext->is_enabled()) {
  2151. return fov_ext->get_foveation_dynamic() == XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB;
  2152. }
  2153. return false;
  2154. }
  2155. void OpenXRAPI::set_foveation_dynamic(bool p_foveation_dynamic) {
  2156. OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
  2157. if (fov_ext != nullptr && fov_ext->is_enabled()) {
  2158. fov_ext->set_foveation_dynamic(p_foveation_dynamic ? XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB : XR_FOVEATION_DYNAMIC_DISABLED_FB);
  2159. }
  2160. }
  2161. Size2 OpenXRAPI::get_play_space_bounds() const {
  2162. Size2 ret;
  2163. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, Size2());
  2164. XrExtent2Df extents;
  2165. XrResult result = xrGetReferenceSpaceBoundsRect(session, reference_space, &extents);
  2166. if (XR_FAILED(result)) {
  2167. print_line("OpenXR: failed to get play space bounds! [", get_error_string(result), "]");
  2168. return ret;
  2169. }
  2170. ret.width = extents.width;
  2171. ret.height = extents.height;
  2172. return ret;
  2173. }
  2174. PackedInt64Array OpenXRAPI::get_supported_swapchain_formats() {
  2175. return supported_swapchain_formats;
  2176. }
  2177. OpenXRAPI::OpenXRAPI() {
  2178. // OpenXRAPI is only constructed if OpenXR is enabled.
  2179. singleton = this;
  2180. if (Engine::get_singleton()->is_editor_hint()) {
  2181. // Enabled OpenXR in the editor? Adjust our settings for the editor
  2182. } else {
  2183. // Load settings from project settings
  2184. int form_factor_setting = GLOBAL_GET("xr/openxr/form_factor");
  2185. switch (form_factor_setting) {
  2186. case 0: {
  2187. form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
  2188. } break;
  2189. case 1: {
  2190. form_factor = XR_FORM_FACTOR_HANDHELD_DISPLAY;
  2191. } break;
  2192. default:
  2193. break;
  2194. }
  2195. int view_configuration_setting = GLOBAL_GET("xr/openxr/view_configuration");
  2196. switch (view_configuration_setting) {
  2197. case 0: {
  2198. view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO;
  2199. } break;
  2200. case 1: {
  2201. view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
  2202. } break;
  2203. /* we don't support quad and observer configurations (yet)
  2204. case 2: {
  2205. view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO;
  2206. } break;
  2207. case 3: {
  2208. view_configuration = XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT;
  2209. } break;
  2210. */
  2211. default:
  2212. break;
  2213. }
  2214. int reference_space_setting = GLOBAL_GET("xr/openxr/reference_space");
  2215. switch (reference_space_setting) {
  2216. case 0: {
  2217. requested_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
  2218. } break;
  2219. case 1: {
  2220. requested_reference_space = XR_REFERENCE_SPACE_TYPE_STAGE;
  2221. } break;
  2222. case 2: {
  2223. requested_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
  2224. } break;
  2225. default:
  2226. break;
  2227. }
  2228. int environment_blend_mode_setting = GLOBAL_GET("xr/openxr/environment_blend_mode");
  2229. switch (environment_blend_mode_setting) {
  2230. case 0: {
  2231. environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
  2232. } break;
  2233. case 1: {
  2234. environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_ADDITIVE;
  2235. } break;
  2236. case 2: {
  2237. environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND;
  2238. } break;
  2239. default:
  2240. break;
  2241. }
  2242. submit_depth_buffer = GLOBAL_GET("xr/openxr/submit_depth_buffer");
  2243. }
  2244. }
  2245. OpenXRAPI::~OpenXRAPI() {
  2246. composition_layer_providers.clear();
  2247. frame_info_extensions.clear();
  2248. supported_extensions.clear();
  2249. layer_properties.clear();
  2250. #ifdef ANDROID_ENABLED
  2251. if (openxr_loader_library_handle) {
  2252. OS::get_singleton()->close_dynamic_library(openxr_loader_library_handle);
  2253. openxr_loader_library_handle = nullptr;
  2254. }
  2255. #endif
  2256. singleton = nullptr;
  2257. }
  2258. Transform3D OpenXRAPI::transform_from_pose(const XrPosef &p_pose) {
  2259. Quaternion q(p_pose.orientation.x, p_pose.orientation.y, p_pose.orientation.z, p_pose.orientation.w);
  2260. Basis basis(q);
  2261. Vector3 origin(p_pose.position.x, p_pose.position.y, p_pose.position.z);
  2262. return Transform3D(basis, origin);
  2263. }
  2264. template <typename T>
  2265. XRPose::TrackingConfidence _transform_from_location(const T &p_location, Transform3D &r_transform) {
  2266. XRPose::TrackingConfidence confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE;
  2267. const XrPosef &pose = p_location.pose;
  2268. // Check orientation
  2269. if (p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
  2270. Quaternion q(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w);
  2271. r_transform.basis = Basis(q);
  2272. if (p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT) {
  2273. // Fully valid orientation, so either 3DOF or 6DOF tracking with high confidence so default to HIGH_TRACKING
  2274. confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH;
  2275. } else {
  2276. // Orientation is being tracked but we're using old/predicted data, so low tracking confidence
  2277. confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW;
  2278. }
  2279. } else {
  2280. r_transform.basis = Basis();
  2281. }
  2282. // Check location
  2283. if (p_location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
  2284. r_transform.origin = Vector3(pose.position.x, pose.position.y, pose.position.z);
  2285. if (!(p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT)) {
  2286. // Location is being tracked but we're using old/predicted data, so low tracking confidence
  2287. confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW;
  2288. } else if (confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) {
  2289. // Position tracking without orientation tracking?
  2290. confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH;
  2291. }
  2292. } else {
  2293. // No tracking or 3DOF I guess..
  2294. r_transform.origin = Vector3();
  2295. }
  2296. return confidence;
  2297. }
  2298. XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform) {
  2299. return _transform_from_location(p_location, r_transform);
  2300. }
  2301. XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform) {
  2302. return _transform_from_location(p_location, r_transform);
  2303. }
  2304. void OpenXRAPI::parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
  2305. if (p_velocity.velocityFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) {
  2306. XrVector3f linear_velocity = p_velocity.linearVelocity;
  2307. r_linear_velocity = Vector3(linear_velocity.x, linear_velocity.y, linear_velocity.z);
  2308. } else {
  2309. r_linear_velocity = Vector3();
  2310. }
  2311. if (p_velocity.velocityFlags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) {
  2312. XrVector3f angular_velocity = p_velocity.angularVelocity;
  2313. r_angular_velocity = Vector3(angular_velocity.x, angular_velocity.y, angular_velocity.z);
  2314. } else {
  2315. r_angular_velocity = Vector3();
  2316. }
  2317. }
  2318. bool OpenXRAPI::xr_result(XrResult result, const char *format, Array args) const {
  2319. if (XR_SUCCEEDED(result)) {
  2320. return true;
  2321. }
  2322. char resultString[XR_MAX_RESULT_STRING_SIZE];
  2323. xrResultToString(instance, result, resultString);
  2324. print_error(String("OpenXR ") + String(format).format(args) + String(" [") + String(resultString) + String("]"));
  2325. return false;
  2326. }
  2327. XrPath OpenXRAPI::get_xr_path(const String &p_path) {
  2328. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, XR_NULL_PATH);
  2329. if (p_path.is_empty()) {
  2330. // This isn't necesairily an issue, so silently return a null path.
  2331. return XR_NULL_PATH;
  2332. }
  2333. XrPath path = XR_NULL_PATH;
  2334. XrResult result = xrStringToPath(instance, p_path.utf8().get_data(), &path);
  2335. if (XR_FAILED(result)) {
  2336. print_line("OpenXR: failed to get path for ", p_path, "! [", get_error_string(result), "]");
  2337. return XR_NULL_PATH;
  2338. }
  2339. return path;
  2340. }
  2341. RID OpenXRAPI::get_tracker_rid(XrPath p_path) {
  2342. List<RID> current;
  2343. tracker_owner.get_owned_list(&current);
  2344. for (const RID &E : current) {
  2345. Tracker *tracker = tracker_owner.get_or_null(E);
  2346. if (tracker && tracker->toplevel_path == p_path) {
  2347. return E;
  2348. }
  2349. }
  2350. return RID();
  2351. }
  2352. RID OpenXRAPI::find_tracker(const String &p_name) {
  2353. List<RID> current;
  2354. tracker_owner.get_owned_list(&current);
  2355. for (const RID &E : current) {
  2356. Tracker *tracker = tracker_owner.get_or_null(E);
  2357. if (tracker && tracker->name == p_name) {
  2358. return E;
  2359. }
  2360. }
  2361. return RID();
  2362. }
  2363. RID OpenXRAPI::tracker_create(const String p_name) {
  2364. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID());
  2365. Tracker new_tracker;
  2366. new_tracker.name = p_name;
  2367. new_tracker.toplevel_path = XR_NULL_PATH;
  2368. new_tracker.active_profile_rid = RID();
  2369. new_tracker.toplevel_path = get_xr_path(p_name);
  2370. ERR_FAIL_COND_V(new_tracker.toplevel_path == XR_NULL_PATH, RID());
  2371. return tracker_owner.make_rid(new_tracker);
  2372. }
  2373. String OpenXRAPI::tracker_get_name(RID p_tracker) {
  2374. if (p_tracker.is_null()) {
  2375. return String("None");
  2376. }
  2377. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2378. ERR_FAIL_NULL_V(tracker, String());
  2379. return tracker->name;
  2380. }
  2381. void OpenXRAPI::tracker_check_profile(RID p_tracker, XrSession p_session) {
  2382. if (p_session == XR_NULL_HANDLE) {
  2383. p_session = session;
  2384. }
  2385. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2386. ERR_FAIL_NULL(tracker);
  2387. if (tracker->toplevel_path == XR_NULL_PATH) {
  2388. // no path, how was this even created?
  2389. return;
  2390. }
  2391. XrInteractionProfileState profile_state = {
  2392. XR_TYPE_INTERACTION_PROFILE_STATE, // type
  2393. nullptr, // next
  2394. XR_NULL_PATH // interactionProfile
  2395. };
  2396. XrResult result = xrGetCurrentInteractionProfile(p_session, tracker->toplevel_path, &profile_state);
  2397. if (XR_FAILED(result)) {
  2398. print_line("OpenXR: Failed to get interaction profile for", itos(tracker->toplevel_path), "[", get_error_string(result), "]");
  2399. return;
  2400. }
  2401. XrPath new_profile = profile_state.interactionProfile;
  2402. XrPath was_profile = get_interaction_profile_path(tracker->active_profile_rid);
  2403. if (was_profile != new_profile) {
  2404. tracker->active_profile_rid = get_interaction_profile_rid(new_profile);
  2405. if (xr_interface) {
  2406. xr_interface->tracker_profile_changed(p_tracker, tracker->active_profile_rid);
  2407. }
  2408. }
  2409. }
  2410. void OpenXRAPI::tracker_free(RID p_tracker) {
  2411. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2412. ERR_FAIL_NULL(tracker);
  2413. // there is nothing to free here
  2414. tracker_owner.free(p_tracker);
  2415. }
  2416. RID OpenXRAPI::action_set_create(const String p_name, const String p_localized_name, const int p_priority) {
  2417. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID());
  2418. ActionSet action_set;
  2419. action_set.name = p_name;
  2420. action_set.is_attached = false;
  2421. // create our action set...
  2422. XrActionSetCreateInfo action_set_info = {
  2423. XR_TYPE_ACTION_SET_CREATE_INFO, // type
  2424. nullptr, // next
  2425. "", // actionSetName
  2426. "", // localizedActionSetName
  2427. uint32_t(p_priority) // priority
  2428. };
  2429. copy_string_to_char_buffer(p_name, action_set_info.actionSetName, XR_MAX_ACTION_SET_NAME_SIZE);
  2430. copy_string_to_char_buffer(p_localized_name, action_set_info.localizedActionSetName, XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE);
  2431. XrResult result = xrCreateActionSet(instance, &action_set_info, &action_set.handle);
  2432. if (XR_FAILED(result)) {
  2433. print_line("OpenXR: failed to create action set ", p_name, "! [", get_error_string(result), "]");
  2434. return RID();
  2435. }
  2436. set_object_name(XR_OBJECT_TYPE_ACTION_SET, uint64_t(action_set.handle), p_name);
  2437. return action_set_owner.make_rid(action_set);
  2438. }
  2439. RID OpenXRAPI::find_action_set(const String p_name) {
  2440. List<RID> current;
  2441. action_set_owner.get_owned_list(&current);
  2442. for (const RID &E : current) {
  2443. ActionSet *action_set = action_set_owner.get_or_null(E);
  2444. if (action_set && action_set->name == p_name) {
  2445. return E;
  2446. }
  2447. }
  2448. return RID();
  2449. }
  2450. String OpenXRAPI::action_set_get_name(RID p_action_set) {
  2451. if (p_action_set.is_null()) {
  2452. return String("None");
  2453. }
  2454. ActionSet *action_set = action_set_owner.get_or_null(p_action_set);
  2455. ERR_FAIL_NULL_V(action_set, String());
  2456. return action_set->name;
  2457. }
  2458. XrActionSet OpenXRAPI::action_set_get_handle(RID p_action_set) {
  2459. if (p_action_set.is_null()) {
  2460. return XR_NULL_HANDLE;
  2461. }
  2462. ActionSet *action_set = action_set_owner.get_or_null(p_action_set);
  2463. ERR_FAIL_NULL_V(action_set, XR_NULL_HANDLE);
  2464. return action_set->handle;
  2465. }
  2466. bool OpenXRAPI::attach_action_sets(const Vector<RID> &p_action_sets) {
  2467. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  2468. Vector<XrActionSet> action_handles;
  2469. action_handles.resize(p_action_sets.size());
  2470. for (int i = 0; i < p_action_sets.size(); i++) {
  2471. ActionSet *action_set = action_set_owner.get_or_null(p_action_sets[i]);
  2472. ERR_FAIL_NULL_V(action_set, false);
  2473. if (action_set->is_attached) {
  2474. return false;
  2475. }
  2476. action_handles.set(i, action_set->handle);
  2477. }
  2478. // So according to the docs, once we attach our action set to our session it becomes read only..
  2479. // https://www.khronos.org/registry/OpenXR/specs/1.0/man/html/xrAttachSessionActionSets.html
  2480. XrSessionActionSetsAttachInfo attach_info = {
  2481. XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO, // type
  2482. nullptr, // next
  2483. (uint32_t)p_action_sets.size(), // countActionSets,
  2484. action_handles.ptr() // actionSets
  2485. };
  2486. XrResult result = xrAttachSessionActionSets(session, &attach_info);
  2487. if (XR_FAILED(result)) {
  2488. print_line("OpenXR: failed to attach action sets! [", get_error_string(result), "]");
  2489. return false;
  2490. }
  2491. for (int i = 0; i < p_action_sets.size(); i++) {
  2492. ActionSet *action_set = action_set_owner.get_or_null(p_action_sets[i]);
  2493. ERR_FAIL_NULL_V(action_set, false);
  2494. action_set->is_attached = true;
  2495. }
  2496. /* For debugging:
  2497. print_verbose("Attached set " + action_set->name);
  2498. List<RID> action_rids;
  2499. action_owner.get_owned_list(&action_rids);
  2500. for (int i = 0; i < action_rids.size(); i++) {
  2501. Action * action = action_owner.get_or_null(action_rids[i]);
  2502. if (action && action->action_set_rid == p_action_set) {
  2503. print_verbose(" - Action " + action->name + ": " + OpenXRUtil::get_action_type_name(action->action_type));
  2504. for (int j = 0; j < action->trackers.size(); j++) {
  2505. Tracker * tracker = tracker_owner.get_or_null(action->trackers[j].tracker_rid);
  2506. if (tracker) {
  2507. print_verbose(" - " + tracker->name);
  2508. }
  2509. }
  2510. }
  2511. }
  2512. */
  2513. return true;
  2514. }
  2515. void OpenXRAPI::action_set_free(RID p_action_set) {
  2516. ActionSet *action_set = action_set_owner.get_or_null(p_action_set);
  2517. ERR_FAIL_NULL(action_set);
  2518. if (action_set->handle != XR_NULL_HANDLE) {
  2519. xrDestroyActionSet(action_set->handle);
  2520. }
  2521. action_set_owner.free(p_action_set);
  2522. }
  2523. RID OpenXRAPI::get_action_rid(XrAction p_action) {
  2524. List<RID> current;
  2525. action_owner.get_owned_list(&current);
  2526. for (const RID &E : current) {
  2527. Action *action = action_owner.get_or_null(E);
  2528. if (action && action->handle == p_action) {
  2529. return E;
  2530. }
  2531. }
  2532. return RID();
  2533. }
  2534. RID OpenXRAPI::find_action(const String &p_name, const RID &p_action_set) {
  2535. List<RID> current;
  2536. action_owner.get_owned_list(&current);
  2537. for (const RID &E : current) {
  2538. Action *action = action_owner.get_or_null(E);
  2539. if (action && action->name == p_name && (p_action_set.is_null() || action->action_set_rid == p_action_set)) {
  2540. return E;
  2541. }
  2542. }
  2543. return RID();
  2544. }
  2545. RID OpenXRAPI::action_create(RID p_action_set, const String p_name, const String p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<RID> &p_trackers) {
  2546. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID());
  2547. Action action;
  2548. action.name = p_name;
  2549. ActionSet *action_set = action_set_owner.get_or_null(p_action_set);
  2550. ERR_FAIL_NULL_V(action_set, RID());
  2551. ERR_FAIL_COND_V(action_set->handle == XR_NULL_HANDLE, RID());
  2552. action.action_set_rid = p_action_set;
  2553. switch (p_action_type) {
  2554. case OpenXRAction::OPENXR_ACTION_BOOL:
  2555. action.action_type = XR_ACTION_TYPE_BOOLEAN_INPUT;
  2556. break;
  2557. case OpenXRAction::OPENXR_ACTION_FLOAT:
  2558. action.action_type = XR_ACTION_TYPE_FLOAT_INPUT;
  2559. break;
  2560. case OpenXRAction::OPENXR_ACTION_VECTOR2:
  2561. action.action_type = XR_ACTION_TYPE_VECTOR2F_INPUT;
  2562. break;
  2563. case OpenXRAction::OPENXR_ACTION_POSE:
  2564. action.action_type = XR_ACTION_TYPE_POSE_INPUT;
  2565. break;
  2566. case OpenXRAction::OPENXR_ACTION_HAPTIC:
  2567. action.action_type = XR_ACTION_TYPE_VIBRATION_OUTPUT;
  2568. break;
  2569. default:
  2570. ERR_FAIL_V(RID());
  2571. break;
  2572. }
  2573. Vector<XrPath> toplevel_paths;
  2574. for (int i = 0; i < p_trackers.size(); i++) {
  2575. Tracker *tracker = tracker_owner.get_or_null(p_trackers[i]);
  2576. if (tracker != nullptr && tracker->toplevel_path != XR_NULL_PATH) {
  2577. ActionTracker action_tracker = {
  2578. p_trackers[i], // tracker
  2579. XR_NULL_HANDLE, // space
  2580. false // was_location_valid
  2581. };
  2582. action.trackers.push_back(action_tracker);
  2583. toplevel_paths.push_back(tracker->toplevel_path);
  2584. }
  2585. }
  2586. XrActionCreateInfo action_info = {
  2587. XR_TYPE_ACTION_CREATE_INFO, // type
  2588. nullptr, // next
  2589. "", // actionName
  2590. action.action_type, // actionType
  2591. uint32_t(toplevel_paths.size()), // countSubactionPaths
  2592. toplevel_paths.ptr(), // subactionPaths
  2593. "" // localizedActionName
  2594. };
  2595. copy_string_to_char_buffer(p_name, action_info.actionName, XR_MAX_ACTION_NAME_SIZE);
  2596. copy_string_to_char_buffer(p_localized_name, action_info.localizedActionName, XR_MAX_LOCALIZED_ACTION_NAME_SIZE);
  2597. XrResult result = xrCreateAction(action_set->handle, &action_info, &action.handle);
  2598. if (XR_FAILED(result)) {
  2599. print_line("OpenXR: failed to create action ", p_name, "! [", get_error_string(result), "]");
  2600. return RID();
  2601. }
  2602. set_object_name(XR_OBJECT_TYPE_ACTION, uint64_t(action.handle), p_name);
  2603. return action_owner.make_rid(action);
  2604. }
  2605. String OpenXRAPI::action_get_name(RID p_action) {
  2606. if (p_action.is_null()) {
  2607. return String("None");
  2608. }
  2609. Action *action = action_owner.get_or_null(p_action);
  2610. ERR_FAIL_NULL_V(action, String());
  2611. return action->name;
  2612. }
  2613. XrAction OpenXRAPI::action_get_handle(RID p_action) {
  2614. if (p_action.is_null()) {
  2615. return XR_NULL_HANDLE;
  2616. }
  2617. Action *action = action_owner.get_or_null(p_action);
  2618. ERR_FAIL_NULL_V(action, XR_NULL_HANDLE);
  2619. return action->handle;
  2620. }
  2621. void OpenXRAPI::action_free(RID p_action) {
  2622. Action *action = action_owner.get_or_null(p_action);
  2623. ERR_FAIL_NULL(action);
  2624. if (action->handle != XR_NULL_HANDLE) {
  2625. xrDestroyAction(action->handle);
  2626. }
  2627. action_owner.free(p_action);
  2628. }
  2629. RID OpenXRAPI::get_interaction_profile_rid(XrPath p_path) {
  2630. List<RID> current;
  2631. interaction_profile_owner.get_owned_list(&current);
  2632. for (const RID &E : current) {
  2633. InteractionProfile *ip = interaction_profile_owner.get_or_null(E);
  2634. if (ip && ip->path == p_path) {
  2635. return E;
  2636. }
  2637. }
  2638. return RID();
  2639. }
  2640. XrPath OpenXRAPI::get_interaction_profile_path(RID p_interaction_profile) {
  2641. if (p_interaction_profile.is_null()) {
  2642. return XR_NULL_PATH;
  2643. }
  2644. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2645. ERR_FAIL_NULL_V(ip, XR_NULL_PATH);
  2646. return ip->path;
  2647. }
  2648. RID OpenXRAPI::interaction_profile_create(const String p_name) {
  2649. if (!is_interaction_profile_supported(p_name)) {
  2650. // The extension enabling this path must not be active, we will silently skip this interaction profile
  2651. return RID();
  2652. }
  2653. InteractionProfile new_interaction_profile;
  2654. XrResult result = xrStringToPath(instance, p_name.utf8().get_data(), &new_interaction_profile.path);
  2655. if (XR_FAILED(result)) {
  2656. print_line("OpenXR: failed to get path for ", p_name, "! [", get_error_string(result), "]");
  2657. return RID();
  2658. }
  2659. RID existing_ip = get_interaction_profile_rid(new_interaction_profile.path);
  2660. if (existing_ip.is_valid()) {
  2661. return existing_ip;
  2662. }
  2663. new_interaction_profile.name = p_name;
  2664. return interaction_profile_owner.make_rid(new_interaction_profile);
  2665. }
  2666. String OpenXRAPI::interaction_profile_get_name(RID p_interaction_profile) {
  2667. if (p_interaction_profile.is_null()) {
  2668. return String("None");
  2669. }
  2670. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2671. ERR_FAIL_NULL_V(ip, String());
  2672. return ip->name;
  2673. }
  2674. void OpenXRAPI::interaction_profile_clear_bindings(RID p_interaction_profile) {
  2675. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2676. ERR_FAIL_NULL(ip);
  2677. ip->bindings.clear();
  2678. }
  2679. int OpenXRAPI::interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path) {
  2680. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2681. ERR_FAIL_NULL_V(ip, -1);
  2682. if (!interaction_profile_supports_io_path(ip->name, p_path)) {
  2683. return -1;
  2684. }
  2685. XrActionSuggestedBinding binding;
  2686. Action *action = action_owner.get_or_null(p_action);
  2687. ERR_FAIL_COND_V(action == nullptr || action->handle == XR_NULL_HANDLE, -1);
  2688. binding.action = action->handle;
  2689. XrResult result = xrStringToPath(instance, p_path.utf8().get_data(), &binding.binding);
  2690. if (XR_FAILED(result)) {
  2691. print_line("OpenXR: failed to get path for ", p_path, "! [", get_error_string(result), "]");
  2692. return -1;
  2693. }
  2694. ip->bindings.push_back(binding);
  2695. return ip->bindings.size() - 1;
  2696. }
  2697. bool OpenXRAPI::interaction_profile_add_modifier(RID p_interaction_profile, const PackedByteArray &p_modifier) {
  2698. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2699. ERR_FAIL_NULL_V(ip, false);
  2700. if (!p_modifier.is_empty()) {
  2701. // Add it to our stack.
  2702. ip->modifiers.push_back(p_modifier);
  2703. }
  2704. return true;
  2705. }
  2706. bool OpenXRAPI::interaction_profile_suggest_bindings(RID p_interaction_profile) {
  2707. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  2708. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2709. ERR_FAIL_NULL_V(ip, false);
  2710. void *next = nullptr;
  2711. // Note, extensions should only add binding modifiers if they are supported, else this may fail.
  2712. XrBindingModificationsKHR binding_modifiers;
  2713. Vector<const XrBindingModificationBaseHeaderKHR *> modifiers;
  2714. if (!ip->modifiers.is_empty()) {
  2715. for (const PackedByteArray &modifier : ip->modifiers) {
  2716. const XrBindingModificationBaseHeaderKHR *ptr = (const XrBindingModificationBaseHeaderKHR *)modifier.ptr();
  2717. modifiers.push_back(ptr);
  2718. }
  2719. binding_modifiers.type = XR_TYPE_BINDING_MODIFICATIONS_KHR;
  2720. binding_modifiers.next = next;
  2721. binding_modifiers.bindingModificationCount = modifiers.size();
  2722. binding_modifiers.bindingModifications = modifiers.ptr();
  2723. next = &binding_modifiers;
  2724. }
  2725. const XrInteractionProfileSuggestedBinding suggested_bindings = {
  2726. XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING, // type
  2727. next, // next
  2728. ip->path, // interactionProfile
  2729. uint32_t(ip->bindings.size()), // countSuggestedBindings
  2730. ip->bindings.ptr() // suggestedBindings
  2731. };
  2732. XrResult result = xrSuggestInteractionProfileBindings(instance, &suggested_bindings);
  2733. if (result == XR_ERROR_PATH_UNSUPPORTED) {
  2734. // this is fine, not all runtimes support all devices.
  2735. print_verbose("OpenXR Interaction profile " + ip->name + " is not supported on this runtime");
  2736. } else if (XR_FAILED(result)) {
  2737. print_line("OpenXR: failed to suggest bindings for ", ip->name, "! [", get_error_string(result), "]");
  2738. // reporting is enough...
  2739. }
  2740. /* For debugging:
  2741. print_verbose("Suggested bindings for " + ip->name);
  2742. for (int i = 0; i < ip->bindings.size(); i++) {
  2743. uint32_t strlen;
  2744. char path[XR_MAX_PATH_LENGTH];
  2745. String action_name = action_get_name(get_action_rid(ip->bindings[i].action));
  2746. XrResult result = xrPathToString(instance, ip->bindings[i].binding, XR_MAX_PATH_LENGTH, &strlen, path);
  2747. if (XR_FAILED(result)) {
  2748. print_line("OpenXR: failed to retrieve bindings for ", action_name, "! [", get_error_string(result), "]");
  2749. }
  2750. print_verbose(" - " + action_name + " => " + String(path));
  2751. }
  2752. */
  2753. return true;
  2754. }
  2755. void OpenXRAPI::interaction_profile_free(RID p_interaction_profile) {
  2756. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2757. ERR_FAIL_NULL(ip);
  2758. ip->bindings.clear();
  2759. ip->modifiers.clear();
  2760. interaction_profile_owner.free(p_interaction_profile);
  2761. }
  2762. bool OpenXRAPI::sync_action_sets(const Vector<RID> p_active_sets) {
  2763. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  2764. if (!running) {
  2765. return false;
  2766. }
  2767. Vector<XrActiveActionSet> active_sets;
  2768. for (int i = 0; i < p_active_sets.size(); i++) {
  2769. ActionSet *action_set = action_set_owner.get_or_null(p_active_sets[i]);
  2770. if (action_set && action_set->handle != XR_NULL_HANDLE) {
  2771. XrActiveActionSet aset;
  2772. aset.actionSet = action_set->handle;
  2773. aset.subactionPath = XR_NULL_PATH;
  2774. active_sets.push_back(aset);
  2775. }
  2776. }
  2777. ERR_FAIL_COND_V(active_sets.is_empty(), false);
  2778. XrActionsSyncInfo sync_info = {
  2779. XR_TYPE_ACTIONS_SYNC_INFO, // type
  2780. nullptr, // next
  2781. uint32_t(active_sets.size()), // countActiveActionSets
  2782. active_sets.ptr() // activeActionSets
  2783. };
  2784. XrResult result = xrSyncActions(session, &sync_info);
  2785. if (XR_FAILED(result)) {
  2786. print_line("OpenXR: failed to sync active action sets! [", get_error_string(result), "]");
  2787. return false;
  2788. }
  2789. return true;
  2790. }
  2791. bool OpenXRAPI::get_action_bool(RID p_action, RID p_tracker) {
  2792. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  2793. Action *action = action_owner.get_or_null(p_action);
  2794. ERR_FAIL_NULL_V(action, false);
  2795. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2796. ERR_FAIL_NULL_V(tracker, false);
  2797. if (!running) {
  2798. return false;
  2799. }
  2800. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_BOOLEAN_INPUT, false);
  2801. XrActionStateGetInfo get_info = {
  2802. XR_TYPE_ACTION_STATE_GET_INFO, // type
  2803. nullptr, // next
  2804. action->handle, // action
  2805. tracker->toplevel_path // subactionPath
  2806. };
  2807. XrActionStateBoolean result_state;
  2808. result_state.type = XR_TYPE_ACTION_STATE_BOOLEAN,
  2809. result_state.next = nullptr;
  2810. XrResult result = xrGetActionStateBoolean(session, &get_info, &result_state);
  2811. if (XR_FAILED(result)) {
  2812. print_line("OpenXR: couldn't get action boolean! [", get_error_string(result), "]");
  2813. return false;
  2814. }
  2815. return result_state.isActive && result_state.currentState;
  2816. }
  2817. float OpenXRAPI::get_action_float(RID p_action, RID p_tracker) {
  2818. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, 0.0);
  2819. Action *action = action_owner.get_or_null(p_action);
  2820. ERR_FAIL_NULL_V(action, 0.0);
  2821. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2822. ERR_FAIL_NULL_V(tracker, 0.0);
  2823. if (!running) {
  2824. return 0.0;
  2825. }
  2826. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_FLOAT_INPUT, 0.0);
  2827. XrActionStateGetInfo get_info = {
  2828. XR_TYPE_ACTION_STATE_GET_INFO, // type
  2829. nullptr, // next
  2830. action->handle, // action
  2831. tracker->toplevel_path // subactionPath
  2832. };
  2833. XrActionStateFloat result_state;
  2834. result_state.type = XR_TYPE_ACTION_STATE_FLOAT,
  2835. result_state.next = nullptr;
  2836. XrResult result = xrGetActionStateFloat(session, &get_info, &result_state);
  2837. if (XR_FAILED(result)) {
  2838. print_line("OpenXR: couldn't get action float! [", get_error_string(result), "]");
  2839. return 0.0;
  2840. }
  2841. return result_state.isActive ? result_state.currentState : 0.0;
  2842. }
  2843. Vector2 OpenXRAPI::get_action_vector2(RID p_action, RID p_tracker) {
  2844. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, Vector2());
  2845. Action *action = action_owner.get_or_null(p_action);
  2846. ERR_FAIL_NULL_V(action, Vector2());
  2847. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2848. ERR_FAIL_NULL_V(tracker, Vector2());
  2849. if (!running) {
  2850. return Vector2();
  2851. }
  2852. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_VECTOR2F_INPUT, Vector2());
  2853. XrActionStateGetInfo get_info = {
  2854. XR_TYPE_ACTION_STATE_GET_INFO, // type
  2855. nullptr, // next
  2856. action->handle, // action
  2857. tracker->toplevel_path // subactionPath
  2858. };
  2859. XrActionStateVector2f result_state;
  2860. result_state.type = XR_TYPE_ACTION_STATE_VECTOR2F,
  2861. result_state.next = nullptr;
  2862. XrResult result = xrGetActionStateVector2f(session, &get_info, &result_state);
  2863. if (XR_FAILED(result)) {
  2864. print_line("OpenXR: couldn't get action vector2! [", get_error_string(result), "]");
  2865. return Vector2();
  2866. }
  2867. return result_state.isActive ? Vector2(result_state.currentState.x, result_state.currentState.y) : Vector2();
  2868. }
  2869. XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
  2870. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  2871. Action *action = action_owner.get_or_null(p_action);
  2872. ERR_FAIL_NULL_V(action, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  2873. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2874. ERR_FAIL_NULL_V(tracker, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  2875. if (!running) {
  2876. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  2877. }
  2878. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_POSE_INPUT, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  2879. // print_verbose("Checking " + action->name + " => " + tracker->name + " (" + itos(tracker->toplevel_path) + ")");
  2880. uint64_t index = 0xFFFFFFFF;
  2881. uint64_t size = uint64_t(action->trackers.size());
  2882. for (uint64_t i = 0; i < size && index == 0xFFFFFFFF; i++) {
  2883. if (action->trackers[i].tracker_rid == p_tracker) {
  2884. index = i;
  2885. }
  2886. }
  2887. if (index == 0xFFFFFFFF) {
  2888. // couldn't find it?
  2889. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  2890. }
  2891. XrTime display_time = get_predicted_display_time();
  2892. if (display_time == 0) {
  2893. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  2894. }
  2895. if (action->trackers[index].space == XR_NULL_HANDLE) {
  2896. // if this is a pose we need to define spaces
  2897. XrActionSpaceCreateInfo action_space_info = {
  2898. XR_TYPE_ACTION_SPACE_CREATE_INFO, // type
  2899. nullptr, // next
  2900. action->handle, // action
  2901. tracker->toplevel_path, // subactionPath
  2902. {
  2903. { 0.0, 0.0, 0.0, 1.0 }, // orientation
  2904. { 0.0, 0.0, 0.0 } // position
  2905. } // poseInActionSpace
  2906. };
  2907. XrSpace space;
  2908. XrResult result = xrCreateActionSpace(session, &action_space_info, &space);
  2909. if (XR_FAILED(result)) {
  2910. print_line("OpenXR: couldn't create action space! [", get_error_string(result), "]");
  2911. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  2912. }
  2913. action->trackers.ptrw()[index].space = space;
  2914. }
  2915. XrSpaceVelocity velocity = {
  2916. XR_TYPE_SPACE_VELOCITY, // type
  2917. nullptr, // next
  2918. 0, // velocityFlags
  2919. { 0.0, 0.0, 0.0 }, // linearVelocity
  2920. { 0.0, 0.0, 0.0 } // angularVelocity
  2921. };
  2922. XrSpaceLocation location = {
  2923. XR_TYPE_SPACE_LOCATION, // type
  2924. &velocity, // next
  2925. 0, // locationFlags
  2926. {
  2927. { 0.0, 0.0, 0.0, 0.0 }, // orientation
  2928. { 0.0, 0.0, 0.0 } // position
  2929. } // pose
  2930. };
  2931. XrResult result = xrLocateSpace(action->trackers[index].space, play_space, display_time, &location);
  2932. if (XR_FAILED(result)) {
  2933. print_line("OpenXR: failed to locate space! [", get_error_string(result), "]");
  2934. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  2935. }
  2936. XRPose::TrackingConfidence confidence = transform_from_location(location, r_transform);
  2937. parse_velocities(velocity, r_linear_velocity, r_angular_velocity);
  2938. return confidence;
  2939. }
  2940. bool OpenXRAPI::trigger_haptic_pulse(RID p_action, RID p_tracker, float p_frequency, float p_amplitude, XrDuration p_duration_ns) {
  2941. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  2942. Action *action = action_owner.get_or_null(p_action);
  2943. ERR_FAIL_NULL_V(action, false);
  2944. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2945. ERR_FAIL_NULL_V(tracker, false);
  2946. if (!running) {
  2947. return false;
  2948. }
  2949. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_VIBRATION_OUTPUT, false);
  2950. XrHapticActionInfo action_info = {
  2951. XR_TYPE_HAPTIC_ACTION_INFO, // type
  2952. nullptr, // next
  2953. action->handle, // action
  2954. tracker->toplevel_path // subactionPath
  2955. };
  2956. XrHapticVibration vibration = {
  2957. XR_TYPE_HAPTIC_VIBRATION, // type
  2958. nullptr, // next
  2959. p_duration_ns, // duration
  2960. p_frequency, // frequency
  2961. p_amplitude, // amplitude
  2962. };
  2963. XrResult result = xrApplyHapticFeedback(session, &action_info, (const XrHapticBaseHeader *)&vibration);
  2964. if (XR_FAILED(result)) {
  2965. print_line("OpenXR: failed to apply haptic feedback! [", get_error_string(result), "]");
  2966. return false;
  2967. }
  2968. return true;
  2969. }
  2970. void OpenXRAPI::register_composition_layer_provider(OpenXRExtensionWrapper *p_extension) {
  2971. composition_layer_providers.append(p_extension);
  2972. }
  2973. void OpenXRAPI::unregister_composition_layer_provider(OpenXRExtensionWrapper *p_extension) {
  2974. composition_layer_providers.erase(p_extension);
  2975. }
  2976. void OpenXRAPI::register_projection_views_extension(OpenXRExtensionWrapper *p_extension) {
  2977. projection_views_extensions.append(p_extension);
  2978. }
  2979. void OpenXRAPI::unregister_projection_views_extension(OpenXRExtensionWrapper *p_extension) {
  2980. projection_views_extensions.erase(p_extension);
  2981. }
  2982. void OpenXRAPI::register_frame_info_extension(OpenXRExtensionWrapper *p_extension) {
  2983. frame_info_extensions.append(p_extension);
  2984. }
  2985. void OpenXRAPI::unregister_frame_info_extension(OpenXRExtensionWrapper *p_extension) {
  2986. frame_info_extensions.erase(p_extension);
  2987. }
  2988. const Vector<XrEnvironmentBlendMode> OpenXRAPI::get_supported_environment_blend_modes() {
  2989. return supported_environment_blend_modes;
  2990. }
  2991. bool OpenXRAPI::is_environment_blend_mode_supported(XrEnvironmentBlendMode p_blend_mode) const {
  2992. return supported_environment_blend_modes.has(p_blend_mode);
  2993. }
  2994. bool OpenXRAPI::set_environment_blend_mode(XrEnvironmentBlendMode p_blend_mode) {
  2995. if (emulate_environment_blend_mode_alpha_blend && p_blend_mode == XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND) {
  2996. requested_environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND;
  2997. environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
  2998. return true;
  2999. }
  3000. // We allow setting this when not initialized and will check if it is supported when initializing.
  3001. // After OpenXR is initialized we verify we're setting a supported blend mode.
  3002. else if (!is_initialized() || is_environment_blend_mode_supported(p_blend_mode)) {
  3003. requested_environment_blend_mode = p_blend_mode;
  3004. environment_blend_mode = p_blend_mode;
  3005. return true;
  3006. }
  3007. return false;
  3008. }
  3009. void OpenXRAPI::set_emulate_environment_blend_mode_alpha_blend(bool p_enabled) {
  3010. emulate_environment_blend_mode_alpha_blend = p_enabled;
  3011. }
  3012. OpenXRAPI::OpenXRAlphaBlendModeSupport OpenXRAPI::is_environment_blend_mode_alpha_blend_supported() {
  3013. if (emulate_environment_blend_mode_alpha_blend) {
  3014. return OPENXR_ALPHA_BLEND_MODE_SUPPORT_EMULATING;
  3015. } else if (is_environment_blend_mode_supported(XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND)) {
  3016. return OPENXR_ALPHA_BLEND_MODE_SUPPORT_REAL;
  3017. }
  3018. return OPENXR_ALPHA_BLEND_MODE_SUPPORT_NONE;
  3019. }