openxr_api.cpp 104 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163
  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 "extensions/openxr_extension_wrapper_extension.h"
  32. #include "openxr_interface.h"
  33. #include "openxr_util.h"
  34. #include "core/config/engine.h"
  35. #include "core/config/project_settings.h"
  36. #include "core/os/memory.h"
  37. #include "core/version.h"
  38. #ifdef TOOLS_ENABLED
  39. #include "editor/editor_settings.h"
  40. #endif
  41. #include "openxr_platform_inc.h"
  42. #ifdef VULKAN_ENABLED
  43. #include "extensions/platform/openxr_vulkan_extension.h"
  44. #endif
  45. #if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
  46. #include "extensions/platform/openxr_opengl_extension.h"
  47. #endif
  48. #include "extensions/openxr_composition_layer_depth_extension.h"
  49. #include "extensions/openxr_fb_display_refresh_rate_extension.h"
  50. #include "extensions/openxr_fb_foveation_extension.h"
  51. #include "extensions/openxr_fb_update_swapchain_extension.h"
  52. #include "extensions/openxr_hand_tracking_extension.h"
  53. #ifdef ANDROID_ENABLED
  54. #define OPENXR_LOADER_NAME "libopenxr_loader.so"
  55. #endif
  56. OpenXRAPI *OpenXRAPI::singleton = nullptr;
  57. Vector<OpenXRExtensionWrapper *> OpenXRAPI::registered_extension_wrappers;
  58. bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) {
  59. // @TODO we need an overrule switch so we can force enable openxr, i.e run "godot --openxr_enabled"
  60. if (Engine::get_singleton()->is_editor_hint() && p_check_run_in_editor) {
  61. // Disabled for now, using XR inside of the editor we'll be working on during the coming months.
  62. return false;
  63. } else {
  64. if (XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT) {
  65. return GLOBAL_GET("xr/openxr/enabled");
  66. } else {
  67. return XRServer::get_xr_mode() == XRServer::XRMODE_ON;
  68. }
  69. }
  70. }
  71. String OpenXRAPI::get_default_action_map_resource_name() {
  72. String name = GLOBAL_GET("xr/openxr/default_action_map");
  73. return name;
  74. }
  75. String OpenXRAPI::get_error_string(XrResult result) const {
  76. if (XR_SUCCEEDED(result)) {
  77. return String("Succeeded");
  78. }
  79. if (instance == XR_NULL_HANDLE) {
  80. Array args;
  81. args.push_back(Variant(result));
  82. return String("Error code {0}").format(args);
  83. }
  84. char resultString[XR_MAX_RESULT_STRING_SIZE];
  85. xrResultToString(instance, result, resultString);
  86. return String(resultString);
  87. }
  88. String OpenXRAPI::get_swapchain_format_name(int64_t p_swapchain_format) const {
  89. // This is rendering engine dependent...
  90. if (graphics_extension) {
  91. return graphics_extension->get_swapchain_format_name(p_swapchain_format);
  92. }
  93. return String("Swapchain format ") + String::num_int64(int64_t(p_swapchain_format));
  94. }
  95. bool OpenXRAPI::load_layer_properties() {
  96. // This queries additional layers that are available and can be initialized when we create our OpenXR instance
  97. if (layer_properties != nullptr) {
  98. // already retrieved this
  99. return true;
  100. }
  101. // Note, instance is not yet setup so we can't use get_error_string to retrieve our error
  102. XrResult result = xrEnumerateApiLayerProperties(0, &num_layer_properties, nullptr);
  103. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate number of api layer properties");
  104. layer_properties = (XrApiLayerProperties *)memalloc(sizeof(XrApiLayerProperties) * num_layer_properties);
  105. ERR_FAIL_NULL_V(layer_properties, false);
  106. for (uint32_t i = 0; i < num_layer_properties; i++) {
  107. layer_properties[i].type = XR_TYPE_API_LAYER_PROPERTIES;
  108. layer_properties[i].next = nullptr;
  109. }
  110. result = xrEnumerateApiLayerProperties(num_layer_properties, &num_layer_properties, layer_properties);
  111. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate api layer properties");
  112. for (uint32_t i = 0; i < num_layer_properties; i++) {
  113. print_verbose(String("OpenXR: Found OpenXR layer ") + layer_properties[i].layerName);
  114. }
  115. return true;
  116. }
  117. bool OpenXRAPI::load_supported_extensions() {
  118. // This queries supported extensions that are available and can be initialized when we create our OpenXR instance
  119. if (supported_extensions != nullptr) {
  120. // already retrieved this
  121. return true;
  122. }
  123. // Note, instance is not yet setup so we can't use get_error_string to retrieve our error
  124. XrResult result = xrEnumerateInstanceExtensionProperties(nullptr, 0, &num_supported_extensions, nullptr);
  125. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate number of extension properties");
  126. supported_extensions = (XrExtensionProperties *)memalloc(sizeof(XrExtensionProperties) * num_supported_extensions);
  127. ERR_FAIL_NULL_V(supported_extensions, false);
  128. // set our types
  129. for (uint32_t i = 0; i < num_supported_extensions; i++) {
  130. supported_extensions[i].type = XR_TYPE_EXTENSION_PROPERTIES;
  131. supported_extensions[i].next = nullptr;
  132. }
  133. result = xrEnumerateInstanceExtensionProperties(nullptr, num_supported_extensions, &num_supported_extensions, supported_extensions);
  134. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate extension properties");
  135. for (uint32_t i = 0; i < num_supported_extensions; i++) {
  136. print_verbose(String("OpenXR: Found OpenXR extension ") + supported_extensions[i].extensionName);
  137. }
  138. return true;
  139. }
  140. bool OpenXRAPI::is_extension_supported(const String &p_extension) const {
  141. for (uint32_t i = 0; i < num_supported_extensions; i++) {
  142. if (supported_extensions[i].extensionName == p_extension) {
  143. return true;
  144. }
  145. }
  146. return false;
  147. }
  148. bool OpenXRAPI::is_extension_enabled(const String &p_extension) const {
  149. CharString extension = p_extension.ascii();
  150. for (int i = 0; i < enabled_extensions.size(); i++) {
  151. if (strcmp(enabled_extensions[i].ptr(), extension.ptr()) == 0) {
  152. return true;
  153. }
  154. }
  155. return false;
  156. }
  157. bool OpenXRAPI::is_top_level_path_supported(const String &p_toplevel_path) {
  158. String required_extension = OpenXRInteractionProfileMetadata::get_singleton()->get_top_level_extension(p_toplevel_path);
  159. // If unsupported is returned we likely have a misspelled interaction profile path in our action map. Always output that as an error.
  160. ERR_FAIL_COND_V_MSG(required_extension == XR_PATH_UNSUPPORTED_NAME, false, "OpenXR: Unsupported toplevel path " + p_toplevel_path);
  161. if (required_extension == "") {
  162. // no extension needed, core top level are always "supported", they just won't be used if not really supported
  163. return true;
  164. }
  165. if (!is_extension_enabled(required_extension)) {
  166. // 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.
  167. print_verbose("OpenXR: Top level path " + p_toplevel_path + " requires extension " + required_extension);
  168. return false;
  169. }
  170. return true;
  171. }
  172. bool OpenXRAPI::is_interaction_profile_supported(const String &p_ip_path) {
  173. String required_extension = OpenXRInteractionProfileMetadata::get_singleton()->get_interaction_profile_extension(p_ip_path);
  174. // If unsupported is returned we likely have a misspelled interaction profile path in our action map. Always output that as an error.
  175. ERR_FAIL_COND_V_MSG(required_extension == XR_PATH_UNSUPPORTED_NAME, false, "OpenXR: Unsupported interaction profile " + p_ip_path);
  176. if (required_extension == "") {
  177. // no extension needed, core interaction profiles are always "supported", they just won't be used if not really supported
  178. return true;
  179. }
  180. if (!is_extension_enabled(required_extension)) {
  181. // It is very likely we have interaction profiles for which the extension is not available so don't flood the logs with unnecessary spam.
  182. print_verbose("OpenXR: Interaction profile " + p_ip_path + " requires extension " + required_extension);
  183. return false;
  184. }
  185. return true;
  186. }
  187. bool OpenXRAPI::interaction_profile_supports_io_path(const String &p_ip_path, const String &p_io_path) {
  188. if (!is_interaction_profile_supported(p_ip_path)) {
  189. return false;
  190. }
  191. const OpenXRInteractionProfileMetadata::IOPath *io_path = OpenXRInteractionProfileMetadata::get_singleton()->get_io_path(p_ip_path, p_io_path);
  192. // If the io_path is not part of our metadata we've likely got a misspelled name or a bad action map, report
  193. ERR_FAIL_NULL_V_MSG(io_path, false, "OpenXR: Unsupported io path " + String(p_ip_path) + String(p_io_path));
  194. if (io_path->openxr_extension_name == "") {
  195. // no extension needed, core io paths are always "supported", they just won't be used if not really supported
  196. return true;
  197. }
  198. if (!is_extension_enabled(io_path->openxr_extension_name)) {
  199. // It is very likely we have io paths for which the extension is not available so don't flood the logs with unnecessary spam.
  200. print_verbose("OpenXR: IO path " + String(p_ip_path) + String(p_io_path) + " requires extension " + io_path->openxr_extension_name);
  201. return false;
  202. }
  203. return true;
  204. }
  205. void OpenXRAPI::copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len) {
  206. CharString char_string = p_string.utf8();
  207. int len = char_string.length();
  208. if (len < p_buffer_len - 1) {
  209. // was having weird CI issues with strcpy so....
  210. memcpy(p_buffer, char_string.get_data(), len);
  211. p_buffer[len] = '\0';
  212. } else {
  213. memcpy(p_buffer, char_string.get_data(), p_buffer_len - 1);
  214. p_buffer[p_buffer_len - 1] = '\0';
  215. }
  216. }
  217. bool OpenXRAPI::create_instance() {
  218. // Create our OpenXR instance, this will query any registered extension wrappers for extensions we need to enable.
  219. // Append the extensions requested by the registered extension wrappers.
  220. HashMap<String, bool *> requested_extensions;
  221. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  222. const HashMap<String, bool *> &wrapper_request_extensions = wrapper->get_requested_extensions();
  223. for (const KeyValue<String, bool *> &requested_extension : wrapper_request_extensions) {
  224. requested_extensions[requested_extension.key] = requested_extension.value;
  225. }
  226. }
  227. // Check which extensions are supported.
  228. enabled_extensions.clear();
  229. for (KeyValue<String, bool *> &requested_extension : requested_extensions) {
  230. if (!is_extension_supported(requested_extension.key)) {
  231. if (requested_extension.value == nullptr) {
  232. // Null means this is a mandatory extension so we fail.
  233. ERR_FAIL_V_MSG(false, String("OpenXR: OpenXR Runtime does not support ") + requested_extension.key + String(" extension!"));
  234. } else {
  235. // Set this extension as not supported.
  236. *requested_extension.value = false;
  237. }
  238. } else if (requested_extension.value != nullptr) {
  239. // Set this extension as supported.
  240. *requested_extension.value = true;
  241. // And record that we want to enable it.
  242. enabled_extensions.push_back(requested_extension.key.ascii());
  243. } else {
  244. // Record that we want to enable this.
  245. enabled_extensions.push_back(requested_extension.key.ascii());
  246. }
  247. }
  248. Vector<const char *> extension_ptrs;
  249. for (int i = 0; i < enabled_extensions.size(); i++) {
  250. print_verbose(String("OpenXR: Enabling extension ") + String(enabled_extensions[i]));
  251. extension_ptrs.push_back(enabled_extensions[i].get_data());
  252. }
  253. // Get our project name
  254. String project_name = GLOBAL_GET("application/config/name");
  255. // Create our OpenXR instance
  256. XrApplicationInfo application_info{
  257. "", // applicationName, we'll set this down below
  258. 1, // applicationVersion, we don't currently have this
  259. "Godot Game Engine", // engineName
  260. VERSION_MAJOR * 10000 + VERSION_MINOR * 100 + VERSION_PATCH, // engineVersion 4.0 -> 40000, 4.0.1 -> 40001, 4.1 -> 40100, etc.
  261. XR_CURRENT_API_VERSION // apiVersion
  262. };
  263. void *next_pointer = nullptr;
  264. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  265. void *np = wrapper->set_instance_create_info_and_get_next_pointer(next_pointer);
  266. if (np != nullptr) {
  267. next_pointer = np;
  268. }
  269. }
  270. XrInstanceCreateInfo instance_create_info = {
  271. XR_TYPE_INSTANCE_CREATE_INFO, // type
  272. next_pointer, // next
  273. 0, // createFlags
  274. application_info, // applicationInfo
  275. 0, // enabledApiLayerCount, need to find out if we need support for this?
  276. nullptr, // enabledApiLayerNames
  277. uint32_t(extension_ptrs.size()), // enabledExtensionCount
  278. extension_ptrs.ptr() // enabledExtensionNames
  279. };
  280. copy_string_to_char_buffer(project_name, instance_create_info.applicationInfo.applicationName, XR_MAX_APPLICATION_NAME_SIZE);
  281. XrResult result = xrCreateInstance(&instance_create_info, &instance);
  282. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "Failed to create XR instance.");
  283. // from this point on we can use get_error_string to get more info about our errors...
  284. XrInstanceProperties instanceProps = {
  285. XR_TYPE_INSTANCE_PROPERTIES, // type;
  286. nullptr, // next
  287. 0, // runtimeVersion, from here will be set by our get call
  288. "" // runtimeName
  289. };
  290. OPENXR_API_INIT_XR_FUNC_V(xrGetInstanceProperties);
  291. result = xrGetInstanceProperties(instance, &instanceProps);
  292. if (XR_FAILED(result)) {
  293. // not fatal probably
  294. print_line("OpenXR: Failed to get XR instance properties [", get_error_string(result), "]");
  295. runtime_name = "";
  296. runtime_version = "";
  297. } else {
  298. runtime_name = instanceProps.runtimeName;
  299. runtime_version = OpenXRUtil::make_xr_version_string(instanceProps.runtimeVersion);
  300. print_line("OpenXR: Running on OpenXR runtime: ", runtime_name, " ", runtime_version);
  301. }
  302. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  303. wrapper->on_instance_created(instance);
  304. }
  305. return true;
  306. }
  307. bool OpenXRAPI::get_system_info() {
  308. // Retrieve basic OpenXR system info based on the form factor we desire
  309. // Retrieve the system for our form factor, fails if form factor is not available
  310. XrSystemGetInfo system_get_info = {
  311. XR_TYPE_SYSTEM_GET_INFO, // type;
  312. nullptr, // next
  313. form_factor // formFactor
  314. };
  315. XrResult result = xrGetSystem(instance, &system_get_info, &system_id);
  316. if (XR_FAILED(result)) {
  317. print_line("OpenXR: Failed to get system for our form factor [", get_error_string(result), "]");
  318. return false;
  319. }
  320. // obtain info about our system, writing this out completely to make CI on Linux happy..
  321. void *next_pointer = nullptr;
  322. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  323. void *np = wrapper->set_system_properties_and_get_next_pointer(next_pointer);
  324. if (np != nullptr) {
  325. next_pointer = np;
  326. }
  327. }
  328. XrSystemProperties system_properties = {
  329. XR_TYPE_SYSTEM_PROPERTIES, // type
  330. next_pointer, // next
  331. 0, // systemId, from here will be set by our get call
  332. 0, // vendorId
  333. "", // systemName
  334. {
  335. 0, // maxSwapchainImageHeight
  336. 0, // maxSwapchainImageWidth
  337. 0, // maxLayerCount
  338. }, // graphicsProperties
  339. {
  340. false, // orientationTracking
  341. false // positionTracking
  342. } // trackingProperties
  343. };
  344. result = xrGetSystemProperties(instance, system_id, &system_properties);
  345. if (XR_FAILED(result)) {
  346. print_line("OpenXR: Failed to get System properties [", get_error_string(result), "]");
  347. return false;
  348. }
  349. // remember this state, we'll use it later
  350. system_name = String(system_properties.systemName);
  351. vendor_id = system_properties.vendorId;
  352. graphics_properties = system_properties.graphicsProperties;
  353. tracking_properties = system_properties.trackingProperties;
  354. return true;
  355. }
  356. bool OpenXRAPI::load_supported_view_configuration_types() {
  357. // This queries the supported configuration types, likely there will only be one choosing between Mono (phone AR) and Stereo (HMDs)
  358. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  359. if (supported_view_configuration_types != nullptr) {
  360. // free previous results
  361. memfree(supported_view_configuration_types);
  362. supported_view_configuration_types = nullptr;
  363. }
  364. XrResult result = xrEnumerateViewConfigurations(instance, system_id, 0, &num_view_configuration_types, nullptr);
  365. if (XR_FAILED(result)) {
  366. print_line("OpenXR: Failed to get view configuration count [", get_error_string(result), "]");
  367. return false;
  368. }
  369. supported_view_configuration_types = (XrViewConfigurationType *)memalloc(sizeof(XrViewConfigurationType) * num_view_configuration_types);
  370. ERR_FAIL_NULL_V(supported_view_configuration_types, false);
  371. result = xrEnumerateViewConfigurations(instance, system_id, num_view_configuration_types, &num_view_configuration_types, supported_view_configuration_types);
  372. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerateview configurations");
  373. ERR_FAIL_COND_V_MSG(num_view_configuration_types == 0, false, "OpenXR: Failed to enumerateview configurations"); // JIC there should be at least 1!
  374. for (uint32_t i = 0; i < num_view_configuration_types; i++) {
  375. print_verbose(String("OpenXR: Found supported view configuration ") + OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[i]));
  376. }
  377. // Check value we loaded at startup...
  378. if (!is_view_configuration_supported(view_configuration)) {
  379. print_verbose(String("OpenXR: ") + OpenXRUtil::get_view_configuration_name(view_configuration) + String(" isn't supported, defaulting to ") + OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[0]));
  380. view_configuration = supported_view_configuration_types[0];
  381. }
  382. return true;
  383. }
  384. bool OpenXRAPI::load_supported_environmental_blend_modes() {
  385. // This queries the supported environmental blend modes.
  386. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  387. if (supported_environment_blend_modes != nullptr) {
  388. // free previous results
  389. memfree(supported_environment_blend_modes);
  390. supported_environment_blend_modes = nullptr;
  391. num_supported_environment_blend_modes = 0;
  392. }
  393. XrResult result = xrEnumerateEnvironmentBlendModes(instance, system_id, view_configuration, 0, &num_supported_environment_blend_modes, nullptr);
  394. if (XR_FAILED(result)) {
  395. print_line("OpenXR: Failed to get supported environmental blend mode count [", get_error_string(result), "]");
  396. return false;
  397. }
  398. supported_environment_blend_modes = (XrEnvironmentBlendMode *)memalloc(sizeof(XrEnvironmentBlendMode) * num_supported_environment_blend_modes);
  399. ERR_FAIL_NULL_V(supported_environment_blend_modes, false);
  400. result = xrEnumerateEnvironmentBlendModes(instance, system_id, view_configuration, num_supported_environment_blend_modes, &num_supported_environment_blend_modes, supported_environment_blend_modes);
  401. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate environmental blend modes");
  402. 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!
  403. for (uint32_t i = 0; i < num_supported_environment_blend_modes; i++) {
  404. print_verbose(String("OpenXR: Found environmental blend mode ") + OpenXRUtil::get_environment_blend_mode_name(supported_environment_blend_modes[i]));
  405. }
  406. // Check value we loaded at startup...
  407. if (!is_environment_blend_mode_supported(environment_blend_mode)) {
  408. 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]));
  409. environment_blend_mode = supported_environment_blend_modes[0];
  410. }
  411. return true;
  412. }
  413. bool OpenXRAPI::is_view_configuration_supported(XrViewConfigurationType p_configuration_type) const {
  414. ERR_FAIL_NULL_V(supported_view_configuration_types, false);
  415. for (uint32_t i = 0; i < num_view_configuration_types; i++) {
  416. if (supported_view_configuration_types[i] == p_configuration_type) {
  417. return true;
  418. }
  419. }
  420. return false;
  421. }
  422. bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType p_configuration_type) {
  423. // This loads our view configuration for each view so for a stereo HMD, we'll get two entries (that are likely identical)
  424. // The returned data supplies us with the recommended render target size
  425. if (!is_view_configuration_supported(p_configuration_type)) {
  426. print_line("OpenXR: View configuration ", OpenXRUtil::get_view_configuration_name(view_configuration), " is not supported.");
  427. return false;
  428. }
  429. if (view_configuration_views != nullptr) {
  430. // free previous results
  431. memfree(view_configuration_views);
  432. view_configuration_views = nullptr;
  433. }
  434. XrResult result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, 0, &view_count, nullptr);
  435. if (XR_FAILED(result)) {
  436. print_line("OpenXR: Failed to get view configuration count [", get_error_string(result), "]");
  437. return false;
  438. }
  439. view_configuration_views = (XrViewConfigurationView *)memalloc(sizeof(XrViewConfigurationView) * view_count);
  440. ERR_FAIL_NULL_V(view_configuration_views, false);
  441. for (uint32_t i = 0; i < view_count; i++) {
  442. view_configuration_views[i].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
  443. view_configuration_views[i].next = nullptr;
  444. }
  445. result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, view_count, &view_count, view_configuration_views);
  446. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate view configurations");
  447. for (uint32_t i = 0; i < view_count; i++) {
  448. print_verbose("OpenXR: Found supported view configuration view");
  449. print_verbose(String(" - width: ") + itos(view_configuration_views[i].maxImageRectWidth));
  450. print_verbose(String(" - height: ") + itos(view_configuration_views[i].maxImageRectHeight));
  451. print_verbose(String(" - sample count: ") + itos(view_configuration_views[i].maxSwapchainSampleCount));
  452. print_verbose(String(" - recommended render width: ") + itos(view_configuration_views[i].recommendedImageRectWidth));
  453. print_verbose(String(" - recommended render height: ") + itos(view_configuration_views[i].recommendedImageRectHeight));
  454. print_verbose(String(" - recommended render sample count: ") + itos(view_configuration_views[i].recommendedSwapchainSampleCount));
  455. }
  456. return true;
  457. }
  458. void OpenXRAPI::destroy_instance() {
  459. if (view_configuration_views != nullptr) {
  460. memfree(view_configuration_views);
  461. view_configuration_views = nullptr;
  462. }
  463. if (supported_view_configuration_types != nullptr) {
  464. memfree(supported_view_configuration_types);
  465. supported_view_configuration_types = nullptr;
  466. }
  467. if (supported_environment_blend_modes != nullptr) {
  468. memfree(supported_environment_blend_modes);
  469. supported_environment_blend_modes = nullptr;
  470. num_supported_environment_blend_modes = 0;
  471. }
  472. if (instance != XR_NULL_HANDLE) {
  473. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  474. wrapper->on_instance_destroyed();
  475. }
  476. xrDestroyInstance(instance);
  477. instance = XR_NULL_HANDLE;
  478. }
  479. enabled_extensions.clear();
  480. if (graphics_extension != nullptr) {
  481. unregister_extension_wrapper(graphics_extension);
  482. memdelete(graphics_extension);
  483. graphics_extension = nullptr;
  484. }
  485. }
  486. bool OpenXRAPI::create_session() {
  487. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  488. ERR_FAIL_COND_V(session != XR_NULL_HANDLE, false);
  489. void *next_pointer = nullptr;
  490. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  491. void *np = wrapper->set_session_create_and_get_next_pointer(next_pointer);
  492. if (np != nullptr) {
  493. next_pointer = np;
  494. }
  495. }
  496. XrSessionCreateInfo session_create_info = {
  497. XR_TYPE_SESSION_CREATE_INFO, // type
  498. next_pointer, // next
  499. 0, // createFlags
  500. system_id // systemId
  501. };
  502. XrResult result = xrCreateSession(instance, &session_create_info, &session);
  503. if (XR_FAILED(result)) {
  504. print_line("OpenXR: Failed to create session [", get_error_string(result), "]");
  505. return false;
  506. }
  507. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  508. wrapper->on_session_created(session);
  509. }
  510. return true;
  511. }
  512. bool OpenXRAPI::load_supported_reference_spaces() {
  513. // loads the supported reference spaces for our OpenXR session
  514. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  515. if (supported_reference_spaces != nullptr) {
  516. // free previous results
  517. memfree(supported_reference_spaces);
  518. supported_reference_spaces = nullptr;
  519. }
  520. XrResult result = xrEnumerateReferenceSpaces(session, 0, &num_reference_spaces, nullptr);
  521. if (XR_FAILED(result)) {
  522. print_line("OpenXR: Failed to get reference space count [", get_error_string(result), "]");
  523. return false;
  524. }
  525. supported_reference_spaces = (XrReferenceSpaceType *)memalloc(sizeof(XrReferenceSpaceType) * num_reference_spaces);
  526. ERR_FAIL_NULL_V(supported_reference_spaces, false);
  527. result = xrEnumerateReferenceSpaces(session, num_reference_spaces, &num_reference_spaces, supported_reference_spaces);
  528. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate reference spaces");
  529. ERR_FAIL_COND_V_MSG(num_reference_spaces == 0, false, "OpenXR: Failed to enumerate reference spaces");
  530. for (uint32_t i = 0; i < num_reference_spaces; i++) {
  531. print_verbose(String("OpenXR: Found supported reference space ") + OpenXRUtil::get_reference_space_name(supported_reference_spaces[i]));
  532. }
  533. return true;
  534. }
  535. bool OpenXRAPI::is_reference_space_supported(XrReferenceSpaceType p_reference_space) {
  536. ERR_FAIL_NULL_V(supported_reference_spaces, false);
  537. for (uint32_t i = 0; i < num_reference_spaces; i++) {
  538. if (supported_reference_spaces[i] == p_reference_space) {
  539. return true;
  540. }
  541. }
  542. return false;
  543. }
  544. bool OpenXRAPI::setup_play_space() {
  545. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  546. XrPosef identityPose = {
  547. { 0.0, 0.0, 0.0, 1.0 },
  548. { 0.0, 0.0, 0.0 }
  549. };
  550. XrReferenceSpaceType new_reference_space;
  551. XrSpace new_play_space = XR_NULL_HANDLE;
  552. bool will_emulate_local_floor = false;
  553. if (is_reference_space_supported(requested_reference_space)) {
  554. new_reference_space = requested_reference_space;
  555. } else if (requested_reference_space == XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT && is_reference_space_supported(XR_REFERENCE_SPACE_TYPE_STAGE)) {
  556. print_verbose("OpenXR: LOCAL_FLOOR space isn't supported, emulating using STAGE and LOCAL spaces.");
  557. new_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
  558. will_emulate_local_floor = true;
  559. } else {
  560. // Fallback on LOCAL, which all OpenXR runtimes are required to support.
  561. print_verbose(String("OpenXR: ") + OpenXRUtil::get_reference_space_name(requested_reference_space) + String(" isn't supported, defaulting to LOCAL space."));
  562. new_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
  563. }
  564. XrReferenceSpaceCreateInfo play_space_create_info = {
  565. XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
  566. nullptr, // next
  567. new_reference_space, // referenceSpaceType
  568. identityPose, // poseInReferenceSpace
  569. };
  570. XrResult result = xrCreateReferenceSpace(session, &play_space_create_info, &new_play_space);
  571. if (XR_FAILED(result)) {
  572. print_line("OpenXR: Failed to create play space [", get_error_string(result), "]");
  573. return false;
  574. }
  575. // If we've previously created a play space, clean it up first.
  576. if (play_space != XR_NULL_HANDLE) {
  577. xrDestroySpace(play_space);
  578. }
  579. play_space = new_play_space;
  580. reference_space = new_reference_space;
  581. emulating_local_floor = will_emulate_local_floor;
  582. if (emulating_local_floor) {
  583. // We'll use the STAGE space to get the floor height, but we can't do that until
  584. // after xrWaitFrame(), so just set this flag for now.
  585. should_reset_emulated_floor_height = true;
  586. }
  587. return true;
  588. }
  589. bool OpenXRAPI::setup_view_space() {
  590. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  591. if (!is_reference_space_supported(XR_REFERENCE_SPACE_TYPE_VIEW)) {
  592. print_line("OpenXR: reference space XR_REFERENCE_SPACE_TYPE_VIEW is not supported.");
  593. return false;
  594. }
  595. XrPosef identityPose = {
  596. { 0.0, 0.0, 0.0, 1.0 },
  597. { 0.0, 0.0, 0.0 }
  598. };
  599. XrReferenceSpaceCreateInfo view_space_create_info = {
  600. XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
  601. nullptr, // next
  602. XR_REFERENCE_SPACE_TYPE_VIEW, // referenceSpaceType
  603. identityPose // poseInReferenceSpace
  604. };
  605. XrResult result = xrCreateReferenceSpace(session, &view_space_create_info, &view_space);
  606. if (XR_FAILED(result)) {
  607. print_line("OpenXR: Failed to create view space [", get_error_string(result), "]");
  608. return false;
  609. }
  610. return true;
  611. }
  612. bool OpenXRAPI::reset_emulated_floor_height() {
  613. ERR_FAIL_COND_V(!emulating_local_floor, false);
  614. // This is based on the example code in the OpenXR spec which shows how to
  615. // emulate LOCAL_FLOOR if it's not supported.
  616. // See: https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_EXT_local_floor
  617. XrResult result;
  618. XrPosef identityPose = {
  619. { 0.0, 0.0, 0.0, 1.0 },
  620. { 0.0, 0.0, 0.0 }
  621. };
  622. XrSpace local_space = XR_NULL_HANDLE;
  623. XrSpace stage_space = XR_NULL_HANDLE;
  624. XrReferenceSpaceCreateInfo create_info = {
  625. XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
  626. nullptr, // next
  627. XR_REFERENCE_SPACE_TYPE_LOCAL, // referenceSpaceType
  628. identityPose, // poseInReferenceSpace
  629. };
  630. result = xrCreateReferenceSpace(session, &create_info, &local_space);
  631. if (XR_FAILED(result)) {
  632. print_line("OpenXR: Failed to create LOCAL space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
  633. return false;
  634. }
  635. create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
  636. result = xrCreateReferenceSpace(session, &create_info, &stage_space);
  637. if (XR_FAILED(result)) {
  638. print_line("OpenXR: Failed to create STAGE space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
  639. xrDestroySpace(local_space);
  640. return false;
  641. }
  642. XrSpaceLocation stage_location = {
  643. XR_TYPE_SPACE_LOCATION, // type
  644. nullptr, // next
  645. 0, // locationFlags
  646. identityPose, // pose
  647. };
  648. result = xrLocateSpace(stage_space, local_space, get_next_frame_time(), &stage_location);
  649. xrDestroySpace(local_space);
  650. xrDestroySpace(stage_space);
  651. if (XR_FAILED(result)) {
  652. print_line("OpenXR: Failed to locate STAGE space in LOCAL space, in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
  653. return false;
  654. }
  655. XrSpace new_play_space;
  656. create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
  657. create_info.poseInReferenceSpace.position.y = stage_location.pose.position.y;
  658. result = xrCreateReferenceSpace(session, &create_info, &new_play_space);
  659. if (XR_FAILED(result)) {
  660. print_line("OpenXR: Failed to recreate emulated LOCAL_FLOOR play space with latest floor estimate [", get_error_string(result), "]");
  661. return false;
  662. }
  663. xrDestroySpace(play_space);
  664. play_space = new_play_space;
  665. // If we've made it this far, it means we can properly emulate LOCAL_FLOOR, so we'll
  666. // report that as the reference space to the outside world.
  667. reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
  668. return true;
  669. }
  670. bool OpenXRAPI::load_supported_swapchain_formats() {
  671. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  672. if (supported_swapchain_formats != nullptr) {
  673. // free previous results
  674. memfree(supported_swapchain_formats);
  675. supported_swapchain_formats = nullptr;
  676. }
  677. XrResult result = xrEnumerateSwapchainFormats(session, 0, &num_swapchain_formats, nullptr);
  678. if (XR_FAILED(result)) {
  679. print_line("OpenXR: Failed to get swapchain format count [", get_error_string(result), "]");
  680. return false;
  681. }
  682. supported_swapchain_formats = (int64_t *)memalloc(sizeof(int64_t) * num_swapchain_formats);
  683. ERR_FAIL_NULL_V(supported_swapchain_formats, false);
  684. result = xrEnumerateSwapchainFormats(session, num_swapchain_formats, &num_swapchain_formats, supported_swapchain_formats);
  685. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate swapchain formats");
  686. for (uint32_t i = 0; i < num_swapchain_formats; i++) {
  687. print_verbose(String("OpenXR: Found supported swapchain format ") + get_swapchain_format_name(supported_swapchain_formats[i]));
  688. }
  689. return true;
  690. }
  691. bool OpenXRAPI::is_swapchain_format_supported(int64_t p_swapchain_format) {
  692. ERR_FAIL_NULL_V(supported_swapchain_formats, false);
  693. for (uint32_t i = 0; i < num_swapchain_formats; i++) {
  694. if (supported_swapchain_formats[i] == p_swapchain_format) {
  695. return true;
  696. }
  697. }
  698. return false;
  699. }
  700. bool OpenXRAPI::create_swapchains() {
  701. ERR_FAIL_NULL_V(graphics_extension, false);
  702. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  703. /*
  704. TODO: We need to improve on this, for now we're taking our old approach of creating our main swapchains and substituting
  705. those for the ones Godot normally creates.
  706. This however means we can only use swapchains for our main XR view.
  707. It would have been nicer if we could override the swapchain creation in Godot with ours but we have a timing issue here.
  708. We can't create XR swapchains until after our XR session is fully instantiated, yet Godot creates its swapchain much earlier.
  709. Also Godot only creates a swapchain for the main output.
  710. OpenXR will require us to create swapchains as the render target for additional viewports if we want to use the layer system
  711. to optimize text rendering and background rendering as OpenXR may choose to reuse the results for reprojection while we're
  712. already rendering the next frame.
  713. Finally an area we need to expand upon is that Foveated rendering is only enabled for the swap chain we create,
  714. as we render 3D content into internal buffers that are copied into the swapchain, we do now have (basic) VRS support
  715. */
  716. Size2 recommended_size = get_recommended_target_size();
  717. uint32_t sample_count = 1;
  718. // We start with our color swapchain...
  719. {
  720. // Build a vector with swapchain formats we want to use, from best fit to worst
  721. Vector<int64_t> usable_swapchain_formats;
  722. int64_t swapchain_format_to_use = 0;
  723. graphics_extension->get_usable_swapchain_formats(usable_swapchain_formats);
  724. // now find out which one is supported
  725. for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) {
  726. if (is_swapchain_format_supported(usable_swapchain_formats[i])) {
  727. swapchain_format_to_use = usable_swapchain_formats[i];
  728. }
  729. }
  730. if (swapchain_format_to_use == 0) {
  731. swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best...
  732. print_line("Couldn't find usable color swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead.");
  733. } else {
  734. print_verbose(String("Using color swap chain format:") + get_swapchain_format_name(swapchain_format_to_use));
  735. }
  736. if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, sample_count, view_count, swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain, &swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data)) {
  737. return false;
  738. }
  739. }
  740. views = (XrView *)memalloc(sizeof(XrView) * view_count);
  741. ERR_FAIL_NULL_V_MSG(views, false, "OpenXR Couldn't allocate memory for views");
  742. projection_views = (XrCompositionLayerProjectionView *)memalloc(sizeof(XrCompositionLayerProjectionView) * view_count);
  743. ERR_FAIL_NULL_V_MSG(projection_views, false, "OpenXR Couldn't allocate memory for projection views");
  744. // We create our depth swapchain if:
  745. // - we've enabled submitting depth buffer
  746. // - we support our depth layer extension
  747. // - we have our spacewarp extension (not yet implemented)
  748. if (submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) {
  749. // Build a vector with swapchain formats we want to use, from best fit to worst
  750. Vector<int64_t> usable_swapchain_formats;
  751. int64_t swapchain_format_to_use = 0;
  752. graphics_extension->get_usable_depth_formats(usable_swapchain_formats);
  753. // now find out which one is supported
  754. for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) {
  755. if (is_swapchain_format_supported(usable_swapchain_formats[i])) {
  756. swapchain_format_to_use = usable_swapchain_formats[i];
  757. }
  758. }
  759. if (swapchain_format_to_use == 0) {
  760. print_line("Couldn't find usable depth swap chain format, depth buffer will not be submitted.");
  761. } else {
  762. print_verbose(String("Using depth swap chain format:") + get_swapchain_format_name(swapchain_format_to_use));
  763. // Note, if VK_FORMAT_D32_SFLOAT is used here but we're using the forward+ renderer, we should probably output a warning.
  764. if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, sample_count, view_count, swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain, &swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data)) {
  765. return false;
  766. }
  767. depth_views = (XrCompositionLayerDepthInfoKHR *)memalloc(sizeof(XrCompositionLayerDepthInfoKHR) * view_count);
  768. ERR_FAIL_NULL_V_MSG(depth_views, false, "OpenXR Couldn't allocate memory for depth views");
  769. }
  770. }
  771. // We create our velocity swapchain if:
  772. // - we have our spacewarp extension (not yet implemented)
  773. {
  774. // TBD
  775. }
  776. for (uint32_t i = 0; i < view_count; i++) {
  777. views[i].type = XR_TYPE_VIEW;
  778. views[i].next = nullptr;
  779. projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
  780. projection_views[i].next = nullptr;
  781. projection_views[i].subImage.swapchain = swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain;
  782. projection_views[i].subImage.imageArrayIndex = i;
  783. projection_views[i].subImage.imageRect.offset.x = 0;
  784. projection_views[i].subImage.imageRect.offset.y = 0;
  785. projection_views[i].subImage.imageRect.extent.width = recommended_size.width;
  786. projection_views[i].subImage.imageRect.extent.height = recommended_size.height;
  787. if (submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available() && depth_views) {
  788. projection_views[i].next = &depth_views[i];
  789. depth_views[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR;
  790. depth_views[i].next = nullptr;
  791. depth_views[i].subImage.swapchain = swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain;
  792. depth_views[i].subImage.imageArrayIndex = i;
  793. depth_views[i].subImage.imageRect.offset.x = 0;
  794. depth_views[i].subImage.imageRect.offset.y = 0;
  795. depth_views[i].subImage.imageRect.extent.width = recommended_size.width;
  796. depth_views[i].subImage.imageRect.extent.height = recommended_size.height;
  797. depth_views[i].minDepth = 0.0;
  798. depth_views[i].maxDepth = 1.0;
  799. depth_views[i].nearZ = 0.01; // Near and far Z will be set to the correct values in fill_projection_matrix
  800. depth_views[i].farZ = 100.0;
  801. }
  802. };
  803. return true;
  804. };
  805. void OpenXRAPI::destroy_session() {
  806. if (running && session != XR_NULL_HANDLE) {
  807. xrEndSession(session);
  808. }
  809. if (graphics_extension) {
  810. graphics_extension->cleanup_swapchain_graphics_data(&swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data);
  811. }
  812. if (views != nullptr) {
  813. memfree(views);
  814. views = nullptr;
  815. }
  816. if (projection_views != nullptr) {
  817. memfree(projection_views);
  818. projection_views = nullptr;
  819. }
  820. if (depth_views != nullptr) {
  821. memfree(depth_views);
  822. depth_views = nullptr;
  823. }
  824. for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) {
  825. if (swapchains[i].swapchain != XR_NULL_HANDLE) {
  826. xrDestroySwapchain(swapchains[i].swapchain);
  827. swapchains[i].swapchain = XR_NULL_HANDLE;
  828. }
  829. }
  830. if (supported_swapchain_formats != nullptr) {
  831. memfree(supported_swapchain_formats);
  832. supported_swapchain_formats = nullptr;
  833. }
  834. // destroy our spaces
  835. if (play_space != XR_NULL_HANDLE) {
  836. xrDestroySpace(play_space);
  837. play_space = XR_NULL_HANDLE;
  838. }
  839. if (view_space != XR_NULL_HANDLE) {
  840. xrDestroySpace(view_space);
  841. view_space = XR_NULL_HANDLE;
  842. }
  843. if (supported_reference_spaces != nullptr) {
  844. // free previous results
  845. memfree(supported_reference_spaces);
  846. supported_reference_spaces = nullptr;
  847. }
  848. if (session != XR_NULL_HANDLE) {
  849. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  850. wrapper->on_session_destroyed();
  851. }
  852. xrDestroySession(session);
  853. session = XR_NULL_HANDLE;
  854. }
  855. }
  856. bool OpenXRAPI::create_swapchain(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, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data) {
  857. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  858. ERR_FAIL_NULL_V(graphics_extension, false);
  859. XrResult result;
  860. void *next_pointer = nullptr;
  861. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  862. void *np = wrapper->set_swapchain_create_info_and_get_next_pointer(next_pointer);
  863. if (np != nullptr) {
  864. next_pointer = np;
  865. }
  866. }
  867. XrSwapchainCreateInfo swapchain_create_info = {
  868. XR_TYPE_SWAPCHAIN_CREATE_INFO, // type
  869. next_pointer, // next
  870. 0, // createFlags
  871. p_usage_flags, // usageFlags
  872. p_swapchain_format, // format
  873. p_sample_count, // sampleCount
  874. p_width, // width
  875. p_height, // height
  876. 1, // faceCount
  877. p_array_size, // arraySize
  878. 1 // mipCount
  879. };
  880. XrSwapchain new_swapchain;
  881. result = xrCreateSwapchain(session, &swapchain_create_info, &new_swapchain);
  882. if (XR_FAILED(result)) {
  883. print_line("OpenXR: Failed to get swapchain [", get_error_string(result), "]");
  884. return false;
  885. }
  886. if (!graphics_extension->get_swapchain_image_data(new_swapchain, p_swapchain_format, p_width, p_height, p_sample_count, p_array_size, r_swapchain_graphics_data)) {
  887. xrDestroySwapchain(new_swapchain);
  888. return false;
  889. }
  890. r_swapchain = new_swapchain;
  891. return true;
  892. }
  893. bool OpenXRAPI::on_state_idle() {
  894. print_verbose("On state idle");
  895. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  896. wrapper->on_state_idle();
  897. }
  898. return true;
  899. }
  900. bool OpenXRAPI::on_state_ready() {
  901. print_verbose("On state ready");
  902. // begin session
  903. XrSessionBeginInfo session_begin_info = {
  904. XR_TYPE_SESSION_BEGIN_INFO, // type
  905. nullptr, // next
  906. view_configuration // primaryViewConfigurationType
  907. };
  908. XrResult result = xrBeginSession(session, &session_begin_info);
  909. if (XR_FAILED(result)) {
  910. print_line("OpenXR: Failed to begin session [", get_error_string(result), "]");
  911. return false;
  912. }
  913. // This is when we create our swapchain, this can be a "long" time after Godot finishes, we can deal with this for now
  914. // but once we want to provide Viewports for additional layers where OpenXR requires us to create further swapchains,
  915. // we'll be creating those viewport WAY before we reach this point.
  916. // We may need to implement a wait in our init in main.cpp polling our events until the session is ready.
  917. // That will be very very ugly
  918. // The other possibility is to create a separate OpenXRViewport type specifically for this goal as part of our OpenXR module
  919. if (!create_swapchains()) {
  920. return false;
  921. }
  922. // we're running
  923. running = true;
  924. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  925. wrapper->on_state_ready();
  926. }
  927. if (xr_interface) {
  928. xr_interface->on_state_ready();
  929. }
  930. // TODO Tell android
  931. return true;
  932. }
  933. bool OpenXRAPI::on_state_synchronized() {
  934. print_verbose("On state synchronized");
  935. // Just in case, see if we already have active trackers...
  936. List<RID> trackers;
  937. tracker_owner.get_owned_list(&trackers);
  938. for (int i = 0; i < trackers.size(); i++) {
  939. tracker_check_profile(trackers[i]);
  940. }
  941. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  942. wrapper->on_state_synchronized();
  943. }
  944. return true;
  945. }
  946. bool OpenXRAPI::on_state_visible() {
  947. print_verbose("On state visible");
  948. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  949. wrapper->on_state_visible();
  950. }
  951. if (xr_interface) {
  952. xr_interface->on_state_visible();
  953. }
  954. return true;
  955. }
  956. bool OpenXRAPI::on_state_focused() {
  957. print_verbose("On state focused");
  958. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  959. wrapper->on_state_focused();
  960. }
  961. if (xr_interface) {
  962. xr_interface->on_state_focused();
  963. }
  964. return true;
  965. }
  966. bool OpenXRAPI::on_state_stopping() {
  967. print_verbose("On state stopping");
  968. if (xr_interface) {
  969. xr_interface->on_state_stopping();
  970. }
  971. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  972. wrapper->on_state_stopping();
  973. }
  974. if (running) {
  975. XrResult result = xrEndSession(session);
  976. if (XR_FAILED(result)) {
  977. // we only report this..
  978. print_line("OpenXR: Failed to end session [", get_error_string(result), "]");
  979. }
  980. running = false;
  981. }
  982. // TODO further cleanup
  983. return true;
  984. }
  985. bool OpenXRAPI::on_state_loss_pending() {
  986. print_verbose("On state loss pending");
  987. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  988. wrapper->on_state_loss_pending();
  989. }
  990. // TODO need to look into the correct action here, read up on the spec but we may need to signal Godot to exit (if it's not already exiting)
  991. return true;
  992. }
  993. bool OpenXRAPI::on_state_exiting() {
  994. print_verbose("On state existing");
  995. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  996. wrapper->on_state_exiting();
  997. }
  998. // TODO need to look into the correct action here, read up on the spec but we may need to signal Godot to exit (if it's not already exiting)
  999. return true;
  1000. }
  1001. void OpenXRAPI::set_form_factor(XrFormFactor p_form_factor) {
  1002. ERR_FAIL_COND(is_initialized());
  1003. form_factor = p_form_factor;
  1004. }
  1005. void OpenXRAPI::set_view_configuration(XrViewConfigurationType p_view_configuration) {
  1006. ERR_FAIL_COND(is_initialized());
  1007. view_configuration = p_view_configuration;
  1008. }
  1009. bool OpenXRAPI::set_requested_reference_space(XrReferenceSpaceType p_requested_reference_space) {
  1010. requested_reference_space = p_requested_reference_space;
  1011. if (is_initialized()) {
  1012. return setup_play_space();
  1013. }
  1014. return true;
  1015. }
  1016. void OpenXRAPI::set_submit_depth_buffer(bool p_submit_depth_buffer) {
  1017. ERR_FAIL_COND(is_initialized());
  1018. submit_depth_buffer = p_submit_depth_buffer;
  1019. }
  1020. bool OpenXRAPI::is_initialized() {
  1021. return (instance != XR_NULL_HANDLE);
  1022. }
  1023. bool OpenXRAPI::is_running() {
  1024. if (instance == XR_NULL_HANDLE) {
  1025. return false;
  1026. }
  1027. if (session == XR_NULL_HANDLE) {
  1028. return false;
  1029. }
  1030. return running;
  1031. }
  1032. bool OpenXRAPI::openxr_loader_init() {
  1033. #ifdef ANDROID_ENABLED
  1034. ERR_FAIL_COND_V_MSG(openxr_loader_library_handle != nullptr, false, "OpenXR Loader library is already loaded.");
  1035. {
  1036. Error error_code = OS::get_singleton()->open_dynamic_library(OPENXR_LOADER_NAME, openxr_loader_library_handle);
  1037. ERR_FAIL_COND_V_MSG(error_code != OK, false, "OpenXR loader not found.");
  1038. }
  1039. {
  1040. Error error_code = OS::get_singleton()->get_dynamic_library_symbol_handle(openxr_loader_library_handle, "xrGetInstanceProcAddr", (void *&)xrGetInstanceProcAddr);
  1041. ERR_FAIL_COND_V_MSG(error_code != OK, false, "Symbol xrGetInstanceProcAddr not found in OpenXR Loader library.");
  1042. }
  1043. #endif
  1044. // Resolve the symbols that don't require an instance
  1045. OPENXR_API_INIT_XR_FUNC_V(xrCreateInstance);
  1046. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateApiLayerProperties);
  1047. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateInstanceExtensionProperties);
  1048. return true;
  1049. }
  1050. bool OpenXRAPI::resolve_instance_openxr_symbols() {
  1051. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  1052. OPENXR_API_INIT_XR_FUNC_V(xrAcquireSwapchainImage);
  1053. OPENXR_API_INIT_XR_FUNC_V(xrApplyHapticFeedback);
  1054. OPENXR_API_INIT_XR_FUNC_V(xrAttachSessionActionSets);
  1055. OPENXR_API_INIT_XR_FUNC_V(xrBeginFrame);
  1056. OPENXR_API_INIT_XR_FUNC_V(xrBeginSession);
  1057. OPENXR_API_INIT_XR_FUNC_V(xrCreateAction);
  1058. OPENXR_API_INIT_XR_FUNC_V(xrCreateActionSet);
  1059. OPENXR_API_INIT_XR_FUNC_V(xrCreateActionSpace);
  1060. OPENXR_API_INIT_XR_FUNC_V(xrCreateReferenceSpace);
  1061. OPENXR_API_INIT_XR_FUNC_V(xrCreateSession);
  1062. OPENXR_API_INIT_XR_FUNC_V(xrCreateSwapchain);
  1063. OPENXR_API_INIT_XR_FUNC_V(xrDestroyAction);
  1064. OPENXR_API_INIT_XR_FUNC_V(xrDestroyActionSet);
  1065. OPENXR_API_INIT_XR_FUNC_V(xrDestroyInstance);
  1066. OPENXR_API_INIT_XR_FUNC_V(xrDestroySession);
  1067. OPENXR_API_INIT_XR_FUNC_V(xrDestroySpace);
  1068. OPENXR_API_INIT_XR_FUNC_V(xrDestroySwapchain);
  1069. OPENXR_API_INIT_XR_FUNC_V(xrEndFrame);
  1070. OPENXR_API_INIT_XR_FUNC_V(xrEndSession);
  1071. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateEnvironmentBlendModes);
  1072. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateReferenceSpaces);
  1073. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateSwapchainFormats);
  1074. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateViewConfigurations);
  1075. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateViewConfigurationViews);
  1076. OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateBoolean);
  1077. OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateFloat);
  1078. OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateVector2f);
  1079. OPENXR_API_INIT_XR_FUNC_V(xrGetCurrentInteractionProfile);
  1080. OPENXR_API_INIT_XR_FUNC_V(xrGetReferenceSpaceBoundsRect);
  1081. OPENXR_API_INIT_XR_FUNC_V(xrGetSystem);
  1082. OPENXR_API_INIT_XR_FUNC_V(xrGetSystemProperties);
  1083. OPENXR_API_INIT_XR_FUNC_V(xrLocateViews);
  1084. OPENXR_API_INIT_XR_FUNC_V(xrLocateSpace);
  1085. OPENXR_API_INIT_XR_FUNC_V(xrPathToString);
  1086. OPENXR_API_INIT_XR_FUNC_V(xrPollEvent);
  1087. OPENXR_API_INIT_XR_FUNC_V(xrReleaseSwapchainImage);
  1088. OPENXR_API_INIT_XR_FUNC_V(xrResultToString);
  1089. OPENXR_API_INIT_XR_FUNC_V(xrStringToPath);
  1090. OPENXR_API_INIT_XR_FUNC_V(xrSuggestInteractionProfileBindings);
  1091. OPENXR_API_INIT_XR_FUNC_V(xrSyncActions);
  1092. OPENXR_API_INIT_XR_FUNC_V(xrWaitFrame);
  1093. OPENXR_API_INIT_XR_FUNC_V(xrWaitSwapchainImage);
  1094. return true;
  1095. }
  1096. XrResult OpenXRAPI::try_get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr) {
  1097. return xrGetInstanceProcAddr(instance, p_name, p_addr);
  1098. }
  1099. XrResult OpenXRAPI::get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr) {
  1100. XrResult result = try_get_instance_proc_addr(p_name, p_addr);
  1101. if (result != XR_SUCCESS) {
  1102. String error_message = String("Symbol ") + p_name + " not found in OpenXR instance.";
  1103. ERR_FAIL_V_MSG(result, error_message.utf8().get_data());
  1104. }
  1105. return result;
  1106. }
  1107. bool OpenXRAPI::initialize(const String &p_rendering_driver) {
  1108. ERR_FAIL_COND_V_MSG(instance != XR_NULL_HANDLE, false, "OpenXR instance was already created");
  1109. if (!openxr_loader_init()) {
  1110. return false;
  1111. }
  1112. if (p_rendering_driver == "vulkan") {
  1113. #ifdef VULKAN_ENABLED
  1114. graphics_extension = memnew(OpenXRVulkanExtension);
  1115. register_extension_wrapper(graphics_extension);
  1116. #else
  1117. // shouldn't be possible...
  1118. ERR_FAIL_V(false);
  1119. #endif
  1120. } else if (p_rendering_driver == "opengl3") {
  1121. #if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
  1122. graphics_extension = memnew(OpenXROpenGLExtension);
  1123. register_extension_wrapper(graphics_extension);
  1124. #else
  1125. // shouldn't be possible...
  1126. ERR_FAIL_V(false);
  1127. #endif
  1128. } else {
  1129. ERR_FAIL_V_MSG(false, "OpenXR: Unsupported rendering device.");
  1130. }
  1131. // Also register our rendering extensions
  1132. register_extension_wrapper(memnew(OpenXRFBUpdateSwapchainExtension(p_rendering_driver)));
  1133. register_extension_wrapper(memnew(OpenXRFBFoveationExtension(p_rendering_driver)));
  1134. // initialize
  1135. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1136. wrapper->on_before_instance_created();
  1137. }
  1138. if (!load_layer_properties()) {
  1139. destroy_instance();
  1140. return false;
  1141. }
  1142. if (!load_supported_extensions()) {
  1143. destroy_instance();
  1144. return false;
  1145. }
  1146. if (!create_instance()) {
  1147. destroy_instance();
  1148. return false;
  1149. }
  1150. if (!resolve_instance_openxr_symbols()) {
  1151. destroy_instance();
  1152. return false;
  1153. }
  1154. if (!get_system_info()) {
  1155. destroy_instance();
  1156. return false;
  1157. }
  1158. if (!load_supported_view_configuration_types()) {
  1159. destroy_instance();
  1160. return false;
  1161. }
  1162. if (!load_supported_view_configuration_views(view_configuration)) {
  1163. destroy_instance();
  1164. return false;
  1165. }
  1166. if (!load_supported_environmental_blend_modes()) {
  1167. destroy_instance();
  1168. return false;
  1169. }
  1170. return true;
  1171. }
  1172. bool OpenXRAPI::initialize_session() {
  1173. if (!create_session()) {
  1174. destroy_session();
  1175. return false;
  1176. }
  1177. if (!load_supported_reference_spaces()) {
  1178. destroy_session();
  1179. return false;
  1180. }
  1181. if (!setup_play_space()) {
  1182. destroy_session();
  1183. return false;
  1184. }
  1185. if (!setup_view_space()) {
  1186. destroy_session();
  1187. return false;
  1188. }
  1189. if (!load_supported_swapchain_formats()) {
  1190. destroy_session();
  1191. return false;
  1192. }
  1193. return true;
  1194. }
  1195. void OpenXRAPI::finish() {
  1196. destroy_session();
  1197. destroy_instance();
  1198. }
  1199. void OpenXRAPI::set_xr_interface(OpenXRInterface *p_xr_interface) {
  1200. xr_interface = p_xr_interface;
  1201. }
  1202. void OpenXRAPI::register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) {
  1203. registered_extension_wrappers.push_back(p_extension_wrapper);
  1204. }
  1205. void OpenXRAPI::unregister_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) {
  1206. registered_extension_wrappers.erase(p_extension_wrapper);
  1207. }
  1208. const Vector<OpenXRExtensionWrapper *> &OpenXRAPI::get_registered_extension_wrappers() {
  1209. return registered_extension_wrappers;
  1210. }
  1211. void OpenXRAPI::register_extension_metadata() {
  1212. for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) {
  1213. extension_wrapper->on_register_metadata();
  1214. }
  1215. }
  1216. void OpenXRAPI::cleanup_extension_wrappers() {
  1217. for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) {
  1218. // Fix crash when the extension wrapper comes from GDExtension.
  1219. OpenXRExtensionWrapperExtension *gdextension_extension_wrapper = dynamic_cast<OpenXRExtensionWrapperExtension *>(extension_wrapper);
  1220. if (gdextension_extension_wrapper) {
  1221. memdelete(gdextension_extension_wrapper);
  1222. } else {
  1223. memdelete(extension_wrapper);
  1224. }
  1225. }
  1226. registered_extension_wrappers.clear();
  1227. }
  1228. XrHandTrackerEXT OpenXRAPI::get_hand_tracker(int p_hand_index) {
  1229. ERR_FAIL_INDEX_V(p_hand_index, OpenXRHandTrackingExtension::HandTrackedHands::OPENXR_MAX_TRACKED_HANDS, XR_NULL_HANDLE);
  1230. OpenXRHandTrackingExtension::HandTrackedHands hand = static_cast<OpenXRHandTrackingExtension::HandTrackedHands>(p_hand_index);
  1231. return OpenXRHandTrackingExtension::get_singleton()->get_hand_tracker(hand)->hand_tracker;
  1232. }
  1233. Size2 OpenXRAPI::get_recommended_target_size() {
  1234. ERR_FAIL_NULL_V(view_configuration_views, Size2());
  1235. Size2 target_size;
  1236. target_size.width = view_configuration_views[0].recommendedImageRectWidth * render_target_size_multiplier;
  1237. target_size.height = view_configuration_views[0].recommendedImageRectHeight * render_target_size_multiplier;
  1238. return target_size;
  1239. }
  1240. XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
  1241. XrResult result;
  1242. if (!running) {
  1243. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  1244. }
  1245. // xrWaitFrame not run yet
  1246. if (frame_state.predictedDisplayTime == 0) {
  1247. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  1248. }
  1249. // Get timing for the next frame, as that is the current frame we're processing
  1250. XrTime display_time = get_next_frame_time();
  1251. XrSpaceVelocity velocity = {
  1252. XR_TYPE_SPACE_VELOCITY, // type
  1253. nullptr, // next
  1254. 0, // velocityFlags
  1255. { 0.0, 0.0, 0.0 }, // linearVelocity
  1256. { 0.0, 0.0, 0.0 } // angularVelocity
  1257. };
  1258. XrSpaceLocation location = {
  1259. XR_TYPE_SPACE_LOCATION, // type
  1260. &velocity, // next
  1261. 0, // locationFlags
  1262. {
  1263. { 0.0, 0.0, 0.0, 0.0 }, // orientation
  1264. { 0.0, 0.0, 0.0 } // position
  1265. } // pose
  1266. };
  1267. result = xrLocateSpace(view_space, play_space, display_time, &location);
  1268. if (XR_FAILED(result)) {
  1269. print_line("OpenXR: Failed to locate view space in play space [", get_error_string(result), "]");
  1270. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  1271. }
  1272. XRPose::TrackingConfidence confidence = transform_from_location(location, r_transform);
  1273. parse_velocities(velocity, r_linear_velocity, r_angular_velocity);
  1274. if (head_pose_confidence != confidence) {
  1275. // prevent error spam
  1276. head_pose_confidence = confidence;
  1277. if (head_pose_confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) {
  1278. print_line("OpenXR head space location not valid (check tracking?)");
  1279. } else if (head_pose_confidence == XRPose::XR_TRACKING_CONFIDENCE_LOW) {
  1280. print_verbose("OpenVR Head pose now tracking with low confidence");
  1281. } else {
  1282. print_verbose("OpenVR Head pose now tracking with high confidence");
  1283. }
  1284. }
  1285. return confidence;
  1286. }
  1287. bool OpenXRAPI::get_view_transform(uint32_t p_view, Transform3D &r_transform) {
  1288. if (!running) {
  1289. return false;
  1290. }
  1291. // xrWaitFrame not run yet
  1292. if (frame_state.predictedDisplayTime == 0) {
  1293. return false;
  1294. }
  1295. // we don't have valid view info
  1296. if (views == nullptr || !view_pose_valid) {
  1297. return false;
  1298. }
  1299. // Note, the timing of this is set right before rendering, which is what we need here.
  1300. r_transform = transform_from_pose(views[p_view].pose);
  1301. return true;
  1302. }
  1303. bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, Projection &p_camera_matrix) {
  1304. ERR_FAIL_NULL_V(graphics_extension, false);
  1305. if (!running) {
  1306. return false;
  1307. }
  1308. // xrWaitFrame not run yet
  1309. if (frame_state.predictedDisplayTime == 0) {
  1310. return false;
  1311. }
  1312. // we don't have valid view info
  1313. if (views == nullptr || !view_pose_valid) {
  1314. return false;
  1315. }
  1316. // if we're using depth views, make sure we update our near and far there...
  1317. if (depth_views != nullptr) {
  1318. for (uint32_t i = 0; i < view_count; i++) {
  1319. depth_views[i].nearZ = p_z_near;
  1320. depth_views[i].farZ = p_z_far;
  1321. }
  1322. }
  1323. // now update our projection
  1324. return graphics_extension->create_projection_fov(views[p_view].fov, p_z_near, p_z_far, p_camera_matrix);
  1325. }
  1326. bool OpenXRAPI::poll_events() {
  1327. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  1328. XrEventDataBuffer runtimeEvent;
  1329. runtimeEvent.type = XR_TYPE_EVENT_DATA_BUFFER;
  1330. runtimeEvent.next = nullptr;
  1331. // runtimeEvent.varying = ...
  1332. XrResult pollResult = xrPollEvent(instance, &runtimeEvent);
  1333. while (pollResult == XR_SUCCESS) {
  1334. bool handled = false;
  1335. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1336. handled |= wrapper->on_event_polled(runtimeEvent);
  1337. }
  1338. switch (runtimeEvent.type) {
  1339. case XR_TYPE_EVENT_DATA_EVENTS_LOST: {
  1340. XrEventDataEventsLost *event = (XrEventDataEventsLost *)&runtimeEvent;
  1341. // We probably didn't poll fast enough, just output warning
  1342. WARN_PRINT("OpenXR EVENT: " + itos(event->lostEventCount) + " event data lost!");
  1343. } break;
  1344. case XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR: {
  1345. // XrEventDataVisibilityMaskChangedKHR *event = (XrEventDataVisibilityMaskChangedKHR *)&runtimeEvent;
  1346. // TODO implement this in the future, we should call xrGetVisibilityMaskKHR to obtain a mask,
  1347. // this will allow us to prevent rendering the part of our view which is never displayed giving us
  1348. // a decent performance improvement.
  1349. print_verbose("OpenXR EVENT: STUB: visibility mask changed");
  1350. } break;
  1351. case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: {
  1352. XrEventDataInstanceLossPending *event = (XrEventDataInstanceLossPending *)&runtimeEvent;
  1353. // TODO We get this event if we're about to loose our OpenXR instance.
  1354. // We should queue exiting Godot at this point.
  1355. print_verbose(String("OpenXR EVENT: instance loss pending at ") + itos(event->lossTime));
  1356. return false;
  1357. } break;
  1358. case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: {
  1359. XrEventDataSessionStateChanged *event = (XrEventDataSessionStateChanged *)&runtimeEvent;
  1360. session_state = event->state;
  1361. if (session_state >= XR_SESSION_STATE_MAX_ENUM) {
  1362. print_verbose(String("OpenXR EVENT: session state changed to UNKNOWN - ") + itos(session_state));
  1363. } else {
  1364. print_verbose(String("OpenXR EVENT: session state changed to ") + OpenXRUtil::get_session_state_name(session_state));
  1365. switch (session_state) {
  1366. case XR_SESSION_STATE_IDLE:
  1367. on_state_idle();
  1368. break;
  1369. case XR_SESSION_STATE_READY:
  1370. on_state_ready();
  1371. break;
  1372. case XR_SESSION_STATE_SYNCHRONIZED:
  1373. on_state_synchronized();
  1374. break;
  1375. case XR_SESSION_STATE_VISIBLE:
  1376. on_state_visible();
  1377. break;
  1378. case XR_SESSION_STATE_FOCUSED:
  1379. on_state_focused();
  1380. break;
  1381. case XR_SESSION_STATE_STOPPING:
  1382. on_state_stopping();
  1383. break;
  1384. case XR_SESSION_STATE_LOSS_PENDING:
  1385. on_state_loss_pending();
  1386. break;
  1387. case XR_SESSION_STATE_EXITING:
  1388. on_state_exiting();
  1389. break;
  1390. default:
  1391. break;
  1392. }
  1393. }
  1394. } break;
  1395. case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING: {
  1396. XrEventDataReferenceSpaceChangePending *event = (XrEventDataReferenceSpaceChangePending *)&runtimeEvent;
  1397. print_verbose(String("OpenXR EVENT: reference space type ") + OpenXRUtil::get_reference_space_name(event->referenceSpaceType) + " change pending!");
  1398. if (emulating_local_floor) {
  1399. should_reset_emulated_floor_height = true;
  1400. }
  1401. if (event->poseValid && xr_interface) {
  1402. xr_interface->on_pose_recentered();
  1403. }
  1404. } break;
  1405. case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED: {
  1406. print_verbose("OpenXR EVENT: interaction profile changed!");
  1407. XrEventDataInteractionProfileChanged *event = (XrEventDataInteractionProfileChanged *)&runtimeEvent;
  1408. List<RID> trackers;
  1409. tracker_owner.get_owned_list(&trackers);
  1410. for (int i = 0; i < trackers.size(); i++) {
  1411. tracker_check_profile(trackers[i], event->session);
  1412. }
  1413. } break;
  1414. default:
  1415. if (!handled) {
  1416. print_verbose(String("OpenXR Unhandled event type ") + OpenXRUtil::get_structure_type_name(runtimeEvent.type));
  1417. }
  1418. break;
  1419. }
  1420. runtimeEvent.type = XR_TYPE_EVENT_DATA_BUFFER;
  1421. pollResult = xrPollEvent(instance, &runtimeEvent);
  1422. }
  1423. if (pollResult == XR_EVENT_UNAVAILABLE) {
  1424. // processed all events in the queue
  1425. return true;
  1426. } else {
  1427. ERR_FAIL_V_MSG(false, "OpenXR: Failed to poll events!");
  1428. }
  1429. }
  1430. bool OpenXRAPI::process() {
  1431. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  1432. if (!poll_events()) {
  1433. return false;
  1434. }
  1435. if (!running) {
  1436. return false;
  1437. }
  1438. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1439. wrapper->on_process();
  1440. }
  1441. return true;
  1442. }
  1443. bool OpenXRAPI::acquire_image(OpenXRSwapChainInfo &p_swapchain) {
  1444. ERR_FAIL_COND_V(p_swapchain.image_acquired, true); // This was not released when it should be, error out and reuse...
  1445. XrResult result;
  1446. if (!p_swapchain.skip_acquire_swapchain) {
  1447. XrSwapchainImageAcquireInfo swapchain_image_acquire_info = {
  1448. XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, // type
  1449. nullptr // next
  1450. };
  1451. result = xrAcquireSwapchainImage(p_swapchain.swapchain, &swapchain_image_acquire_info, &p_swapchain.image_index);
  1452. if (!XR_UNQUALIFIED_SUCCESS(result)) {
  1453. // Make sure end_frame knows we need to submit an empty frame
  1454. frame_state.shouldRender = false;
  1455. if (XR_FAILED(result)) {
  1456. // Unexpected failure, log this!
  1457. print_line("OpenXR: failed to acquire swapchain image [", get_error_string(result), "]");
  1458. return false;
  1459. } else {
  1460. // In this scenario we silently fail, the XR runtime is simply not ready yet to acquire the swapchain.
  1461. return false;
  1462. }
  1463. }
  1464. }
  1465. XrSwapchainImageWaitInfo swapchain_image_wait_info = {
  1466. XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, // type
  1467. nullptr, // next
  1468. 17000000 // timeout in nanoseconds
  1469. };
  1470. result = xrWaitSwapchainImage(p_swapchain.swapchain, &swapchain_image_wait_info);
  1471. if (!XR_UNQUALIFIED_SUCCESS(result)) {
  1472. // Make sure end_frame knows we need to submit an empty frame
  1473. frame_state.shouldRender = false;
  1474. if (XR_FAILED(result)) {
  1475. // Unexpected failure, log this!
  1476. print_line("OpenXR: failed to wait for swapchain image [", get_error_string(result), "]");
  1477. return false;
  1478. } else {
  1479. // Make sure to skip trying to acquire the swapchain image in the next frame
  1480. p_swapchain.skip_acquire_swapchain = true;
  1481. return false;
  1482. }
  1483. } else {
  1484. p_swapchain.skip_acquire_swapchain = false;
  1485. }
  1486. return true;
  1487. }
  1488. bool OpenXRAPI::release_image(OpenXRSwapChainInfo &p_swapchain) {
  1489. XrSwapchainImageReleaseInfo swapchain_image_release_info = {
  1490. XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, // type
  1491. nullptr // next
  1492. };
  1493. XrResult result = xrReleaseSwapchainImage(p_swapchain.swapchain, &swapchain_image_release_info);
  1494. if (XR_FAILED(result)) {
  1495. print_line("OpenXR: failed to release swapchain image! [", get_error_string(result), "]");
  1496. return false;
  1497. }
  1498. return true;
  1499. }
  1500. void OpenXRAPI::pre_render() {
  1501. ERR_FAIL_COND(instance == XR_NULL_HANDLE);
  1502. if (!running) {
  1503. return;
  1504. }
  1505. // Waitframe does 2 important things in our process:
  1506. // 1) It provides us with predictive timing, telling us when OpenXR expects to display the frame we're about to commit
  1507. // 2) It will use the previous timing to pause our thread so that rendering starts as close to displaying as possible
  1508. // This must thus be called as close to when we start rendering as possible
  1509. XrFrameWaitInfo frame_wait_info = { XR_TYPE_FRAME_WAIT_INFO, nullptr };
  1510. frame_state.predictedDisplayTime = 0;
  1511. frame_state.predictedDisplayPeriod = 0;
  1512. frame_state.shouldRender = false;
  1513. XrResult result = xrWaitFrame(session, &frame_wait_info, &frame_state);
  1514. if (XR_FAILED(result)) {
  1515. print_line("OpenXR: xrWaitFrame() was not successful [", get_error_string(result), "]");
  1516. // reset just in case
  1517. frame_state.predictedDisplayTime = 0;
  1518. frame_state.predictedDisplayPeriod = 0;
  1519. frame_state.shouldRender = false;
  1520. return;
  1521. }
  1522. if (frame_state.predictedDisplayPeriod > 500000000) {
  1523. // display period more then 0.5 seconds? must be wrong data
  1524. print_verbose(String("OpenXR resetting invalid display period ") + rtos(frame_state.predictedDisplayPeriod));
  1525. frame_state.predictedDisplayPeriod = 0;
  1526. }
  1527. if (unlikely(should_reset_emulated_floor_height)) {
  1528. reset_emulated_floor_height();
  1529. should_reset_emulated_floor_height = false;
  1530. }
  1531. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1532. wrapper->on_pre_render();
  1533. }
  1534. // Get our view info for the frame we're about to render, note from the OpenXR manual:
  1535. // "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"
  1536. // We're calling this "relatively" early, the positioning we're obtaining here will be used to do our frustum culling,
  1537. // occlusion culling, etc. There is however a technique that we can investigate in the future where after our entire
  1538. // Vulkan command buffer is build, but right before vkSubmitQueue is called, we call xrLocateViews one more time and
  1539. // update the view and projection matrix once more with a slightly more accurate predication and then submit the
  1540. // command queues.
  1541. // That is not possible yet but worth investigating in the future.
  1542. XrViewLocateInfo view_locate_info = {
  1543. XR_TYPE_VIEW_LOCATE_INFO, // type
  1544. nullptr, // next
  1545. view_configuration, // viewConfigurationType
  1546. frame_state.predictedDisplayTime, // displayTime
  1547. play_space // space
  1548. };
  1549. XrViewState view_state = {
  1550. XR_TYPE_VIEW_STATE, // type
  1551. nullptr, // next
  1552. 0 // viewStateFlags
  1553. };
  1554. uint32_t view_count_output;
  1555. result = xrLocateViews(session, &view_locate_info, &view_state, view_count, &view_count_output, views);
  1556. if (XR_FAILED(result)) {
  1557. print_line("OpenXR: Couldn't locate views [", get_error_string(result), "]");
  1558. return;
  1559. }
  1560. bool pose_valid = true;
  1561. for (uint64_t i = 0; i < view_count_output; i++) {
  1562. if ((view_state.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) == 0 ||
  1563. (view_state.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT) == 0) {
  1564. pose_valid = false;
  1565. }
  1566. }
  1567. if (view_pose_valid != pose_valid) {
  1568. view_pose_valid = pose_valid;
  1569. if (!view_pose_valid) {
  1570. print_verbose("OpenXR View pose became invalid");
  1571. } else {
  1572. print_verbose("OpenXR View pose became valid");
  1573. }
  1574. }
  1575. // let's start our frame..
  1576. XrFrameBeginInfo frame_begin_info = {
  1577. XR_TYPE_FRAME_BEGIN_INFO, // type
  1578. nullptr // next
  1579. };
  1580. result = xrBeginFrame(session, &frame_begin_info);
  1581. if (XR_FAILED(result)) {
  1582. print_line("OpenXR: failed to being frame [", get_error_string(result), "]");
  1583. return;
  1584. }
  1585. }
  1586. bool OpenXRAPI::pre_draw_viewport(RID p_render_target) {
  1587. if (!can_render()) {
  1588. return false;
  1589. }
  1590. // TODO: at some point in time we may support multiple viewports in which case we need to handle that...
  1591. // Acquire our images
  1592. for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) {
  1593. if (!swapchains[i].image_acquired && swapchains[i].swapchain != XR_NULL_HANDLE) {
  1594. if (!acquire_image(swapchains[i])) {
  1595. return false;
  1596. }
  1597. swapchains[i].image_acquired = true;
  1598. }
  1599. }
  1600. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1601. wrapper->on_pre_draw_viewport(p_render_target);
  1602. }
  1603. return true;
  1604. }
  1605. XrSwapchain OpenXRAPI::get_color_swapchain() {
  1606. return swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain;
  1607. }
  1608. RID OpenXRAPI::get_color_texture() {
  1609. if (swapchains[OPENXR_SWAPCHAIN_COLOR].image_acquired) {
  1610. return graphics_extension->get_texture(swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data, swapchains[OPENXR_SWAPCHAIN_COLOR].image_index);
  1611. } else {
  1612. return RID();
  1613. }
  1614. }
  1615. RID OpenXRAPI::get_depth_texture() {
  1616. // Note, image will not be acquired if we didn't have a suitable swap chain format.
  1617. if (submit_depth_buffer && swapchains[OPENXR_SWAPCHAIN_DEPTH].image_acquired) {
  1618. return graphics_extension->get_texture(swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data, swapchains[OPENXR_SWAPCHAIN_DEPTH].image_index);
  1619. } else {
  1620. return RID();
  1621. }
  1622. }
  1623. void OpenXRAPI::post_draw_viewport(RID p_render_target) {
  1624. if (!can_render()) {
  1625. return;
  1626. }
  1627. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1628. wrapper->on_post_draw_viewport(p_render_target);
  1629. }
  1630. };
  1631. void OpenXRAPI::end_frame() {
  1632. XrResult result;
  1633. ERR_FAIL_COND(instance == XR_NULL_HANDLE);
  1634. if (!running) {
  1635. return;
  1636. }
  1637. if (frame_state.shouldRender && view_pose_valid && !swapchains[OPENXR_SWAPCHAIN_COLOR].image_acquired) {
  1638. print_line("OpenXR: No viewport was marked with use_xr, there is no rendered output!");
  1639. }
  1640. // must have:
  1641. // - shouldRender set to true
  1642. // - a valid view pose for projection_views[eye].pose to submit layer
  1643. // - an image to render
  1644. if (!frame_state.shouldRender || !view_pose_valid || !swapchains[OPENXR_SWAPCHAIN_COLOR].image_acquired) {
  1645. // submit 0 layers when we shouldn't render
  1646. XrFrameEndInfo frame_end_info = {
  1647. XR_TYPE_FRAME_END_INFO, // type
  1648. nullptr, // next
  1649. frame_state.predictedDisplayTime, // displayTime
  1650. environment_blend_mode, // environmentBlendMode
  1651. 0, // layerCount
  1652. nullptr // layers
  1653. };
  1654. result = xrEndFrame(session, &frame_end_info);
  1655. if (XR_FAILED(result)) {
  1656. print_line("OpenXR: failed to end frame! [", get_error_string(result), "]");
  1657. return;
  1658. }
  1659. // neither eye is rendered
  1660. return;
  1661. }
  1662. // release our swapchain image if we acquired it
  1663. for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) {
  1664. if (swapchains[i].image_acquired) {
  1665. swapchains[i].image_acquired = false; // whether we succeed or not, consider this released.
  1666. release_image(swapchains[i]);
  1667. }
  1668. }
  1669. for (uint32_t eye = 0; eye < view_count; eye++) {
  1670. projection_views[eye].fov = views[eye].fov;
  1671. projection_views[eye].pose = views[eye].pose;
  1672. }
  1673. Vector<const XrCompositionLayerBaseHeader *> layers_list;
  1674. // Add composition layers from providers
  1675. for (OpenXRCompositionLayerProvider *provider : composition_layer_providers) {
  1676. XrCompositionLayerBaseHeader *layer = provider->get_composition_layer();
  1677. if (layer) {
  1678. layers_list.push_back(layer);
  1679. }
  1680. }
  1681. XrCompositionLayerFlags layer_flags = XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
  1682. if (layers_list.size() > 0 || environment_blend_mode != XR_ENVIRONMENT_BLEND_MODE_OPAQUE) {
  1683. layer_flags |= XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
  1684. }
  1685. XrCompositionLayerProjection projection_layer = {
  1686. XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type
  1687. nullptr, // next
  1688. layer_flags, // layerFlags
  1689. play_space, // space
  1690. view_count, // viewCount
  1691. projection_views, // views
  1692. };
  1693. layers_list.push_back((const XrCompositionLayerBaseHeader *)&projection_layer);
  1694. XrFrameEndInfo frame_end_info = {
  1695. XR_TYPE_FRAME_END_INFO, // type
  1696. nullptr, // next
  1697. frame_state.predictedDisplayTime, // displayTime
  1698. environment_blend_mode, // environmentBlendMode
  1699. static_cast<uint32_t>(layers_list.size()), // layerCount
  1700. layers_list.ptr() // layers
  1701. };
  1702. result = xrEndFrame(session, &frame_end_info);
  1703. if (XR_FAILED(result)) {
  1704. print_line("OpenXR: failed to end frame! [", get_error_string(result), "]");
  1705. return;
  1706. }
  1707. }
  1708. float OpenXRAPI::get_display_refresh_rate() const {
  1709. OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
  1710. if (drrext) {
  1711. return drrext->get_refresh_rate();
  1712. }
  1713. return 0.0;
  1714. }
  1715. void OpenXRAPI::set_display_refresh_rate(float p_refresh_rate) {
  1716. OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
  1717. if (drrext != nullptr) {
  1718. drrext->set_refresh_rate(p_refresh_rate);
  1719. }
  1720. }
  1721. Array OpenXRAPI::get_available_display_refresh_rates() const {
  1722. OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
  1723. if (drrext != nullptr) {
  1724. return drrext->get_available_refresh_rates();
  1725. }
  1726. return Array();
  1727. }
  1728. double OpenXRAPI::get_render_target_size_multiplier() const {
  1729. return render_target_size_multiplier;
  1730. }
  1731. void OpenXRAPI::set_render_target_size_multiplier(double multiplier) {
  1732. render_target_size_multiplier = multiplier;
  1733. }
  1734. bool OpenXRAPI::is_foveation_supported() const {
  1735. OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
  1736. return fov_ext != nullptr && fov_ext->is_enabled();
  1737. }
  1738. int OpenXRAPI::get_foveation_level() const {
  1739. OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
  1740. if (fov_ext != nullptr && fov_ext->is_enabled()) {
  1741. switch (fov_ext->get_foveation_level()) {
  1742. case XR_FOVEATION_LEVEL_NONE_FB:
  1743. return 0;
  1744. case XR_FOVEATION_LEVEL_LOW_FB:
  1745. return 1;
  1746. case XR_FOVEATION_LEVEL_MEDIUM_FB:
  1747. return 2;
  1748. case XR_FOVEATION_LEVEL_HIGH_FB:
  1749. return 3;
  1750. default:
  1751. return 0;
  1752. }
  1753. }
  1754. return 0;
  1755. }
  1756. void OpenXRAPI::set_foveation_level(int p_foveation_level) {
  1757. ERR_FAIL_UNSIGNED_INDEX(p_foveation_level, 4);
  1758. OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
  1759. if (fov_ext != nullptr && fov_ext->is_enabled()) {
  1760. XrFoveationLevelFB levels[] = { XR_FOVEATION_LEVEL_NONE_FB, XR_FOVEATION_LEVEL_LOW_FB, XR_FOVEATION_LEVEL_MEDIUM_FB, XR_FOVEATION_LEVEL_HIGH_FB };
  1761. fov_ext->set_foveation_level(levels[p_foveation_level]);
  1762. }
  1763. }
  1764. bool OpenXRAPI::get_foveation_dynamic() const {
  1765. OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
  1766. if (fov_ext != nullptr && fov_ext->is_enabled()) {
  1767. return fov_ext->get_foveation_dynamic() == XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB;
  1768. }
  1769. return false;
  1770. }
  1771. void OpenXRAPI::set_foveation_dynamic(bool p_foveation_dynamic) {
  1772. OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
  1773. if (fov_ext != nullptr && fov_ext->is_enabled()) {
  1774. fov_ext->set_foveation_dynamic(p_foveation_dynamic ? XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB : XR_FOVEATION_DYNAMIC_DISABLED_FB);
  1775. }
  1776. }
  1777. Size2 OpenXRAPI::get_play_space_bounds() const {
  1778. Size2 ret;
  1779. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, Size2());
  1780. XrExtent2Df extents;
  1781. XrResult result = xrGetReferenceSpaceBoundsRect(session, reference_space, &extents);
  1782. if (XR_FAILED(result)) {
  1783. print_line("OpenXR: failed to get play space bounds! [", get_error_string(result), "]");
  1784. return ret;
  1785. }
  1786. ret.width = extents.width;
  1787. ret.height = extents.height;
  1788. return ret;
  1789. }
  1790. OpenXRAPI::OpenXRAPI() {
  1791. // OpenXRAPI is only constructed if OpenXR is enabled.
  1792. singleton = this;
  1793. if (Engine::get_singleton()->is_editor_hint()) {
  1794. // Enabled OpenXR in the editor? Adjust our settings for the editor
  1795. } else {
  1796. // Load settings from project settings
  1797. int form_factor_setting = GLOBAL_GET("xr/openxr/form_factor");
  1798. switch (form_factor_setting) {
  1799. case 0: {
  1800. form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
  1801. } break;
  1802. case 1: {
  1803. form_factor = XR_FORM_FACTOR_HANDHELD_DISPLAY;
  1804. } break;
  1805. default:
  1806. break;
  1807. }
  1808. int view_configuration_setting = GLOBAL_GET("xr/openxr/view_configuration");
  1809. switch (view_configuration_setting) {
  1810. case 0: {
  1811. view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO;
  1812. } break;
  1813. case 1: {
  1814. view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
  1815. } break;
  1816. /* we don't support quad and observer configurations (yet)
  1817. case 2: {
  1818. view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO;
  1819. } break;
  1820. case 3: {
  1821. view_configuration = XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT;
  1822. } break;
  1823. */
  1824. default:
  1825. break;
  1826. }
  1827. int reference_space_setting = GLOBAL_GET("xr/openxr/reference_space");
  1828. switch (reference_space_setting) {
  1829. case 0: {
  1830. requested_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
  1831. } break;
  1832. case 1: {
  1833. requested_reference_space = XR_REFERENCE_SPACE_TYPE_STAGE;
  1834. } break;
  1835. case 2: {
  1836. requested_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
  1837. } break;
  1838. default:
  1839. break;
  1840. }
  1841. int environment_blend_mode_setting = GLOBAL_GET("xr/openxr/environment_blend_mode");
  1842. switch (environment_blend_mode_setting) {
  1843. case 0: {
  1844. environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
  1845. } break;
  1846. case 1: {
  1847. environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_ADDITIVE;
  1848. } break;
  1849. case 2: {
  1850. environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND;
  1851. } break;
  1852. default:
  1853. break;
  1854. }
  1855. submit_depth_buffer = GLOBAL_GET("xr/openxr/submit_depth_buffer");
  1856. }
  1857. // reset a few things that can't be done in our class definition
  1858. frame_state.predictedDisplayTime = 0;
  1859. frame_state.predictedDisplayPeriod = 0;
  1860. }
  1861. OpenXRAPI::~OpenXRAPI() {
  1862. // cleanup our composition layer providers
  1863. for (OpenXRCompositionLayerProvider *provider : composition_layer_providers) {
  1864. memdelete(provider);
  1865. }
  1866. composition_layer_providers.clear();
  1867. if (supported_extensions != nullptr) {
  1868. memfree(supported_extensions);
  1869. supported_extensions = nullptr;
  1870. }
  1871. if (layer_properties != nullptr) {
  1872. memfree(layer_properties);
  1873. layer_properties = nullptr;
  1874. }
  1875. #ifdef ANDROID_ENABLED
  1876. if (openxr_loader_library_handle) {
  1877. OS::get_singleton()->close_dynamic_library(openxr_loader_library_handle);
  1878. openxr_loader_library_handle = nullptr;
  1879. }
  1880. #endif
  1881. singleton = nullptr;
  1882. }
  1883. Transform3D OpenXRAPI::transform_from_pose(const XrPosef &p_pose) {
  1884. Quaternion q(p_pose.orientation.x, p_pose.orientation.y, p_pose.orientation.z, p_pose.orientation.w);
  1885. Basis basis(q);
  1886. Vector3 origin(p_pose.position.x, p_pose.position.y, p_pose.position.z);
  1887. return Transform3D(basis, origin);
  1888. }
  1889. template <typename T>
  1890. XRPose::TrackingConfidence _transform_from_location(const T &p_location, Transform3D &r_transform) {
  1891. Basis basis;
  1892. Vector3 origin;
  1893. XRPose::TrackingConfidence confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE;
  1894. const XrPosef &pose = p_location.pose;
  1895. // Check orientation
  1896. if (p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
  1897. Quaternion q(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w);
  1898. r_transform.basis = Basis(q);
  1899. if (p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT) {
  1900. // Fully valid orientation, so either 3DOF or 6DOF tracking with high confidence so default to HIGH_TRACKING
  1901. confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH;
  1902. } else {
  1903. // Orientation is being tracked but we're using old/predicted data, so low tracking confidence
  1904. confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW;
  1905. }
  1906. } else {
  1907. r_transform.basis = Basis();
  1908. }
  1909. // Check location
  1910. if (p_location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
  1911. r_transform.origin = Vector3(pose.position.x, pose.position.y, pose.position.z);
  1912. if (!(p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT)) {
  1913. // Location is being tracked but we're using old/predicted data, so low tracking confidence
  1914. confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW;
  1915. } else if (confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) {
  1916. // Position tracking without orientation tracking?
  1917. confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH;
  1918. }
  1919. } else {
  1920. // No tracking or 3DOF I guess..
  1921. r_transform.origin = Vector3();
  1922. }
  1923. return confidence;
  1924. }
  1925. XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform) {
  1926. return _transform_from_location(p_location, r_transform);
  1927. }
  1928. XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform) {
  1929. return _transform_from_location(p_location, r_transform);
  1930. }
  1931. void OpenXRAPI::parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
  1932. if (p_velocity.velocityFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) {
  1933. XrVector3f linear_velocity = p_velocity.linearVelocity;
  1934. r_linear_velocity = Vector3(linear_velocity.x, linear_velocity.y, linear_velocity.z);
  1935. } else {
  1936. r_linear_velocity = Vector3();
  1937. }
  1938. if (p_velocity.velocityFlags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) {
  1939. XrVector3f angular_velocity = p_velocity.angularVelocity;
  1940. r_angular_velocity = Vector3(angular_velocity.x, angular_velocity.y, angular_velocity.z);
  1941. } else {
  1942. r_angular_velocity = Vector3();
  1943. }
  1944. }
  1945. bool OpenXRAPI::xr_result(XrResult result, const char *format, Array args) const {
  1946. if (XR_SUCCEEDED(result))
  1947. return true;
  1948. char resultString[XR_MAX_RESULT_STRING_SIZE];
  1949. xrResultToString(instance, result, resultString);
  1950. print_error(String("OpenXR ") + String(format).format(args) + String(" [") + String(resultString) + String("]"));
  1951. return false;
  1952. }
  1953. RID OpenXRAPI::get_tracker_rid(XrPath p_path) {
  1954. List<RID> current;
  1955. tracker_owner.get_owned_list(&current);
  1956. for (int i = 0; i < current.size(); i++) {
  1957. Tracker *tracker = tracker_owner.get_or_null(current[i]);
  1958. if (tracker && tracker->toplevel_path == p_path) {
  1959. return current[i];
  1960. }
  1961. }
  1962. return RID();
  1963. }
  1964. RID OpenXRAPI::tracker_create(const String p_name) {
  1965. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID());
  1966. Tracker new_tracker;
  1967. new_tracker.name = p_name;
  1968. new_tracker.toplevel_path = XR_NULL_PATH;
  1969. new_tracker.active_profile_rid = RID();
  1970. XrResult result = xrStringToPath(instance, p_name.utf8().get_data(), &new_tracker.toplevel_path);
  1971. if (XR_FAILED(result)) {
  1972. print_line("OpenXR: failed to get path for ", p_name, "! [", get_error_string(result), "]");
  1973. return RID();
  1974. }
  1975. return tracker_owner.make_rid(new_tracker);
  1976. }
  1977. String OpenXRAPI::tracker_get_name(RID p_tracker) {
  1978. if (p_tracker.is_null()) {
  1979. return String("None");
  1980. }
  1981. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  1982. ERR_FAIL_NULL_V(tracker, String());
  1983. return tracker->name;
  1984. }
  1985. void OpenXRAPI::tracker_check_profile(RID p_tracker, XrSession p_session) {
  1986. if (p_session == XR_NULL_HANDLE) {
  1987. p_session = session;
  1988. }
  1989. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  1990. ERR_FAIL_NULL(tracker);
  1991. if (tracker->toplevel_path == XR_NULL_PATH) {
  1992. // no path, how was this even created?
  1993. return;
  1994. }
  1995. XrInteractionProfileState profile_state = {
  1996. XR_TYPE_INTERACTION_PROFILE_STATE, // type
  1997. nullptr, // next
  1998. XR_NULL_PATH // interactionProfile
  1999. };
  2000. XrResult result = xrGetCurrentInteractionProfile(p_session, tracker->toplevel_path, &profile_state);
  2001. if (XR_FAILED(result)) {
  2002. print_line("OpenXR: Failed to get interaction profile for", itos(tracker->toplevel_path), "[", get_error_string(result), "]");
  2003. return;
  2004. }
  2005. XrPath new_profile = profile_state.interactionProfile;
  2006. XrPath was_profile = get_interaction_profile_path(tracker->active_profile_rid);
  2007. if (was_profile != new_profile) {
  2008. tracker->active_profile_rid = get_interaction_profile_rid(new_profile);
  2009. if (xr_interface) {
  2010. xr_interface->tracker_profile_changed(p_tracker, tracker->active_profile_rid);
  2011. }
  2012. }
  2013. }
  2014. void OpenXRAPI::tracker_free(RID p_tracker) {
  2015. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2016. ERR_FAIL_NULL(tracker);
  2017. // there is nothing to free here
  2018. tracker_owner.free(p_tracker);
  2019. }
  2020. RID OpenXRAPI::action_set_create(const String p_name, const String p_localized_name, const int p_priority) {
  2021. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID());
  2022. ActionSet action_set;
  2023. action_set.name = p_name;
  2024. action_set.is_attached = false;
  2025. // create our action set...
  2026. XrActionSetCreateInfo action_set_info = {
  2027. XR_TYPE_ACTION_SET_CREATE_INFO, // type
  2028. nullptr, // next
  2029. "", // actionSetName
  2030. "", // localizedActionSetName
  2031. uint32_t(p_priority) // priority
  2032. };
  2033. copy_string_to_char_buffer(p_name, action_set_info.actionSetName, XR_MAX_ACTION_SET_NAME_SIZE);
  2034. copy_string_to_char_buffer(p_localized_name, action_set_info.localizedActionSetName, XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE);
  2035. XrResult result = xrCreateActionSet(instance, &action_set_info, &action_set.handle);
  2036. if (XR_FAILED(result)) {
  2037. print_line("OpenXR: failed to create action set ", p_name, "! [", get_error_string(result), "]");
  2038. return RID();
  2039. }
  2040. return action_set_owner.make_rid(action_set);
  2041. }
  2042. String OpenXRAPI::action_set_get_name(RID p_action_set) {
  2043. if (p_action_set.is_null()) {
  2044. return String("None");
  2045. }
  2046. ActionSet *action_set = action_set_owner.get_or_null(p_action_set);
  2047. ERR_FAIL_NULL_V(action_set, String());
  2048. return action_set->name;
  2049. }
  2050. bool OpenXRAPI::attach_action_sets(const Vector<RID> &p_action_sets) {
  2051. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  2052. Vector<XrActionSet> action_handles;
  2053. action_handles.resize(p_action_sets.size());
  2054. for (int i = 0; i < p_action_sets.size(); i++) {
  2055. ActionSet *action_set = action_set_owner.get_or_null(p_action_sets[i]);
  2056. ERR_FAIL_NULL_V(action_set, false);
  2057. if (action_set->is_attached) {
  2058. return false;
  2059. }
  2060. action_handles.set(i, action_set->handle);
  2061. }
  2062. // So according to the docs, once we attach our action set to our session it becomes read only..
  2063. // https://www.khronos.org/registry/OpenXR/specs/1.0/man/html/xrAttachSessionActionSets.html
  2064. XrSessionActionSetsAttachInfo attach_info = {
  2065. XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO, // type
  2066. nullptr, // next
  2067. (uint32_t)p_action_sets.size(), // countActionSets,
  2068. action_handles.ptr() // actionSets
  2069. };
  2070. XrResult result = xrAttachSessionActionSets(session, &attach_info);
  2071. if (XR_FAILED(result)) {
  2072. print_line("OpenXR: failed to attach action sets! [", get_error_string(result), "]");
  2073. return false;
  2074. }
  2075. for (int i = 0; i < p_action_sets.size(); i++) {
  2076. ActionSet *action_set = action_set_owner.get_or_null(p_action_sets[i]);
  2077. ERR_FAIL_NULL_V(action_set, false);
  2078. action_set->is_attached = true;
  2079. }
  2080. /* For debugging:
  2081. print_verbose("Attached set " + action_set->name);
  2082. List<RID> action_rids;
  2083. action_owner.get_owned_list(&action_rids);
  2084. for (int i = 0; i < action_rids.size(); i++) {
  2085. Action * action = action_owner.get_or_null(action_rids[i]);
  2086. if (action && action->action_set_rid == p_action_set) {
  2087. print_verbose(" - Action " + action->name + ": " + OpenXRUtil::get_action_type_name(action->action_type));
  2088. for (int j = 0; j < action->trackers.size(); j++) {
  2089. Tracker * tracker = tracker_owner.get_or_null(action->trackers[j].tracker_rid);
  2090. if (tracker) {
  2091. print_verbose(" - " + tracker->name);
  2092. }
  2093. }
  2094. }
  2095. }
  2096. */
  2097. return true;
  2098. }
  2099. void OpenXRAPI::action_set_free(RID p_action_set) {
  2100. ActionSet *action_set = action_set_owner.get_or_null(p_action_set);
  2101. ERR_FAIL_NULL(action_set);
  2102. if (action_set->handle != XR_NULL_HANDLE) {
  2103. xrDestroyActionSet(action_set->handle);
  2104. }
  2105. action_set_owner.free(p_action_set);
  2106. }
  2107. RID OpenXRAPI::get_action_rid(XrAction p_action) {
  2108. List<RID> current;
  2109. action_owner.get_owned_list(&current);
  2110. for (int i = 0; i < current.size(); i++) {
  2111. Action *action = action_owner.get_or_null(current[i]);
  2112. if (action && action->handle == p_action) {
  2113. return current[i];
  2114. }
  2115. }
  2116. return RID();
  2117. }
  2118. 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) {
  2119. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID());
  2120. Action action;
  2121. action.name = p_name;
  2122. ActionSet *action_set = action_set_owner.get_or_null(p_action_set);
  2123. ERR_FAIL_NULL_V(action_set, RID());
  2124. ERR_FAIL_COND_V(action_set->handle == XR_NULL_HANDLE, RID());
  2125. action.action_set_rid = p_action_set;
  2126. switch (p_action_type) {
  2127. case OpenXRAction::OPENXR_ACTION_BOOL:
  2128. action.action_type = XR_ACTION_TYPE_BOOLEAN_INPUT;
  2129. break;
  2130. case OpenXRAction::OPENXR_ACTION_FLOAT:
  2131. action.action_type = XR_ACTION_TYPE_FLOAT_INPUT;
  2132. break;
  2133. case OpenXRAction::OPENXR_ACTION_VECTOR2:
  2134. action.action_type = XR_ACTION_TYPE_VECTOR2F_INPUT;
  2135. break;
  2136. case OpenXRAction::OPENXR_ACTION_POSE:
  2137. action.action_type = XR_ACTION_TYPE_POSE_INPUT;
  2138. break;
  2139. case OpenXRAction::OPENXR_ACTION_HAPTIC:
  2140. action.action_type = XR_ACTION_TYPE_VIBRATION_OUTPUT;
  2141. break;
  2142. default:
  2143. ERR_FAIL_V(RID());
  2144. break;
  2145. }
  2146. Vector<XrPath> toplevel_paths;
  2147. for (int i = 0; i < p_trackers.size(); i++) {
  2148. Tracker *tracker = tracker_owner.get_or_null(p_trackers[i]);
  2149. if (tracker != nullptr && tracker->toplevel_path != XR_NULL_PATH) {
  2150. ActionTracker action_tracker = {
  2151. p_trackers[i], // tracker
  2152. XR_NULL_HANDLE, // space
  2153. false // was_location_valid
  2154. };
  2155. action.trackers.push_back(action_tracker);
  2156. toplevel_paths.push_back(tracker->toplevel_path);
  2157. }
  2158. }
  2159. XrActionCreateInfo action_info = {
  2160. XR_TYPE_ACTION_CREATE_INFO, // type
  2161. nullptr, // next
  2162. "", // actionName
  2163. action.action_type, // actionType
  2164. uint32_t(toplevel_paths.size()), // countSubactionPaths
  2165. toplevel_paths.ptr(), // subactionPaths
  2166. "" // localizedActionName
  2167. };
  2168. copy_string_to_char_buffer(p_name, action_info.actionName, XR_MAX_ACTION_NAME_SIZE);
  2169. copy_string_to_char_buffer(p_localized_name, action_info.localizedActionName, XR_MAX_LOCALIZED_ACTION_NAME_SIZE);
  2170. XrResult result = xrCreateAction(action_set->handle, &action_info, &action.handle);
  2171. if (XR_FAILED(result)) {
  2172. print_line("OpenXR: failed to create action ", p_name, "! [", get_error_string(result), "]");
  2173. return RID();
  2174. }
  2175. return action_owner.make_rid(action);
  2176. }
  2177. String OpenXRAPI::action_get_name(RID p_action) {
  2178. if (p_action.is_null()) {
  2179. return String("None");
  2180. }
  2181. Action *action = action_owner.get_or_null(p_action);
  2182. ERR_FAIL_NULL_V(action, String());
  2183. return action->name;
  2184. }
  2185. void OpenXRAPI::action_free(RID p_action) {
  2186. Action *action = action_owner.get_or_null(p_action);
  2187. ERR_FAIL_NULL(action);
  2188. if (action->handle != XR_NULL_HANDLE) {
  2189. xrDestroyAction(action->handle);
  2190. }
  2191. action_owner.free(p_action);
  2192. }
  2193. RID OpenXRAPI::get_interaction_profile_rid(XrPath p_path) {
  2194. List<RID> current;
  2195. interaction_profile_owner.get_owned_list(&current);
  2196. for (int i = 0; i < current.size(); i++) {
  2197. InteractionProfile *ip = interaction_profile_owner.get_or_null(current[i]);
  2198. if (ip && ip->path == p_path) {
  2199. return current[i];
  2200. }
  2201. }
  2202. return RID();
  2203. }
  2204. XrPath OpenXRAPI::get_interaction_profile_path(RID p_interaction_profile) {
  2205. if (p_interaction_profile.is_null()) {
  2206. return XR_NULL_PATH;
  2207. }
  2208. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2209. ERR_FAIL_NULL_V(ip, XR_NULL_PATH);
  2210. return ip->path;
  2211. }
  2212. RID OpenXRAPI::interaction_profile_create(const String p_name) {
  2213. if (!is_interaction_profile_supported(p_name)) {
  2214. // The extension enabling this path must not be active, we will silently skip this interaction profile
  2215. return RID();
  2216. }
  2217. InteractionProfile new_interaction_profile;
  2218. XrResult result = xrStringToPath(instance, p_name.utf8().get_data(), &new_interaction_profile.path);
  2219. if (XR_FAILED(result)) {
  2220. print_line("OpenXR: failed to get path for ", p_name, "! [", get_error_string(result), "]");
  2221. return RID();
  2222. }
  2223. RID existing_ip = get_interaction_profile_rid(new_interaction_profile.path);
  2224. if (existing_ip.is_valid()) {
  2225. return existing_ip;
  2226. }
  2227. new_interaction_profile.name = p_name;
  2228. return interaction_profile_owner.make_rid(new_interaction_profile);
  2229. }
  2230. String OpenXRAPI::interaction_profile_get_name(RID p_interaction_profile) {
  2231. if (p_interaction_profile.is_null()) {
  2232. return String("None");
  2233. }
  2234. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2235. ERR_FAIL_NULL_V(ip, String());
  2236. return ip->name;
  2237. }
  2238. void OpenXRAPI::interaction_profile_clear_bindings(RID p_interaction_profile) {
  2239. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2240. ERR_FAIL_NULL(ip);
  2241. ip->bindings.clear();
  2242. }
  2243. bool OpenXRAPI::interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path) {
  2244. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2245. ERR_FAIL_NULL_V(ip, false);
  2246. if (!interaction_profile_supports_io_path(ip->name, p_path)) {
  2247. return false;
  2248. }
  2249. XrActionSuggestedBinding binding;
  2250. Action *action = action_owner.get_or_null(p_action);
  2251. ERR_FAIL_COND_V(action == nullptr || action->handle == XR_NULL_HANDLE, false);
  2252. binding.action = action->handle;
  2253. XrResult result = xrStringToPath(instance, p_path.utf8().get_data(), &binding.binding);
  2254. if (XR_FAILED(result)) {
  2255. print_line("OpenXR: failed to get path for ", p_path, "! [", get_error_string(result), "]");
  2256. return false;
  2257. }
  2258. ip->bindings.push_back(binding);
  2259. return true;
  2260. }
  2261. bool OpenXRAPI::interaction_profile_suggest_bindings(RID p_interaction_profile) {
  2262. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  2263. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2264. ERR_FAIL_NULL_V(ip, false);
  2265. const XrInteractionProfileSuggestedBinding suggested_bindings = {
  2266. XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING, // type
  2267. nullptr, // next
  2268. ip->path, // interactionProfile
  2269. uint32_t(ip->bindings.size()), // countSuggestedBindings
  2270. ip->bindings.ptr() // suggestedBindings
  2271. };
  2272. XrResult result = xrSuggestInteractionProfileBindings(instance, &suggested_bindings);
  2273. if (result == XR_ERROR_PATH_UNSUPPORTED) {
  2274. // this is fine, not all runtimes support all devices.
  2275. print_verbose("OpenXR Interaction profile " + ip->name + " is not supported on this runtime");
  2276. } else if (XR_FAILED(result)) {
  2277. print_line("OpenXR: failed to suggest bindings for ", ip->name, "! [", get_error_string(result), "]");
  2278. // reporting is enough...
  2279. }
  2280. /* For debugging:
  2281. print_verbose("Suggested bindings for " + ip->name);
  2282. for (int i = 0; i < ip->bindings.size(); i++) {
  2283. uint32_t strlen;
  2284. char path[XR_MAX_PATH_LENGTH];
  2285. String action_name = action_get_name(get_action_rid(ip->bindings[i].action));
  2286. XrResult result = xrPathToString(instance, ip->bindings[i].binding, XR_MAX_PATH_LENGTH, &strlen, path);
  2287. if (XR_FAILED(result)) {
  2288. print_line("OpenXR: failed to retrieve bindings for ", action_name, "! [", get_error_string(result), "]");
  2289. }
  2290. print_verbose(" - " + action_name + " => " + String(path));
  2291. }
  2292. */
  2293. return true;
  2294. }
  2295. void OpenXRAPI::interaction_profile_free(RID p_interaction_profile) {
  2296. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  2297. ERR_FAIL_NULL(ip);
  2298. ip->bindings.clear();
  2299. interaction_profile_owner.free(p_interaction_profile);
  2300. }
  2301. bool OpenXRAPI::sync_action_sets(const Vector<RID> p_active_sets) {
  2302. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  2303. if (!running) {
  2304. return false;
  2305. }
  2306. Vector<XrActiveActionSet> active_sets;
  2307. for (int i = 0; i < p_active_sets.size(); i++) {
  2308. ActionSet *action_set = action_set_owner.get_or_null(p_active_sets[i]);
  2309. if (action_set && action_set->handle != XR_NULL_HANDLE) {
  2310. XrActiveActionSet aset;
  2311. aset.actionSet = action_set->handle;
  2312. aset.subactionPath = XR_NULL_PATH;
  2313. active_sets.push_back(aset);
  2314. }
  2315. }
  2316. ERR_FAIL_COND_V(active_sets.is_empty(), false);
  2317. XrActionsSyncInfo sync_info = {
  2318. XR_TYPE_ACTIONS_SYNC_INFO, // type
  2319. nullptr, // next
  2320. uint32_t(active_sets.size()), // countActiveActionSets
  2321. active_sets.ptr() // activeActionSets
  2322. };
  2323. XrResult result = xrSyncActions(session, &sync_info);
  2324. if (XR_FAILED(result)) {
  2325. print_line("OpenXR: failed to sync active action sets! [", get_error_string(result), "]");
  2326. return false;
  2327. }
  2328. return true;
  2329. }
  2330. bool OpenXRAPI::get_action_bool(RID p_action, RID p_tracker) {
  2331. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  2332. Action *action = action_owner.get_or_null(p_action);
  2333. ERR_FAIL_NULL_V(action, false);
  2334. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2335. ERR_FAIL_NULL_V(tracker, false);
  2336. if (!running) {
  2337. return false;
  2338. }
  2339. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_BOOLEAN_INPUT, false);
  2340. XrActionStateGetInfo get_info = {
  2341. XR_TYPE_ACTION_STATE_GET_INFO, // type
  2342. nullptr, // next
  2343. action->handle, // action
  2344. tracker->toplevel_path // subactionPath
  2345. };
  2346. XrActionStateBoolean result_state;
  2347. result_state.type = XR_TYPE_ACTION_STATE_BOOLEAN,
  2348. result_state.next = nullptr;
  2349. XrResult result = xrGetActionStateBoolean(session, &get_info, &result_state);
  2350. if (XR_FAILED(result)) {
  2351. print_line("OpenXR: couldn't get action boolean! [", get_error_string(result), "]");
  2352. return false;
  2353. }
  2354. return result_state.isActive && result_state.currentState;
  2355. }
  2356. float OpenXRAPI::get_action_float(RID p_action, RID p_tracker) {
  2357. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, 0.0);
  2358. Action *action = action_owner.get_or_null(p_action);
  2359. ERR_FAIL_NULL_V(action, 0.0);
  2360. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2361. ERR_FAIL_NULL_V(tracker, 0.0);
  2362. if (!running) {
  2363. return 0.0;
  2364. }
  2365. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_FLOAT_INPUT, 0.0);
  2366. XrActionStateGetInfo get_info = {
  2367. XR_TYPE_ACTION_STATE_GET_INFO, // type
  2368. nullptr, // next
  2369. action->handle, // action
  2370. tracker->toplevel_path // subactionPath
  2371. };
  2372. XrActionStateFloat result_state;
  2373. result_state.type = XR_TYPE_ACTION_STATE_FLOAT,
  2374. result_state.next = nullptr;
  2375. XrResult result = xrGetActionStateFloat(session, &get_info, &result_state);
  2376. if (XR_FAILED(result)) {
  2377. print_line("OpenXR: couldn't get action float! [", get_error_string(result), "]");
  2378. return 0.0;
  2379. }
  2380. return result_state.isActive ? result_state.currentState : 0.0;
  2381. }
  2382. Vector2 OpenXRAPI::get_action_vector2(RID p_action, RID p_tracker) {
  2383. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, Vector2());
  2384. Action *action = action_owner.get_or_null(p_action);
  2385. ERR_FAIL_NULL_V(action, Vector2());
  2386. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2387. ERR_FAIL_NULL_V(tracker, Vector2());
  2388. if (!running) {
  2389. return Vector2();
  2390. }
  2391. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_VECTOR2F_INPUT, Vector2());
  2392. XrActionStateGetInfo get_info = {
  2393. XR_TYPE_ACTION_STATE_GET_INFO, // type
  2394. nullptr, // next
  2395. action->handle, // action
  2396. tracker->toplevel_path // subactionPath
  2397. };
  2398. XrActionStateVector2f result_state;
  2399. result_state.type = XR_TYPE_ACTION_STATE_VECTOR2F,
  2400. result_state.next = nullptr;
  2401. XrResult result = xrGetActionStateVector2f(session, &get_info, &result_state);
  2402. if (XR_FAILED(result)) {
  2403. print_line("OpenXR: couldn't get action vector2! [", get_error_string(result), "]");
  2404. return Vector2();
  2405. }
  2406. return result_state.isActive ? Vector2(result_state.currentState.x, result_state.currentState.y) : Vector2();
  2407. }
  2408. XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
  2409. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  2410. Action *action = action_owner.get_or_null(p_action);
  2411. ERR_FAIL_NULL_V(action, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  2412. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2413. ERR_FAIL_NULL_V(tracker, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  2414. if (!running) {
  2415. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  2416. }
  2417. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_POSE_INPUT, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  2418. // print_verbose("Checking " + action->name + " => " + tracker->name + " (" + itos(tracker->toplevel_path) + ")");
  2419. uint64_t index = 0xFFFFFFFF;
  2420. uint64_t size = uint64_t(action->trackers.size());
  2421. for (uint64_t i = 0; i < size && index == 0xFFFFFFFF; i++) {
  2422. if (action->trackers[i].tracker_rid == p_tracker) {
  2423. index = i;
  2424. }
  2425. }
  2426. if (index == 0xFFFFFFFF) {
  2427. // couldn't find it?
  2428. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  2429. }
  2430. XrTime display_time = get_next_frame_time();
  2431. if (display_time == 0) {
  2432. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  2433. }
  2434. if (action->trackers[index].space == XR_NULL_HANDLE) {
  2435. // if this is a pose we need to define spaces
  2436. XrActionSpaceCreateInfo action_space_info = {
  2437. XR_TYPE_ACTION_SPACE_CREATE_INFO, // type
  2438. nullptr, // next
  2439. action->handle, // action
  2440. tracker->toplevel_path, // subactionPath
  2441. {
  2442. { 0.0, 0.0, 0.0, 1.0 }, // orientation
  2443. { 0.0, 0.0, 0.0 } // position
  2444. } // poseInActionSpace
  2445. };
  2446. XrSpace space;
  2447. XrResult result = xrCreateActionSpace(session, &action_space_info, &space);
  2448. if (XR_FAILED(result)) {
  2449. print_line("OpenXR: couldn't create action space! [", get_error_string(result), "]");
  2450. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  2451. }
  2452. action->trackers.ptrw()[index].space = space;
  2453. }
  2454. XrSpaceVelocity velocity = {
  2455. XR_TYPE_SPACE_VELOCITY, // type
  2456. nullptr, // next
  2457. 0, // velocityFlags
  2458. { 0.0, 0.0, 0.0 }, // linearVelocity
  2459. { 0.0, 0.0, 0.0 } // angularVelocity
  2460. };
  2461. XrSpaceLocation location = {
  2462. XR_TYPE_SPACE_LOCATION, // type
  2463. &velocity, // next
  2464. 0, // locationFlags
  2465. {
  2466. { 0.0, 0.0, 0.0, 0.0 }, // orientation
  2467. { 0.0, 0.0, 0.0 } // position
  2468. } // pose
  2469. };
  2470. XrResult result = xrLocateSpace(action->trackers[index].space, play_space, display_time, &location);
  2471. if (XR_FAILED(result)) {
  2472. print_line("OpenXR: failed to locate space! [", get_error_string(result), "]");
  2473. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  2474. }
  2475. XRPose::TrackingConfidence confidence = transform_from_location(location, r_transform);
  2476. parse_velocities(velocity, r_linear_velocity, r_angular_velocity);
  2477. return confidence;
  2478. }
  2479. bool OpenXRAPI::trigger_haptic_pulse(RID p_action, RID p_tracker, float p_frequency, float p_amplitude, XrDuration p_duration_ns) {
  2480. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  2481. Action *action = action_owner.get_or_null(p_action);
  2482. ERR_FAIL_NULL_V(action, false);
  2483. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2484. ERR_FAIL_NULL_V(tracker, false);
  2485. if (!running) {
  2486. return false;
  2487. }
  2488. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_VIBRATION_OUTPUT, false);
  2489. XrHapticActionInfo action_info = {
  2490. XR_TYPE_HAPTIC_ACTION_INFO, // type
  2491. nullptr, // next
  2492. action->handle, // action
  2493. tracker->toplevel_path // subactionPath
  2494. };
  2495. XrHapticVibration vibration = {
  2496. XR_TYPE_HAPTIC_VIBRATION, // type
  2497. nullptr, // next
  2498. p_duration_ns, // duration
  2499. p_frequency, // frequency
  2500. p_amplitude, // amplitude
  2501. };
  2502. XrResult result = xrApplyHapticFeedback(session, &action_info, (const XrHapticBaseHeader *)&vibration);
  2503. if (XR_FAILED(result)) {
  2504. print_line("OpenXR: failed to apply haptic feedback! [", get_error_string(result), "]");
  2505. return false;
  2506. }
  2507. return true;
  2508. }
  2509. void OpenXRAPI::register_composition_layer_provider(OpenXRCompositionLayerProvider *provider) {
  2510. composition_layer_providers.append(provider);
  2511. }
  2512. void OpenXRAPI::unregister_composition_layer_provider(OpenXRCompositionLayerProvider *provider) {
  2513. composition_layer_providers.erase(provider);
  2514. }
  2515. const XrEnvironmentBlendMode *OpenXRAPI::get_supported_environment_blend_modes(uint32_t &count) {
  2516. count = num_supported_environment_blend_modes;
  2517. return supported_environment_blend_modes;
  2518. }
  2519. bool OpenXRAPI::is_environment_blend_mode_supported(XrEnvironmentBlendMode p_blend_mode) const {
  2520. ERR_FAIL_NULL_V(supported_environment_blend_modes, false);
  2521. for (uint32_t i = 0; i < num_supported_environment_blend_modes; i++) {
  2522. if (supported_environment_blend_modes[i] == p_blend_mode) {
  2523. return true;
  2524. }
  2525. }
  2526. return false;
  2527. }
  2528. bool OpenXRAPI::set_environment_blend_mode(XrEnvironmentBlendMode p_blend_mode) {
  2529. if (emulate_environment_blend_mode_alpha_blend && p_blend_mode == XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND) {
  2530. requested_environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND;
  2531. environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
  2532. return true;
  2533. }
  2534. // We allow setting this when not initialized and will check if it is supported when initializing.
  2535. // After OpenXR is initialized we verify we're setting a supported blend mode.
  2536. else if (!is_initialized() || is_environment_blend_mode_supported(p_blend_mode)) {
  2537. requested_environment_blend_mode = p_blend_mode;
  2538. environment_blend_mode = p_blend_mode;
  2539. return true;
  2540. }
  2541. return false;
  2542. }
  2543. void OpenXRAPI::set_emulate_environment_blend_mode_alpha_blend(bool p_enabled) {
  2544. emulate_environment_blend_mode_alpha_blend = p_enabled;
  2545. }
  2546. OpenXRAPI::OpenXRAlphaBlendModeSupport OpenXRAPI::is_environment_blend_mode_alpha_blend_supported() {
  2547. if (is_environment_blend_mode_supported(XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND)) {
  2548. return OPENXR_ALPHA_BLEND_MODE_SUPPORT_REAL;
  2549. } else if (emulate_environment_blend_mode_alpha_blend) {
  2550. return OPENXR_ALPHA_BLEND_MODE_SUPPORT_EMULATING;
  2551. }
  2552. return OPENXR_ALPHA_BLEND_MODE_SUPPORT_NONE;
  2553. }