openxr_api.cpp 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533
  1. /*************************************************************************/
  2. /* openxr_api.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "openxr_api.h"
  31. #include "openxr_util.h"
  32. #include "core/config/engine.h"
  33. #include "core/config/project_settings.h"
  34. #include "core/os/memory.h"
  35. #include "core/version.h"
  36. #ifdef TOOLS_ENABLED
  37. #include "editor/editor_settings.h"
  38. #endif
  39. #ifdef ANDROID_ENABLED
  40. #define OPENXR_LOADER_NAME "libopenxr_loader.so"
  41. #include "extensions/openxr_android_extension.h"
  42. #endif
  43. #ifdef VULKAN_ENABLED
  44. #include "extensions/openxr_vulkan_extension.h"
  45. #endif
  46. #include "extensions/openxr_htc_vive_tracker_extension.h"
  47. #include "modules/openxr/openxr_interface.h"
  48. OpenXRAPI *OpenXRAPI::singleton = nullptr;
  49. bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) {
  50. // @TODO we need an overrule switch so we can force enable openxr, i.e run "godot --openxr_enabled"
  51. if (Engine::get_singleton()->is_editor_hint() && p_check_run_in_editor) {
  52. // Disabled for now, using XR inside of the editor we'll be working on during the coming months.
  53. return false;
  54. } else {
  55. if (XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT) {
  56. return GLOBAL_GET("xr/openxr/enabled");
  57. } else {
  58. return XRServer::get_xr_mode() == XRServer::XRMODE_ON;
  59. }
  60. }
  61. }
  62. OpenXRAPI *OpenXRAPI::get_singleton() {
  63. return singleton;
  64. }
  65. String OpenXRAPI::get_default_action_map_resource_name() {
  66. String name = GLOBAL_GET("xr/openxr/default_action_map");
  67. return name;
  68. }
  69. String OpenXRAPI::get_error_string(XrResult result) {
  70. if (XR_SUCCEEDED(result)) {
  71. return String("Succeeded");
  72. }
  73. if (instance == XR_NULL_HANDLE) {
  74. Array args;
  75. args.push_back(Variant(result));
  76. return String("Error code {0}").format(args);
  77. }
  78. char resultString[XR_MAX_RESULT_STRING_SIZE];
  79. xrResultToString(instance, result, resultString);
  80. return String(resultString);
  81. }
  82. String OpenXRAPI::get_swapchain_format_name(int64_t p_swapchain_format) const {
  83. // This is rendering engine dependent...
  84. if (graphics_extension) {
  85. return graphics_extension->get_swapchain_format_name(p_swapchain_format);
  86. }
  87. return String("Swapchain format ") + String::num_int64(int64_t(p_swapchain_format));
  88. }
  89. bool OpenXRAPI::load_layer_properties() {
  90. // This queries additional layers that are available and can be initialized when we create our OpenXR instance
  91. if (layer_properties != nullptr) {
  92. // already retrieved this
  93. return true;
  94. }
  95. // Note, instance is not yet setup so we can't use get_error_string to retrieve our error
  96. XrResult result = xrEnumerateApiLayerProperties(0, &num_layer_properties, nullptr);
  97. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate number of api layer properties");
  98. layer_properties = (XrApiLayerProperties *)memalloc(sizeof(XrApiLayerProperties) * num_layer_properties);
  99. ERR_FAIL_NULL_V(layer_properties, false);
  100. for (uint32_t i = 0; i < num_layer_properties; i++) {
  101. layer_properties[i].type = XR_TYPE_API_LAYER_PROPERTIES;
  102. layer_properties[i].next = nullptr;
  103. }
  104. result = xrEnumerateApiLayerProperties(num_layer_properties, &num_layer_properties, layer_properties);
  105. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate api layer properties");
  106. #ifdef DEBUG
  107. for (uint32_t i = 0; i < num_layer_properties; i++) {
  108. print_line("OpenXR: Found OpenXR layer ", layer_properties[i].layerName);
  109. }
  110. #endif
  111. return true;
  112. }
  113. bool OpenXRAPI::load_supported_extensions() {
  114. // This queries supported extensions that are available and can be initialized when we create our OpenXR instance
  115. if (supported_extensions != nullptr) {
  116. // already retrieved this
  117. return true;
  118. }
  119. // Note, instance is not yet setup so we can't use get_error_string to retrieve our error
  120. XrResult result = xrEnumerateInstanceExtensionProperties(nullptr, 0, &num_supported_extensions, nullptr);
  121. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate number of extension properties");
  122. supported_extensions = (XrExtensionProperties *)memalloc(sizeof(XrExtensionProperties) * num_supported_extensions);
  123. ERR_FAIL_NULL_V(supported_extensions, false);
  124. // set our types
  125. for (uint32_t i = 0; i < num_supported_extensions; i++) {
  126. supported_extensions[i].type = XR_TYPE_EXTENSION_PROPERTIES;
  127. supported_extensions[i].next = nullptr;
  128. }
  129. result = xrEnumerateInstanceExtensionProperties(nullptr, num_supported_extensions, &num_supported_extensions, supported_extensions);
  130. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate extension properties");
  131. #ifdef DEBUG
  132. for (uint32_t i = 0; i < num_supported_extensions; i++) {
  133. print_line("OpenXR: Found OpenXR extension ", supported_extensions[i].extensionName);
  134. }
  135. #endif
  136. return true;
  137. }
  138. bool OpenXRAPI::is_extension_supported(const String &p_extension) const {
  139. for (uint32_t i = 0; i < num_supported_extensions; i++) {
  140. if (supported_extensions[i].extensionName == p_extension) {
  141. #ifdef DEBUG
  142. print_line("OpenXR: requested extension", p_extension, "is supported");
  143. #endif
  144. return true;
  145. }
  146. }
  147. #ifdef DEBUG
  148. print_line("OpenXR: requested extension", p_extension, "is not supported");
  149. #endif
  150. return false;
  151. }
  152. void OpenXRAPI::copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len) {
  153. CharString char_string = p_string.utf8();
  154. int len = char_string.length();
  155. if (len < p_buffer_len - 1) {
  156. // was having weird CI issues with strcpy so....
  157. memcpy(p_buffer, char_string.get_data(), len);
  158. p_buffer[len] = '\0';
  159. } else {
  160. memcpy(p_buffer, char_string.get_data(), p_buffer_len - 1);
  161. p_buffer[p_buffer_len - 1] = '\0';
  162. }
  163. }
  164. bool OpenXRAPI::create_instance() {
  165. // Create our OpenXR instance, this will query any registered extension wrappers for extensions we need to enable.
  166. // Append the extensions requested by the registered extension wrappers.
  167. HashMap<String, bool *> requested_extensions;
  168. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  169. const HashMap<String, bool *> &wrapper_request_extensions = wrapper->get_request_extensions();
  170. // requested_extensions.insert(wrapper_request_extensions.begin(), wrapper_request_extensions.end());
  171. for (auto &requested_extension : wrapper_request_extensions) {
  172. requested_extensions[requested_extension.key] = requested_extension.value;
  173. }
  174. }
  175. // Add optional extensions for controllers that may be supported.
  176. // Overkill to create extension classes for this.
  177. requested_extensions[XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME] = &ext_hp_mixed_reality_available;
  178. requested_extensions[XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME] = &ext_samsung_odyssey_available;
  179. requested_extensions[XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_cosmos_available;
  180. requested_extensions[XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_focus3_available;
  181. requested_extensions[XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_huawei_controller_available;
  182. // Check which extensions are supported
  183. enabled_extensions.clear();
  184. for (auto &requested_extension : requested_extensions) {
  185. if (!is_extension_supported(requested_extension.key)) {
  186. if (requested_extension.value == nullptr) {
  187. // nullptr means this is a manditory extension so we fail
  188. ERR_FAIL_V_MSG(false, "OpenXR: OpenXR Runtime does not support OpenGL extension!");
  189. } else {
  190. // set this extension as not supported
  191. *requested_extension.value = false;
  192. }
  193. } else if (requested_extension.value != nullptr) {
  194. // set this extension as supported
  195. *requested_extension.value = true;
  196. // and record that we want to enable it
  197. enabled_extensions.push_back(requested_extension.key.ascii());
  198. } else {
  199. // record that we want to enable this
  200. enabled_extensions.push_back(requested_extension.key.ascii());
  201. }
  202. }
  203. Vector<const char *> extension_ptrs;
  204. for (int i = 0; i < enabled_extensions.size(); i++) {
  205. extension_ptrs.push_back(enabled_extensions[i].get_data());
  206. }
  207. // Get our project name
  208. String project_name = GLOBAL_GET("application/config/name");
  209. // Create our OpenXR instance
  210. XrApplicationInfo application_info{
  211. "", // applicationName, we'll set this down below
  212. 1, // applicationVersion, we don't currently have this
  213. "Godot Game Engine", // engineName
  214. VERSION_MAJOR * 10000 + VERSION_MINOR * 100 + VERSION_PATCH, // engineVersion 4.0 -> 40000, 4.0.1 -> 40001, 4.1 -> 40100, etc.
  215. XR_CURRENT_API_VERSION // apiVersion
  216. };
  217. XrInstanceCreateInfo instance_create_info = {
  218. XR_TYPE_INSTANCE_CREATE_INFO, // type
  219. nullptr, // next
  220. 0, // createFlags
  221. application_info, // applicationInfo
  222. 0, // enabledApiLayerCount, need to find out if we need support for this?
  223. nullptr, // enabledApiLayerNames
  224. uint32_t(extension_ptrs.size()), // enabledExtensionCount
  225. extension_ptrs.ptr() // enabledExtensionNames
  226. };
  227. copy_string_to_char_buffer(project_name, instance_create_info.applicationInfo.applicationName, XR_MAX_APPLICATION_NAME_SIZE);
  228. XrResult result = xrCreateInstance(&instance_create_info, &instance);
  229. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "Failed to create XR instance.");
  230. // from this point on we can use get_error_string to get more info about our errors...
  231. XrInstanceProperties instanceProps = {
  232. XR_TYPE_INSTANCE_PROPERTIES, // type;
  233. nullptr, // next
  234. 0, // runtimeVersion, from here will be set by our get call
  235. "" // runtimeName
  236. };
  237. OPENXR_API_INIT_XR_FUNC_V(xrGetInstanceProperties);
  238. result = xrGetInstanceProperties(instance, &instanceProps);
  239. if (XR_FAILED(result)) {
  240. // not fatal probably
  241. print_line("OpenXR: Failed to get XR instance properties [", get_error_string(result), "]");
  242. } else {
  243. print_line("OpenXR: Running on OpenXR runtime: ", instanceProps.runtimeName, " ", OpenXRUtil::make_xr_version_string(instanceProps.runtimeVersion));
  244. }
  245. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  246. wrapper->on_instance_created(instance);
  247. }
  248. return true;
  249. }
  250. bool OpenXRAPI::get_system_info() {
  251. // Retrieve basic OpenXR system info based on the form factor we desire
  252. // Retrieve the system for our form factor, fails if form factor is not available
  253. XrSystemGetInfo system_get_info = {
  254. XR_TYPE_SYSTEM_GET_INFO, // type;
  255. nullptr, // next
  256. form_factor // formFactor
  257. };
  258. XrResult result = xrGetSystem(instance, &system_get_info, &system_id);
  259. if (XR_FAILED(result)) {
  260. print_line("OpenXR: Failed to get system for our form factor [", get_error_string(result), "]");
  261. return false;
  262. }
  263. // obtain info about our system, writing this out completely to make CI on Linux happy..
  264. void *next_pointer = nullptr;
  265. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  266. void *np = wrapper->set_system_properties_and_get_next_pointer(next_pointer);
  267. if (np != nullptr) {
  268. next_pointer = np;
  269. }
  270. }
  271. XrSystemProperties system_properties = {
  272. XR_TYPE_SYSTEM_PROPERTIES, // type
  273. next_pointer, // next
  274. 0, // systemId, from here will be set by our get call
  275. 0, // vendorId
  276. "", // systemName
  277. {
  278. 0, // maxSwapchainImageHeight
  279. 0, // maxSwapchainImageWidth
  280. 0, // maxLayerCount
  281. }, // graphicsProperties
  282. {
  283. false, // orientationTracking
  284. false // positionTracking
  285. } // trackingProperties
  286. };
  287. result = xrGetSystemProperties(instance, system_id, &system_properties);
  288. if (XR_FAILED(result)) {
  289. print_line("OpenXR: Failed to get System properties [", get_error_string(result), "]");
  290. return false;
  291. }
  292. // remember this state, we'll use it later
  293. system_name = String(system_properties.systemName);
  294. vendor_id = system_properties.vendorId;
  295. graphics_properties = system_properties.graphicsProperties;
  296. tracking_properties = system_properties.trackingProperties;
  297. return true;
  298. }
  299. bool OpenXRAPI::load_supported_view_configuration_types() {
  300. // This queries the supported configuration types, likely there will only be one choosing between Mono (phone AR) and Stereo (HMDs)
  301. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  302. if (supported_view_configuration_types != nullptr) {
  303. // free previous results
  304. memfree(supported_view_configuration_types);
  305. supported_view_configuration_types = nullptr;
  306. }
  307. XrResult result = xrEnumerateViewConfigurations(instance, system_id, 0, &num_view_configuration_types, nullptr);
  308. if (XR_FAILED(result)) {
  309. print_line("OpenXR: Failed to get view configuration count [", get_error_string(result), "]");
  310. return false;
  311. }
  312. supported_view_configuration_types = (XrViewConfigurationType *)memalloc(sizeof(XrViewConfigurationType) * num_view_configuration_types);
  313. ERR_FAIL_NULL_V(supported_view_configuration_types, false);
  314. result = xrEnumerateViewConfigurations(instance, system_id, num_view_configuration_types, &num_view_configuration_types, supported_view_configuration_types);
  315. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerateview configurations");
  316. #ifdef DEBUG
  317. for (uint32_t i = 0; i < num_view_configuration_types; i++) {
  318. print_line("OpenXR: Found supported view configuration ", OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[i]));
  319. }
  320. #endif
  321. return true;
  322. }
  323. bool OpenXRAPI::is_view_configuration_supported(XrViewConfigurationType p_configuration_type) const {
  324. ERR_FAIL_NULL_V(supported_view_configuration_types, false);
  325. for (uint32_t i = 0; i < num_view_configuration_types; i++) {
  326. if (supported_view_configuration_types[i] == p_configuration_type) {
  327. return true;
  328. }
  329. }
  330. return false;
  331. }
  332. bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType p_configuration_type) {
  333. // This loads our view configuration for each view so for a stereo HMD, we'll get two entries (that are likely identical)
  334. // The returned data supplies us with the recommended render target size
  335. if (!is_view_configuration_supported(p_configuration_type)) {
  336. print_line("OpenXR: View configuration ", OpenXRUtil::get_view_configuration_name(view_configuration), " is not supported.");
  337. return false;
  338. }
  339. if (view_configuration_views != nullptr) {
  340. // free previous results
  341. memfree(view_configuration_views);
  342. view_configuration_views = nullptr;
  343. }
  344. XrResult result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, 0, &view_count, nullptr);
  345. if (XR_FAILED(result)) {
  346. print_line("OpenXR: Failed to get view configuration count [", get_error_string(result), "]");
  347. return false;
  348. }
  349. view_configuration_views = (XrViewConfigurationView *)memalloc(sizeof(XrViewConfigurationView) * view_count);
  350. ERR_FAIL_NULL_V(view_configuration_views, false);
  351. for (uint32_t i = 0; i < view_count; i++) {
  352. view_configuration_views[i].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
  353. view_configuration_views[i].next = nullptr;
  354. }
  355. result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, view_count, &view_count, view_configuration_views);
  356. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate view configurations");
  357. #ifdef DEBUG
  358. for (uint32_t i = 0; i < view_count; i++) {
  359. print_line("OpenXR: Found supported view configuration view");
  360. print_line(" - width: ", view_configuration_views[i].maxImageRectWidth);
  361. print_line(" - height: ", view_configuration_views[i].maxImageRectHeight);
  362. print_line(" - sample count: ", view_configuration_views[i].maxSwapchainSampleCount);
  363. print_line(" - recommended render width: ", view_configuration_views[i].recommendedImageRectWidth);
  364. print_line(" - recommended render height: ", view_configuration_views[i].recommendedImageRectHeight);
  365. print_line(" - recommended render sample count: ", view_configuration_views[i].recommendedSwapchainSampleCount);
  366. }
  367. #endif
  368. return true;
  369. }
  370. void OpenXRAPI::destroy_instance() {
  371. if (view_configuration_views != nullptr) {
  372. memfree(view_configuration_views);
  373. view_configuration_views = nullptr;
  374. }
  375. if (supported_view_configuration_types != nullptr) {
  376. memfree(supported_view_configuration_types);
  377. supported_view_configuration_types = nullptr;
  378. }
  379. if (instance != XR_NULL_HANDLE) {
  380. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  381. wrapper->on_instance_destroyed();
  382. }
  383. xrDestroyInstance(instance);
  384. instance = XR_NULL_HANDLE;
  385. }
  386. enabled_extensions.clear();
  387. }
  388. bool OpenXRAPI::create_session() {
  389. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  390. ERR_FAIL_COND_V(session != XR_NULL_HANDLE, false);
  391. void *next_pointer = nullptr;
  392. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  393. void *np = wrapper->set_session_create_and_get_next_pointer(next_pointer);
  394. if (np != nullptr) {
  395. next_pointer = np;
  396. }
  397. }
  398. XrSessionCreateInfo session_create_info = {
  399. XR_TYPE_SESSION_CREATE_INFO, // type
  400. next_pointer, // next
  401. 0, // createFlags
  402. system_id // systemId
  403. };
  404. XrResult result = xrCreateSession(instance, &session_create_info, &session);
  405. if (XR_FAILED(result)) {
  406. print_line("OpenXR: Failed to create session [", get_error_string(result), "]");
  407. return false;
  408. }
  409. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  410. wrapper->on_session_created(session);
  411. }
  412. return true;
  413. }
  414. bool OpenXRAPI::load_supported_reference_spaces() {
  415. // loads the supported reference spaces for our OpenXR session
  416. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  417. if (supported_reference_spaces != nullptr) {
  418. // free previous results
  419. memfree(supported_reference_spaces);
  420. supported_reference_spaces = nullptr;
  421. }
  422. XrResult result = xrEnumerateReferenceSpaces(session, 0, &num_reference_spaces, nullptr);
  423. if (XR_FAILED(result)) {
  424. print_line("OpenXR: Failed to get reference space count [", get_error_string(result), "]");
  425. return false;
  426. }
  427. supported_reference_spaces = (XrReferenceSpaceType *)memalloc(sizeof(XrReferenceSpaceType) * num_reference_spaces);
  428. ERR_FAIL_NULL_V(supported_reference_spaces, false);
  429. result = xrEnumerateReferenceSpaces(session, num_reference_spaces, &num_reference_spaces, supported_reference_spaces);
  430. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate reference spaces");
  431. // #ifdef DEBUG
  432. for (uint32_t i = 0; i < num_reference_spaces; i++) {
  433. print_line("OpenXR: Found supported reference space ", OpenXRUtil::get_reference_space_name(supported_reference_spaces[i]));
  434. }
  435. // #endif
  436. return true;
  437. }
  438. bool OpenXRAPI::is_reference_space_supported(XrReferenceSpaceType p_reference_space) {
  439. ERR_FAIL_NULL_V(supported_reference_spaces, false);
  440. for (uint32_t i = 0; i < num_reference_spaces; i++) {
  441. if (supported_reference_spaces[i] == p_reference_space) {
  442. return true;
  443. }
  444. }
  445. return false;
  446. }
  447. bool OpenXRAPI::setup_spaces() {
  448. XrResult result;
  449. XrPosef identityPose = {
  450. { 0.0, 0.0, 0.0, 1.0 },
  451. { 0.0, 0.0, 0.0 }
  452. };
  453. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  454. // create play space
  455. {
  456. if (!is_reference_space_supported(reference_space)) {
  457. print_line("OpenXR: reference space ", OpenXRUtil::get_reference_space_name(reference_space), " is not supported.");
  458. return false;
  459. }
  460. XrReferenceSpaceCreateInfo play_space_create_info = {
  461. XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
  462. nullptr, // next
  463. reference_space, // referenceSpaceType
  464. identityPose // poseInReferenceSpace
  465. };
  466. result = xrCreateReferenceSpace(session, &play_space_create_info, &play_space);
  467. if (XR_FAILED(result)) {
  468. print_line("OpenXR: Failed to create play space [", get_error_string(result), "]");
  469. return false;
  470. }
  471. }
  472. // create view space
  473. {
  474. if (!is_reference_space_supported(XR_REFERENCE_SPACE_TYPE_VIEW)) {
  475. print_line("OpenXR: reference space XR_REFERENCE_SPACE_TYPE_VIEW is not supported.");
  476. return false;
  477. }
  478. XrReferenceSpaceCreateInfo view_space_create_info = {
  479. XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
  480. nullptr, // next
  481. XR_REFERENCE_SPACE_TYPE_VIEW, // referenceSpaceType
  482. identityPose // poseInReferenceSpace
  483. };
  484. result = xrCreateReferenceSpace(session, &view_space_create_info, &view_space);
  485. if (XR_FAILED(result)) {
  486. print_line("OpenXR: Failed to create view space [", get_error_string(result), "]");
  487. return false;
  488. }
  489. }
  490. return true;
  491. }
  492. bool OpenXRAPI::load_supported_swapchain_formats() {
  493. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  494. if (supported_swapchain_formats != nullptr) {
  495. // free previous results
  496. memfree(supported_swapchain_formats);
  497. supported_swapchain_formats = nullptr;
  498. }
  499. XrResult result = xrEnumerateSwapchainFormats(session, 0, &num_swapchain_formats, nullptr);
  500. if (XR_FAILED(result)) {
  501. print_line("OpenXR: Failed to get swapchain format count [", get_error_string(result), "]");
  502. return false;
  503. }
  504. supported_swapchain_formats = (int64_t *)memalloc(sizeof(int64_t) * num_swapchain_formats);
  505. ERR_FAIL_NULL_V(supported_swapchain_formats, false);
  506. result = xrEnumerateSwapchainFormats(session, num_swapchain_formats, &num_swapchain_formats, supported_swapchain_formats);
  507. ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate swapchain formats");
  508. // #ifdef DEBUG
  509. for (uint32_t i = 0; i < num_swapchain_formats; i++) {
  510. print_line("OpenXR: Found supported swapchain format ", get_swapchain_format_name(supported_swapchain_formats[i]));
  511. }
  512. // #endif
  513. return true;
  514. }
  515. bool OpenXRAPI::is_swapchain_format_supported(int64_t p_swapchain_format) {
  516. ERR_FAIL_NULL_V(supported_swapchain_formats, false);
  517. for (uint32_t i = 0; i < num_swapchain_formats; i++) {
  518. if (supported_swapchain_formats[i] == p_swapchain_format) {
  519. return true;
  520. }
  521. }
  522. return false;
  523. }
  524. bool OpenXRAPI::create_main_swapchain() {
  525. ERR_FAIL_NULL_V(graphics_extension, false);
  526. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  527. /*
  528. TODO: We need to improve on this, for now we're taking our old approach of creating our main swapchains and substituting
  529. those for the ones Godot normally creates.
  530. This however means we can only use swapchains for our main XR view.
  531. It would have been nicer if we could override the swapchain creation in Godot with ours but we have a timing issue here.
  532. We can't create XR swapchains until after our XR session is fully instantiated, yet Godot creates its swapchain much earlier.
  533. Also Godot only creates a swapchain for the main output.
  534. OpenXR will require us to create swapchains as the render target for additional viewports if we want to use the layer system
  535. to optimise text rendering and background rendering as OpenXR may choose to re-use the results for reprojection while we're
  536. already rendering the next frame.
  537. Finally an area we need to expand upon is that Foveated rendering is only enabled for the swap chain we create,
  538. as we render 3D content into internal buffers that are copied into the swapchain, we don't get any of the performance gains
  539. until such time as we implement VRS.
  540. */
  541. // Build a vector with swapchain formats we want to use, from best fit to worst
  542. Vector<int64_t> usable_swapchain_formats;
  543. int64_t swapchain_format_to_use = 0;
  544. graphics_extension->get_usable_swapchain_formats(usable_swapchain_formats);
  545. // now find out which one is supported
  546. for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) {
  547. if (is_swapchain_format_supported(usable_swapchain_formats[i])) {
  548. swapchain_format_to_use = usable_swapchain_formats[i];
  549. }
  550. }
  551. if (swapchain_format_to_use == 0) {
  552. swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best...
  553. print_line("Couldn't find usable swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead.");
  554. } else {
  555. print_line("Using swap chain format:", get_swapchain_format_name(swapchain_format_to_use));
  556. }
  557. Size2 recommended_size = get_recommended_target_size();
  558. if (!create_swapchain(swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchain, &swapchain_graphics_data)) {
  559. return false;
  560. }
  561. views = (XrView *)memalloc(sizeof(XrView) * view_count);
  562. ERR_FAIL_NULL_V_MSG(views, false, "OpenXR Couldn't allocate memory for views");
  563. projection_views = (XrCompositionLayerProjectionView *)memalloc(sizeof(XrCompositionLayerProjectionView) * view_count);
  564. ERR_FAIL_NULL_V_MSG(projection_views, false, "OpenXR Couldn't allocate memory for projection views");
  565. for (uint32_t i = 0; i < view_count; i++) {
  566. views[i].type = XR_TYPE_VIEW;
  567. views[i].next = nullptr;
  568. projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
  569. projection_views[i].next = nullptr;
  570. projection_views[i].subImage.swapchain = swapchain;
  571. projection_views[i].subImage.imageArrayIndex = i;
  572. projection_views[i].subImage.imageRect.offset.x = 0;
  573. projection_views[i].subImage.imageRect.offset.y = 0;
  574. projection_views[i].subImage.imageRect.extent.width = recommended_size.width;
  575. projection_views[i].subImage.imageRect.extent.height = recommended_size.height;
  576. };
  577. return true;
  578. };
  579. void OpenXRAPI::destroy_session() {
  580. if (running && session != XR_NULL_HANDLE) {
  581. xrEndSession(session);
  582. }
  583. if (graphics_extension) {
  584. graphics_extension->cleanup_swapchain_graphics_data(&swapchain_graphics_data);
  585. }
  586. if (views != nullptr) {
  587. memfree(views);
  588. views = nullptr;
  589. }
  590. if (projection_views != nullptr) {
  591. memfree(projection_views);
  592. projection_views = nullptr;
  593. }
  594. if (swapchain != XR_NULL_HANDLE) {
  595. xrDestroySwapchain(swapchain);
  596. swapchain = XR_NULL_HANDLE;
  597. }
  598. if (supported_swapchain_formats != nullptr) {
  599. memfree(supported_swapchain_formats);
  600. supported_swapchain_formats = nullptr;
  601. }
  602. // destroy our spaces
  603. if (play_space != XR_NULL_HANDLE) {
  604. xrDestroySpace(play_space);
  605. play_space = XR_NULL_HANDLE;
  606. }
  607. if (view_space != XR_NULL_HANDLE) {
  608. xrDestroySpace(view_space);
  609. view_space = XR_NULL_HANDLE;
  610. }
  611. if (supported_reference_spaces != nullptr) {
  612. // free previous results
  613. memfree(supported_reference_spaces);
  614. supported_reference_spaces = nullptr;
  615. }
  616. if (session != XR_NULL_HANDLE) {
  617. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  618. wrapper->on_session_destroyed();
  619. }
  620. xrDestroySession(session);
  621. session = XR_NULL_HANDLE;
  622. }
  623. }
  624. bool OpenXRAPI::create_swapchain(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) {
  625. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  626. ERR_FAIL_NULL_V(graphics_extension, false);
  627. XrResult result;
  628. void *next_pointer = nullptr;
  629. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  630. void *np = wrapper->set_swapchain_create_info_and_get_next_pointer(next_pointer);
  631. if (np != nullptr) {
  632. next_pointer = np;
  633. }
  634. }
  635. XrSwapchainCreateInfo swapchain_create_info = {
  636. XR_TYPE_SWAPCHAIN_CREATE_INFO, // type
  637. next_pointer, // next
  638. 0, // createFlags
  639. XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, // usageFlags
  640. p_swapchain_format, // format
  641. p_sample_count, // sampleCount
  642. p_width, // width
  643. p_height, // height
  644. 1, // faceCount
  645. p_array_size, // arraySize
  646. 1 // mipCount
  647. };
  648. XrSwapchain new_swapchain;
  649. result = xrCreateSwapchain(session, &swapchain_create_info, &new_swapchain);
  650. if (XR_FAILED(result)) {
  651. print_line("OpenXR: Failed to get swapchain [", get_error_string(result), "]");
  652. return false;
  653. }
  654. 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)) {
  655. xrDestroySwapchain(new_swapchain);
  656. return false;
  657. }
  658. r_swapchain = new_swapchain;
  659. return true;
  660. }
  661. bool OpenXRAPI::on_state_idle() {
  662. #ifdef DEBUG
  663. print_line("On state idle");
  664. #endif
  665. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  666. wrapper->on_state_idle();
  667. }
  668. return true;
  669. }
  670. bool OpenXRAPI::on_state_ready() {
  671. #ifdef DEBUG
  672. print_line("On state ready");
  673. #endif
  674. // begin session
  675. XrSessionBeginInfo session_begin_info = {
  676. XR_TYPE_SESSION_BEGIN_INFO, // type
  677. nullptr, // next
  678. view_configuration // primaryViewConfigurationType
  679. };
  680. XrResult result = xrBeginSession(session, &session_begin_info);
  681. if (XR_FAILED(result)) {
  682. print_line("OpenXR: Failed to begin session [", get_error_string(result), "]");
  683. return false;
  684. }
  685. // This is when we create our swapchain, this can be a "long" time after Godot finishes, we can deal with this for now
  686. // but once we want to provide Viewports for additional layers where OpenXR requires us to create further swapchains,
  687. // we'll be creating those viewport WAY before we reach this point.
  688. // We may need to implement a wait in our init in main.cpp polling our events until the session is ready.
  689. // That will be very very ugly
  690. // The other possibility is to create a separate OpenXRViewport type specifically for this goal as part of our OpenXR module
  691. if (!create_main_swapchain()) {
  692. return false;
  693. }
  694. // we're running
  695. running = true;
  696. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  697. wrapper->on_state_ready();
  698. }
  699. if (xr_interface) {
  700. xr_interface->on_state_ready();
  701. }
  702. // TODO Tell android
  703. return true;
  704. }
  705. bool OpenXRAPI::on_state_synchronized() {
  706. #ifdef DEBUG
  707. print_line("On state synchronized");
  708. #endif
  709. // Just in case, see if we already have active trackers...
  710. List<RID> trackers;
  711. tracker_owner.get_owned_list(&trackers);
  712. for (int i = 0; i < trackers.size(); i++) {
  713. tracker_check_profile(trackers[i]);
  714. }
  715. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  716. wrapper->on_state_synchronized();
  717. }
  718. return true;
  719. }
  720. bool OpenXRAPI::on_state_visible() {
  721. #ifdef DEBUG
  722. print_line("On state visible");
  723. #endif
  724. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  725. wrapper->on_state_visible();
  726. }
  727. if (xr_interface) {
  728. xr_interface->on_state_visible();
  729. }
  730. return true;
  731. }
  732. bool OpenXRAPI::on_state_focused() {
  733. #ifdef DEBUG
  734. print_line("On state focused");
  735. #endif
  736. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  737. wrapper->on_state_focused();
  738. }
  739. if (xr_interface) {
  740. xr_interface->on_state_focused();
  741. }
  742. return true;
  743. }
  744. bool OpenXRAPI::on_state_stopping() {
  745. #ifdef DEBUG
  746. print_line("On state stopping");
  747. #endif
  748. if (xr_interface) {
  749. xr_interface->on_state_stopping();
  750. }
  751. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  752. wrapper->on_state_stopping();
  753. }
  754. if (running) {
  755. XrResult result = xrEndSession(session);
  756. if (XR_FAILED(result)) {
  757. // we only report this..
  758. print_line("OpenXR: Failed to end session [", get_error_string(result), "]");
  759. }
  760. running = false;
  761. }
  762. // TODO further cleanup
  763. return true;
  764. }
  765. bool OpenXRAPI::on_state_loss_pending() {
  766. #ifdef DEBUG
  767. print_line("On state loss pending");
  768. #endif
  769. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  770. wrapper->on_state_loss_pending();
  771. }
  772. // 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)
  773. return true;
  774. }
  775. bool OpenXRAPI::on_state_exiting() {
  776. #ifdef DEBUG
  777. print_line("On state existing");
  778. #endif
  779. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  780. wrapper->on_state_exiting();
  781. }
  782. // 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)
  783. return true;
  784. }
  785. bool OpenXRAPI::is_initialized() {
  786. return (instance != XR_NULL_HANDLE);
  787. }
  788. bool OpenXRAPI::is_running() {
  789. if (instance == XR_NULL_HANDLE) {
  790. return false;
  791. }
  792. if (session == XR_NULL_HANDLE) {
  793. return false;
  794. }
  795. return running;
  796. }
  797. bool OpenXRAPI::openxr_loader_init() {
  798. #ifdef ANDROID_ENABLED
  799. ERR_FAIL_COND_V_MSG(openxr_loader_library_handle != nullptr, false, "OpenXR Loader library is already loaded.");
  800. {
  801. Error error_code = OS::get_singleton()->open_dynamic_library(OPENXR_LOADER_NAME, openxr_loader_library_handle);
  802. ERR_FAIL_COND_V_MSG(error_code != OK, false, "OpenXR loader not found.");
  803. }
  804. {
  805. Error error_code = OS::get_singleton()->get_dynamic_library_symbol_handle(openxr_loader_library_handle, "xrGetInstanceProcAddr", (void *&)xrGetInstanceProcAddr);
  806. ERR_FAIL_COND_V_MSG(error_code != OK, false, "Symbol xrGetInstanceProcAddr not found in OpenXR Loader library.");
  807. }
  808. #endif
  809. // Resolve the symbols that don't require an instance
  810. OPENXR_API_INIT_XR_FUNC_V(xrCreateInstance);
  811. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateApiLayerProperties);
  812. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateInstanceExtensionProperties);
  813. return true;
  814. }
  815. bool OpenXRAPI::resolve_instance_openxr_symbols() {
  816. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  817. OPENXR_API_INIT_XR_FUNC_V(xrAcquireSwapchainImage);
  818. OPENXR_API_INIT_XR_FUNC_V(xrApplyHapticFeedback);
  819. OPENXR_API_INIT_XR_FUNC_V(xrAttachSessionActionSets);
  820. OPENXR_API_INIT_XR_FUNC_V(xrBeginFrame);
  821. OPENXR_API_INIT_XR_FUNC_V(xrBeginSession);
  822. OPENXR_API_INIT_XR_FUNC_V(xrCreateAction);
  823. OPENXR_API_INIT_XR_FUNC_V(xrCreateActionSet);
  824. OPENXR_API_INIT_XR_FUNC_V(xrCreateActionSpace);
  825. OPENXR_API_INIT_XR_FUNC_V(xrCreateReferenceSpace);
  826. OPENXR_API_INIT_XR_FUNC_V(xrCreateSession);
  827. OPENXR_API_INIT_XR_FUNC_V(xrCreateSwapchain);
  828. OPENXR_API_INIT_XR_FUNC_V(xrDestroyAction);
  829. OPENXR_API_INIT_XR_FUNC_V(xrDestroyActionSet);
  830. OPENXR_API_INIT_XR_FUNC_V(xrDestroyInstance);
  831. OPENXR_API_INIT_XR_FUNC_V(xrDestroySession);
  832. OPENXR_API_INIT_XR_FUNC_V(xrDestroySpace);
  833. OPENXR_API_INIT_XR_FUNC_V(xrDestroySwapchain);
  834. OPENXR_API_INIT_XR_FUNC_V(xrEndFrame);
  835. OPENXR_API_INIT_XR_FUNC_V(xrEndSession);
  836. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateReferenceSpaces);
  837. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateSwapchainFormats);
  838. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateViewConfigurations);
  839. OPENXR_API_INIT_XR_FUNC_V(xrEnumerateViewConfigurationViews);
  840. OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateBoolean);
  841. OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateFloat);
  842. OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateVector2f);
  843. OPENXR_API_INIT_XR_FUNC_V(xrGetCurrentInteractionProfile);
  844. OPENXR_API_INIT_XR_FUNC_V(xrGetSystem);
  845. OPENXR_API_INIT_XR_FUNC_V(xrGetSystemProperties);
  846. OPENXR_API_INIT_XR_FUNC_V(xrLocateViews);
  847. OPENXR_API_INIT_XR_FUNC_V(xrLocateSpace);
  848. OPENXR_API_INIT_XR_FUNC_V(xrPathToString);
  849. OPENXR_API_INIT_XR_FUNC_V(xrPollEvent);
  850. OPENXR_API_INIT_XR_FUNC_V(xrReleaseSwapchainImage);
  851. OPENXR_API_INIT_XR_FUNC_V(xrResultToString);
  852. OPENXR_API_INIT_XR_FUNC_V(xrStringToPath);
  853. OPENXR_API_INIT_XR_FUNC_V(xrSuggestInteractionProfileBindings);
  854. OPENXR_API_INIT_XR_FUNC_V(xrSyncActions);
  855. OPENXR_API_INIT_XR_FUNC_V(xrWaitFrame);
  856. OPENXR_API_INIT_XR_FUNC_V(xrWaitSwapchainImage);
  857. return true;
  858. }
  859. XrResult OpenXRAPI::get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr) {
  860. XrResult result = xrGetInstanceProcAddr(instance, p_name, p_addr);
  861. if (result != XR_SUCCESS) {
  862. String error_message = String("Symbol ") + p_name + " not found in OpenXR instance.";
  863. ERR_FAIL_COND_V_MSG(true, result, error_message.utf8().get_data());
  864. }
  865. return result;
  866. }
  867. bool OpenXRAPI::initialize(const String &p_rendering_driver) {
  868. ERR_FAIL_COND_V_MSG(instance != XR_NULL_HANDLE, false, "OpenXR instance was already created");
  869. if (!openxr_loader_init()) {
  870. return false;
  871. }
  872. if (p_rendering_driver == "vulkan") {
  873. #ifdef VULKAN_ENABLED
  874. graphics_extension = memnew(OpenXRVulkanExtension(this));
  875. register_extension_wrapper(graphics_extension);
  876. #else
  877. // shouldn't be possible...
  878. ERR_FAIL_V(false);
  879. #endif
  880. } else if (p_rendering_driver == "opengl3") {
  881. #ifdef GLES3_ENABLED
  882. // graphics_extension = memnew(OpenXROpenGLExtension(this));
  883. // register_extension_wrapper(graphics_extension);
  884. ERR_FAIL_V_MSG(false, "OpenXR: OpenGL is not supported at this time.");
  885. #else
  886. // shouldn't be possible...
  887. ERR_FAIL_V(false);
  888. #endif
  889. } else {
  890. ERR_FAIL_V_MSG(false, "OpenXR: Unsupported rendering device.");
  891. }
  892. // initialize
  893. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  894. wrapper->on_before_instance_created();
  895. }
  896. if (!load_layer_properties()) {
  897. destroy_instance();
  898. return false;
  899. }
  900. if (!load_supported_extensions()) {
  901. destroy_instance();
  902. return false;
  903. }
  904. if (!create_instance()) {
  905. destroy_instance();
  906. return false;
  907. }
  908. if (!resolve_instance_openxr_symbols()) {
  909. destroy_instance();
  910. return false;
  911. }
  912. if (!get_system_info()) {
  913. destroy_instance();
  914. return false;
  915. }
  916. if (!load_supported_view_configuration_types()) {
  917. destroy_instance();
  918. return false;
  919. }
  920. if (!load_supported_view_configuration_views(view_configuration)) {
  921. destroy_instance();
  922. return false;
  923. }
  924. return true;
  925. }
  926. bool OpenXRAPI::initialize_session() {
  927. if (!create_session()) {
  928. destroy_session();
  929. return false;
  930. }
  931. if (!load_supported_reference_spaces()) {
  932. destroy_session();
  933. return false;
  934. }
  935. if (!setup_spaces()) {
  936. destroy_session();
  937. return false;
  938. }
  939. if (!load_supported_swapchain_formats()) {
  940. destroy_session();
  941. return false;
  942. }
  943. return true;
  944. }
  945. void OpenXRAPI::finish() {
  946. destroy_session();
  947. destroy_instance();
  948. }
  949. void OpenXRAPI::set_xr_interface(OpenXRInterface *p_xr_interface) {
  950. xr_interface = p_xr_interface;
  951. }
  952. void OpenXRAPI::register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) {
  953. registered_extension_wrappers.push_back(p_extension_wrapper);
  954. }
  955. Size2 OpenXRAPI::get_recommended_target_size() {
  956. ERR_FAIL_NULL_V(view_configuration_views, Size2());
  957. Size2 target_size;
  958. target_size.width = view_configuration_views[0].recommendedImageRectWidth;
  959. target_size.height = view_configuration_views[0].recommendedImageRectHeight;
  960. return target_size;
  961. }
  962. XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
  963. XrResult result;
  964. ERR_FAIL_COND_V(!running, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  965. // xrWaitFrame not run yet
  966. if (frame_state.predictedDisplayTime == 0) {
  967. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  968. }
  969. // Get timing for the next frame, as that is the current frame we're processing
  970. XrTime display_time = get_next_frame_time();
  971. XrSpaceVelocity velocity = {
  972. XR_TYPE_SPACE_VELOCITY, // type
  973. nullptr, // next
  974. 0, // velocityFlags
  975. { 0.0, 0.0, 0.0 }, // linearVelocity
  976. { 0.0, 0.0, 0.0 } // angularVelocity
  977. };
  978. XrSpaceLocation location = {
  979. XR_TYPE_SPACE_LOCATION, // type
  980. &velocity, // next
  981. 0, // locationFlags
  982. {
  983. { 0.0, 0.0, 0.0, 0.0 }, // orientation
  984. { 0.0, 0.0, 0.0 } // position
  985. } // pose
  986. };
  987. result = xrLocateSpace(view_space, play_space, display_time, &location);
  988. if (XR_FAILED(result)) {
  989. print_line("OpenXR: Failed to locate view space in play space [", get_error_string(result), "]");
  990. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  991. }
  992. XRPose::TrackingConfidence confidence = transform_from_location(location, r_transform);
  993. parse_velocities(velocity, r_linear_velocity, r_angular_velocity);
  994. if (head_pose_confidence != confidence) {
  995. // prevent error spam
  996. head_pose_confidence = confidence;
  997. if (head_pose_confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) {
  998. print_line("OpenXR head space location not valid (check tracking?)");
  999. #ifdef DEBUG
  1000. } else if (head_pose_confidence == XRPose::XR_TRACKING_CONFIDENCE_LOW) {
  1001. print_line("OpenVR Head pose now tracking with low confidence");
  1002. } else {
  1003. print_line("OpenVR Head pose now tracking with high confidence");
  1004. #endif
  1005. }
  1006. }
  1007. return confidence;
  1008. }
  1009. bool OpenXRAPI::get_view_transform(uint32_t p_view, Transform3D &r_transform) {
  1010. ERR_FAIL_COND_V(!running, false);
  1011. // xrWaitFrame not run yet
  1012. if (frame_state.predictedDisplayTime == 0) {
  1013. return false;
  1014. }
  1015. // we don't have valid view info
  1016. if (views == nullptr || !view_pose_valid) {
  1017. return false;
  1018. }
  1019. // Note, the timing of this is set right before rendering, which is what we need here.
  1020. r_transform = transform_from_pose(views[p_view].pose);
  1021. return true;
  1022. }
  1023. bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, Projection &p_camera_matrix) {
  1024. ERR_FAIL_COND_V(!running, false);
  1025. ERR_FAIL_NULL_V(graphics_extension, false);
  1026. // xrWaitFrame not run yet
  1027. if (frame_state.predictedDisplayTime == 0) {
  1028. return false;
  1029. }
  1030. // we don't have valid view info
  1031. if (views == nullptr || !view_pose_valid) {
  1032. return false;
  1033. }
  1034. return graphics_extension->create_projection_fov(views[p_view].fov, p_z_near, p_z_far, p_camera_matrix);
  1035. }
  1036. bool OpenXRAPI::poll_events() {
  1037. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  1038. XrEventDataBuffer runtimeEvent;
  1039. runtimeEvent.type = XR_TYPE_EVENT_DATA_BUFFER;
  1040. runtimeEvent.next = nullptr;
  1041. // runtimeEvent.varying = ...
  1042. XrResult pollResult = xrPollEvent(instance, &runtimeEvent);
  1043. while (pollResult == XR_SUCCESS) {
  1044. bool handled = false;
  1045. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1046. handled |= wrapper->on_event_polled(runtimeEvent);
  1047. }
  1048. switch (runtimeEvent.type) {
  1049. case XR_TYPE_EVENT_DATA_EVENTS_LOST: {
  1050. XrEventDataEventsLost *event = (XrEventDataEventsLost *)&runtimeEvent;
  1051. // We probably didn't poll fast enough, just output warning
  1052. WARN_PRINT("OpenXR EVENT: " + itos(event->lostEventCount) + " event data lost!");
  1053. } break;
  1054. case XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR: {
  1055. // XrEventDataVisibilityMaskChangedKHR *event = (XrEventDataVisibilityMaskChangedKHR *)&runtimeEvent;
  1056. // TODO implement this in the future, we should call xrGetVisibilityMaskKHR to obtain a mask,
  1057. // this will allow us to prevent rendering the part of our view which is never displayed giving us
  1058. // a decent performance improvement.
  1059. print_verbose("OpenXR EVENT: STUB: visibility mask changed");
  1060. } break;
  1061. case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: {
  1062. XrEventDataInstanceLossPending *event = (XrEventDataInstanceLossPending *)&runtimeEvent;
  1063. // TODO We get this event if we're about to loose our OpenXR instance.
  1064. // We should queue exiting Godot at this point.
  1065. print_verbose("OpenXR EVENT: instance loss pending at " + itos(event->lossTime));
  1066. return false;
  1067. } break;
  1068. case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: {
  1069. XrEventDataSessionStateChanged *event = (XrEventDataSessionStateChanged *)&runtimeEvent;
  1070. session_state = event->state;
  1071. if (session_state >= XR_SESSION_STATE_MAX_ENUM) {
  1072. print_verbose("OpenXR EVENT: session state changed to UNKNOWN - " + itos(session_state));
  1073. } else {
  1074. print_verbose("OpenXR EVENT: session state changed to " + OpenXRUtil::get_session_state_name(session_state));
  1075. switch (session_state) {
  1076. case XR_SESSION_STATE_IDLE:
  1077. on_state_idle();
  1078. break;
  1079. case XR_SESSION_STATE_READY:
  1080. on_state_ready();
  1081. break;
  1082. case XR_SESSION_STATE_SYNCHRONIZED:
  1083. on_state_synchronized();
  1084. break;
  1085. case XR_SESSION_STATE_VISIBLE:
  1086. on_state_visible();
  1087. break;
  1088. case XR_SESSION_STATE_FOCUSED:
  1089. on_state_focused();
  1090. break;
  1091. case XR_SESSION_STATE_STOPPING:
  1092. on_state_stopping();
  1093. break;
  1094. case XR_SESSION_STATE_LOSS_PENDING:
  1095. on_state_loss_pending();
  1096. break;
  1097. case XR_SESSION_STATE_EXITING:
  1098. on_state_exiting();
  1099. break;
  1100. default:
  1101. break;
  1102. }
  1103. }
  1104. } break;
  1105. case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING: {
  1106. XrEventDataReferenceSpaceChangePending *event = (XrEventDataReferenceSpaceChangePending *)&runtimeEvent;
  1107. print_verbose("OpenXR EVENT: reference space type " + OpenXRUtil::get_reference_space_name(event->referenceSpaceType) + " change pending!");
  1108. if (event->poseValid && xr_interface) {
  1109. xr_interface->on_pose_recentered();
  1110. }
  1111. } break;
  1112. case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED: {
  1113. print_verbose("OpenXR EVENT: interaction profile changed!");
  1114. XrEventDataInteractionProfileChanged *event = (XrEventDataInteractionProfileChanged *)&runtimeEvent;
  1115. List<RID> trackers;
  1116. tracker_owner.get_owned_list(&trackers);
  1117. for (int i = 0; i < trackers.size(); i++) {
  1118. tracker_check_profile(trackers[i], event->session);
  1119. }
  1120. } break;
  1121. default:
  1122. if (!handled) {
  1123. print_verbose("OpenXR Unhandled event type " + OpenXRUtil::get_structure_type_name(runtimeEvent.type));
  1124. }
  1125. break;
  1126. }
  1127. runtimeEvent.type = XR_TYPE_EVENT_DATA_BUFFER;
  1128. pollResult = xrPollEvent(instance, &runtimeEvent);
  1129. }
  1130. if (pollResult == XR_EVENT_UNAVAILABLE) {
  1131. // processed all events in the queue
  1132. return true;
  1133. } else {
  1134. ERR_FAIL_V_MSG(false, "OpenXR: Failed to poll events!");
  1135. }
  1136. }
  1137. bool OpenXRAPI::process() {
  1138. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  1139. if (!poll_events()) {
  1140. return false;
  1141. }
  1142. if (!running) {
  1143. return false;
  1144. }
  1145. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1146. wrapper->on_process();
  1147. }
  1148. return true;
  1149. }
  1150. bool OpenXRAPI::acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index) {
  1151. ERR_FAIL_COND_V(image_acquired, true); // this was not released when it should be, error out and re-use...
  1152. XrResult result;
  1153. XrSwapchainImageAcquireInfo swapchain_image_acquire_info = {
  1154. XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, // type
  1155. nullptr // next
  1156. };
  1157. result = xrAcquireSwapchainImage(p_swapchain, &swapchain_image_acquire_info, &r_image_index);
  1158. if (XR_FAILED(result)) {
  1159. print_line("OpenXR: failed to acquire swapchain image [", get_error_string(result), "]");
  1160. return false;
  1161. }
  1162. XrSwapchainImageWaitInfo swapchain_image_wait_info = {
  1163. XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, // type
  1164. nullptr, // next
  1165. 17000000 // timeout in nanoseconds
  1166. };
  1167. result = xrWaitSwapchainImage(p_swapchain, &swapchain_image_wait_info);
  1168. if (XR_FAILED(result)) {
  1169. print_line("OpenXR: failed to wait for swapchain image [", get_error_string(result), "]");
  1170. return false;
  1171. }
  1172. return true;
  1173. }
  1174. bool OpenXRAPI::release_image(XrSwapchain p_swapchain) {
  1175. XrSwapchainImageReleaseInfo swapchain_image_release_info = {
  1176. XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, // type
  1177. nullptr // next
  1178. };
  1179. XrResult result = xrReleaseSwapchainImage(swapchain, &swapchain_image_release_info);
  1180. if (XR_FAILED(result)) {
  1181. print_line("OpenXR: failed to release swapchain image! [", get_error_string(result), "]");
  1182. return false;
  1183. }
  1184. return true;
  1185. }
  1186. void OpenXRAPI::pre_render() {
  1187. ERR_FAIL_COND(instance == XR_NULL_HANDLE);
  1188. if (!running) {
  1189. return;
  1190. }
  1191. // Waitframe does 2 important things in our process:
  1192. // 1) It provides us with predictive timing, telling us when OpenXR expects to display the frame we're about to commit
  1193. // 2) It will use the previous timing to pause our thread so that rendering starts as close to displaying as possible
  1194. // This must thus be called as close to when we start rendering as possible
  1195. XrFrameWaitInfo frame_wait_info = { XR_TYPE_FRAME_WAIT_INFO, nullptr };
  1196. XrResult result = xrWaitFrame(session, &frame_wait_info, &frame_state);
  1197. if (XR_FAILED(result)) {
  1198. print_line("OpenXR: xrWaitFrame() was not successful [", get_error_string(result), "]");
  1199. // reset just in case
  1200. frame_state.predictedDisplayTime = 0;
  1201. frame_state.predictedDisplayPeriod = 0;
  1202. frame_state.shouldRender = false;
  1203. return;
  1204. }
  1205. if (frame_state.predictedDisplayPeriod > 500000000) {
  1206. // display period more then 0.5 seconds? must be wrong data
  1207. print_verbose("OpenXR resetting invalid display period " + rtos(frame_state.predictedDisplayPeriod));
  1208. frame_state.predictedDisplayPeriod = 0;
  1209. }
  1210. for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
  1211. wrapper->on_pre_render();
  1212. }
  1213. // Get our view info for the frame we're about to render, note from the OpenXR manual:
  1214. // "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"
  1215. // We're calling this "relatively" early, the positioning we're obtaining here will be used to do our frustum culling,
  1216. // occlusion culling, etc. There is however a technique that we can investigate in the future where after our entire
  1217. // Vulkan command buffer is build, but right before vkSubmitQueue is called, we call xrLocateViews one more time and
  1218. // update the view and projection matrix once more with a slightly more accurate predication and then submit the
  1219. // command queues.
  1220. // That is not possible yet but worth investigating in the future.
  1221. XrViewLocateInfo view_locate_info = {
  1222. XR_TYPE_VIEW_LOCATE_INFO, // type
  1223. nullptr, // next
  1224. view_configuration, // viewConfigurationType
  1225. frame_state.predictedDisplayTime, // displayTime
  1226. play_space // space
  1227. };
  1228. XrViewState view_state = {
  1229. XR_TYPE_VIEW_STATE, // type
  1230. nullptr, // next
  1231. 0 // viewStateFlags
  1232. };
  1233. uint32_t view_count_output;
  1234. result = xrLocateViews(session, &view_locate_info, &view_state, view_count, &view_count_output, views);
  1235. if (XR_FAILED(result)) {
  1236. print_line("OpenXR: Couldn't locate views [", get_error_string(result), "]");
  1237. return;
  1238. }
  1239. bool pose_valid = true;
  1240. for (uint64_t i = 0; i < view_count_output; i++) {
  1241. if ((view_state.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) == 0 ||
  1242. (view_state.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT) == 0) {
  1243. pose_valid = false;
  1244. }
  1245. }
  1246. if (view_pose_valid != pose_valid) {
  1247. view_pose_valid = pose_valid;
  1248. #ifdef DEBUG
  1249. if (!view_pose_valid) {
  1250. print_line("OpenXR View pose became invalid");
  1251. } else {
  1252. print_line("OpenXR View pose became valid");
  1253. }
  1254. #endif
  1255. }
  1256. // let's start our frame..
  1257. XrFrameBeginInfo frame_begin_info = {
  1258. XR_TYPE_FRAME_BEGIN_INFO, // type
  1259. nullptr // next
  1260. };
  1261. result = xrBeginFrame(session, &frame_begin_info);
  1262. if (XR_FAILED(result)) {
  1263. print_line("OpenXR: failed to being frame [", get_error_string(result), "]");
  1264. return;
  1265. }
  1266. }
  1267. bool OpenXRAPI::pre_draw_viewport(RID p_render_target) {
  1268. if (!can_render()) {
  1269. return false;
  1270. }
  1271. // TODO: at some point in time we may support multiple viewports in which case we need to handle that...
  1272. return true;
  1273. }
  1274. void OpenXRAPI::post_draw_viewport(RID p_render_target) {
  1275. if (!can_render()) {
  1276. return;
  1277. }
  1278. // TODO: at some point in time we may support multiple viewports in which case we need to handle that...
  1279. // TODO: if we can get PR 51179 to work properly we can change away from this approach and move this into get_external_texture or something
  1280. if (!image_acquired) {
  1281. if (!acquire_image(swapchain, image_index)) {
  1282. return;
  1283. }
  1284. image_acquired = true;
  1285. // print_line("OpenXR: acquired image " + itos(image_index) + ", copying...");
  1286. // Copy our buffer into our swap chain (remove once PR 51179 is done)
  1287. graphics_extension->copy_render_target_to_image(p_render_target, swapchain_graphics_data, image_index);
  1288. }
  1289. };
  1290. void OpenXRAPI::end_frame() {
  1291. XrResult result;
  1292. ERR_FAIL_COND(instance == XR_NULL_HANDLE);
  1293. if (!running) {
  1294. return;
  1295. }
  1296. if (frame_state.shouldRender && view_pose_valid && !image_acquired) {
  1297. print_line("OpenXR: No viewport was marked with use_xr, there is no rendered output!");
  1298. }
  1299. // must have:
  1300. // - shouldRender set to true
  1301. // - a valid view pose for projection_views[eye].pose to submit layer
  1302. // - an image to render
  1303. if (!frame_state.shouldRender || !view_pose_valid || !image_acquired) {
  1304. // submit 0 layers when we shouldn't render
  1305. XrFrameEndInfo frame_end_info = {
  1306. XR_TYPE_FRAME_END_INFO, // type
  1307. nullptr, // next
  1308. frame_state.predictedDisplayTime, // displayTime
  1309. XR_ENVIRONMENT_BLEND_MODE_OPAQUE, // environmentBlendMode
  1310. 0, // layerCount
  1311. nullptr // layers
  1312. };
  1313. result = xrEndFrame(session, &frame_end_info);
  1314. if (XR_FAILED(result)) {
  1315. print_line("OpenXR: failed to end frame! [", get_error_string(result), "]");
  1316. return;
  1317. }
  1318. // neither eye is rendered
  1319. return;
  1320. }
  1321. // release our swapchain image if we acquired it
  1322. if (image_acquired) {
  1323. image_acquired = false; // whether we succeed or not, consider this released.
  1324. release_image(swapchain);
  1325. }
  1326. for (uint32_t eye = 0; eye < view_count; eye++) {
  1327. projection_views[eye].fov = views[eye].fov;
  1328. projection_views[eye].pose = views[eye].pose;
  1329. }
  1330. Vector<const XrCompositionLayerBaseHeader *> layers_list;
  1331. // Add composition layers from providers
  1332. for (OpenXRCompositionLayerProvider *provider : composition_layer_providers) {
  1333. XrCompositionLayerBaseHeader *layer = provider->get_composition_layer();
  1334. if (layer) {
  1335. layers_list.push_back(layer);
  1336. }
  1337. }
  1338. XrCompositionLayerProjection projection_layer = {
  1339. XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type
  1340. nullptr, // next
  1341. layers_list.size() > 1 ? XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT : XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, // layerFlags
  1342. play_space, // space
  1343. view_count, // viewCount
  1344. projection_views, // views
  1345. };
  1346. layers_list.push_back((const XrCompositionLayerBaseHeader *)&projection_layer);
  1347. XrFrameEndInfo frame_end_info = {
  1348. XR_TYPE_FRAME_END_INFO, // type
  1349. nullptr, // next
  1350. frame_state.predictedDisplayTime, // displayTime
  1351. XR_ENVIRONMENT_BLEND_MODE_OPAQUE, // environmentBlendMode
  1352. static_cast<uint32_t>(layers_list.size()), // layerCount
  1353. layers_list.ptr() // layers
  1354. };
  1355. result = xrEndFrame(session, &frame_end_info);
  1356. if (XR_FAILED(result)) {
  1357. print_line("OpenXR: failed to end frame! [", get_error_string(result), "]");
  1358. return;
  1359. }
  1360. }
  1361. OpenXRAPI::OpenXRAPI() {
  1362. // OpenXRAPI is only constructed if OpenXR is enabled.
  1363. singleton = this;
  1364. if (Engine::get_singleton()->is_editor_hint()) {
  1365. // Enabled OpenXR in the editor? Adjust our settings for the editor
  1366. } else {
  1367. // Load settings from project settings
  1368. int ff = GLOBAL_GET("xr/openxr/form_factor");
  1369. switch (ff) {
  1370. case 0: {
  1371. form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
  1372. } break;
  1373. case 1: {
  1374. form_factor = XR_FORM_FACTOR_HANDHELD_DISPLAY;
  1375. } break;
  1376. default:
  1377. break;
  1378. }
  1379. int vc = GLOBAL_GET("xr/openxr/view_configuration");
  1380. switch (vc) {
  1381. case 0: {
  1382. view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO;
  1383. } break;
  1384. case 1: {
  1385. view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
  1386. } break;
  1387. /* we don't support quad and observer configurations (yet)
  1388. case 2: {
  1389. view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO;
  1390. } break;
  1391. case 3: {
  1392. view_configuration = XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT;
  1393. } break;
  1394. */
  1395. default:
  1396. break;
  1397. }
  1398. int rs = GLOBAL_GET("xr/openxr/reference_space");
  1399. switch (rs) {
  1400. case 0: {
  1401. reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
  1402. } break;
  1403. case 1: {
  1404. reference_space = XR_REFERENCE_SPACE_TYPE_STAGE;
  1405. } break;
  1406. default:
  1407. break;
  1408. }
  1409. }
  1410. // reset a few things that can't be done in our class definition
  1411. frame_state.predictedDisplayTime = 0;
  1412. frame_state.predictedDisplayPeriod = 0;
  1413. #ifdef ANDROID_ENABLED
  1414. // our android wrapper will initialize our android loader at this point
  1415. register_extension_wrapper(memnew(OpenXRAndroidExtension(this)));
  1416. #endif
  1417. // register our other extensions
  1418. register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension(this)));
  1419. }
  1420. OpenXRAPI::~OpenXRAPI() {
  1421. // cleanup our composition layer providers
  1422. for (OpenXRCompositionLayerProvider *provider : composition_layer_providers) {
  1423. memdelete(provider);
  1424. }
  1425. composition_layer_providers.clear();
  1426. // cleanup our extension wrappers
  1427. for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) {
  1428. memdelete(extension_wrapper);
  1429. }
  1430. registered_extension_wrappers.clear();
  1431. if (supported_extensions != nullptr) {
  1432. memfree(supported_extensions);
  1433. supported_extensions = nullptr;
  1434. }
  1435. if (layer_properties != nullptr) {
  1436. memfree(layer_properties);
  1437. layer_properties = nullptr;
  1438. }
  1439. #ifdef ANDROID_ENABLED
  1440. if (openxr_loader_library_handle) {
  1441. OS::get_singleton()->close_dynamic_library(openxr_loader_library_handle);
  1442. openxr_loader_library_handle = nullptr;
  1443. }
  1444. #endif
  1445. singleton = nullptr;
  1446. }
  1447. Transform3D OpenXRAPI::transform_from_pose(const XrPosef &p_pose) {
  1448. Quaternion q(p_pose.orientation.x, p_pose.orientation.y, p_pose.orientation.z, p_pose.orientation.w);
  1449. Basis basis(q);
  1450. Vector3 origin(p_pose.position.x, p_pose.position.y, p_pose.position.z);
  1451. return Transform3D(basis, origin);
  1452. }
  1453. template <typename T>
  1454. XRPose::TrackingConfidence _transform_from_location(const T &p_location, Transform3D &r_transform) {
  1455. Basis basis;
  1456. Vector3 origin;
  1457. XRPose::TrackingConfidence confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE;
  1458. const auto &pose = p_location.pose;
  1459. // Check orientation
  1460. if (p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
  1461. Quaternion q(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w);
  1462. r_transform.basis = Basis(q);
  1463. if (p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT) {
  1464. // Fully valid orientation, so either 3DOF or 6DOF tracking with high confidence so default to HIGH_TRACKING
  1465. confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH;
  1466. } else {
  1467. // Orientation is being tracked but we're using old/predicted data, so low tracking confidence
  1468. confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW;
  1469. }
  1470. } else {
  1471. r_transform.basis = Basis();
  1472. }
  1473. // Check location
  1474. if (p_location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
  1475. r_transform.origin = Vector3(pose.position.x, pose.position.y, pose.position.z);
  1476. if (!(p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT)) {
  1477. // Location is being tracked but we're using old/predicted data, so low tracking confidence
  1478. confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW;
  1479. } else if (confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) {
  1480. // Position tracking without orientation tracking?
  1481. confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH;
  1482. }
  1483. } else {
  1484. // No tracking or 3DOF I guess..
  1485. r_transform.origin = Vector3();
  1486. }
  1487. return confidence;
  1488. }
  1489. XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform) {
  1490. return _transform_from_location(p_location, r_transform);
  1491. }
  1492. XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform) {
  1493. return _transform_from_location(p_location, r_transform);
  1494. }
  1495. void OpenXRAPI::parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
  1496. if (p_velocity.velocityFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) {
  1497. XrVector3f linear_velocity = p_velocity.linearVelocity;
  1498. r_linear_velocity = Vector3(linear_velocity.x, linear_velocity.y, linear_velocity.z);
  1499. } else {
  1500. r_linear_velocity = Vector3();
  1501. }
  1502. if (p_velocity.velocityFlags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) {
  1503. XrVector3f angular_velocity = p_velocity.angularVelocity;
  1504. r_angular_velocity = Vector3(angular_velocity.x, angular_velocity.y, angular_velocity.z);
  1505. } else {
  1506. r_angular_velocity = Vector3();
  1507. }
  1508. }
  1509. RID OpenXRAPI::get_tracker_rid(XrPath p_path) {
  1510. List<RID> current;
  1511. tracker_owner.get_owned_list(&current);
  1512. for (int i = 0; i < current.size(); i++) {
  1513. Tracker *tracker = tracker_owner.get_or_null(current[i]);
  1514. if (tracker && tracker->toplevel_path == p_path) {
  1515. return current[i];
  1516. }
  1517. }
  1518. return RID();
  1519. }
  1520. RID OpenXRAPI::tracker_create(const String p_name) {
  1521. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID());
  1522. Tracker new_tracker;
  1523. new_tracker.name = p_name;
  1524. new_tracker.toplevel_path = XR_NULL_PATH;
  1525. new_tracker.active_profile_rid = RID();
  1526. XrResult result = xrStringToPath(instance, p_name.utf8().get_data(), &new_tracker.toplevel_path);
  1527. if (XR_FAILED(result)) {
  1528. print_line("OpenXR: failed to get path for ", p_name, "! [", get_error_string(result), "]");
  1529. return RID();
  1530. }
  1531. return tracker_owner.make_rid(new_tracker);
  1532. }
  1533. String OpenXRAPI::tracker_get_name(RID p_tracker) {
  1534. if (p_tracker.is_null()) {
  1535. return String("None");
  1536. }
  1537. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  1538. ERR_FAIL_NULL_V(tracker, String());
  1539. return tracker->name;
  1540. }
  1541. void OpenXRAPI::tracker_check_profile(RID p_tracker, XrSession p_session) {
  1542. if (p_session == XR_NULL_HANDLE) {
  1543. p_session = session;
  1544. }
  1545. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  1546. ERR_FAIL_NULL(tracker);
  1547. if (tracker->toplevel_path == XR_NULL_PATH) {
  1548. // no path, how was this even created?
  1549. return;
  1550. }
  1551. XrInteractionProfileState profile_state = {
  1552. XR_TYPE_INTERACTION_PROFILE_STATE, // type
  1553. nullptr, // next
  1554. XR_NULL_PATH // interactionProfile
  1555. };
  1556. XrResult result = xrGetCurrentInteractionProfile(p_session, tracker->toplevel_path, &profile_state);
  1557. if (XR_FAILED(result)) {
  1558. print_line("OpenXR: Failed to get interaction profile for", itos(tracker->toplevel_path), "[", get_error_string(result), "]");
  1559. return;
  1560. }
  1561. XrPath new_profile = profile_state.interactionProfile;
  1562. XrPath was_profile = get_interaction_profile_path(tracker->active_profile_rid);
  1563. if (was_profile != new_profile) {
  1564. tracker->active_profile_rid = get_interaction_profile_rid(new_profile);
  1565. if (xr_interface) {
  1566. xr_interface->tracker_profile_changed(p_tracker, tracker->active_profile_rid);
  1567. }
  1568. }
  1569. }
  1570. void OpenXRAPI::tracker_free(RID p_tracker) {
  1571. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  1572. ERR_FAIL_NULL(tracker);
  1573. // there is nothing to free here
  1574. tracker_owner.free(p_tracker);
  1575. }
  1576. RID OpenXRAPI::action_set_create(const String p_name, const String p_localized_name, const int p_priority) {
  1577. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID());
  1578. ActionSet action_set;
  1579. action_set.name = p_name;
  1580. action_set.is_attached = false;
  1581. // create our action set...
  1582. XrActionSetCreateInfo action_set_info = {
  1583. XR_TYPE_ACTION_SET_CREATE_INFO, // type
  1584. nullptr, // next
  1585. "", // actionSetName
  1586. "", // localizedActionSetName
  1587. uint32_t(p_priority) // priority
  1588. };
  1589. copy_string_to_char_buffer(p_name, action_set_info.actionSetName, XR_MAX_ACTION_SET_NAME_SIZE);
  1590. copy_string_to_char_buffer(p_localized_name, action_set_info.localizedActionSetName, XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE);
  1591. // print_line("Creating action set ", action_set_info.actionSetName, " - ", action_set_info.localizedActionSetName, " (", itos(action_set_info.priority), ")");
  1592. XrResult result = xrCreateActionSet(instance, &action_set_info, &action_set.handle);
  1593. if (XR_FAILED(result)) {
  1594. print_line("OpenXR: failed to create action set ", p_name, "! [", get_error_string(result), "]");
  1595. return RID();
  1596. }
  1597. return action_set_owner.make_rid(action_set);
  1598. }
  1599. String OpenXRAPI::action_set_get_name(RID p_action_set) {
  1600. if (p_action_set.is_null()) {
  1601. return String("None");
  1602. }
  1603. ActionSet *action_set = action_set_owner.get_or_null(p_action_set);
  1604. ERR_FAIL_NULL_V(action_set, String());
  1605. return action_set->name;
  1606. }
  1607. bool OpenXRAPI::action_set_attach(RID p_action_set) {
  1608. ActionSet *action_set = action_set_owner.get_or_null(p_action_set);
  1609. ERR_FAIL_NULL_V(action_set, false);
  1610. if (action_set->is_attached) {
  1611. // already attached
  1612. return true;
  1613. }
  1614. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  1615. // So according to the docs, once we attach our action set to our session it becomes read only..
  1616. // https://www.khronos.org/registry/OpenXR/specs/1.0/man/html/xrAttachSessionActionSets.html
  1617. XrSessionActionSetsAttachInfo attach_info = {
  1618. XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO, // type
  1619. nullptr, // next
  1620. 1, // countActionSets,
  1621. &action_set->handle // actionSets
  1622. };
  1623. XrResult result = xrAttachSessionActionSets(session, &attach_info);
  1624. if (XR_FAILED(result)) {
  1625. print_line("OpenXR: failed to attach action set! [", get_error_string(result), "]");
  1626. return false;
  1627. }
  1628. action_set->is_attached = true;
  1629. /* For debugging:
  1630. print_verbose("Attached set " + action_set->name);
  1631. List<RID> action_rids;
  1632. action_owner.get_owned_list(&action_rids);
  1633. for (int i = 0; i < action_rids.size(); i++) {
  1634. Action * action = action_owner.get_or_null(action_rids[i]);
  1635. if (action && action->action_set_rid == p_action_set) {
  1636. print_verbose(" - Action " + action->name + ": " + OpenXRUtil::get_action_type_name(action->action_type));
  1637. for (int j = 0; j < action->trackers.size(); j++) {
  1638. Tracker * tracker = tracker_owner.get_or_null(action->trackers[j].tracker_rid);
  1639. if (tracker) {
  1640. print_verbose(" - " + tracker->name);
  1641. }
  1642. }
  1643. }
  1644. }
  1645. */
  1646. return true;
  1647. }
  1648. void OpenXRAPI::action_set_free(RID p_action_set) {
  1649. ActionSet *action_set = action_set_owner.get_or_null(p_action_set);
  1650. ERR_FAIL_NULL(action_set);
  1651. if (action_set->handle != XR_NULL_HANDLE) {
  1652. xrDestroyActionSet(action_set->handle);
  1653. }
  1654. action_set_owner.free(p_action_set);
  1655. }
  1656. RID OpenXRAPI::get_action_rid(XrAction p_action) {
  1657. List<RID> current;
  1658. action_owner.get_owned_list(&current);
  1659. for (int i = 0; i < current.size(); i++) {
  1660. Action *action = action_owner.get_or_null(current[i]);
  1661. if (action && action->handle == p_action) {
  1662. return current[i];
  1663. }
  1664. }
  1665. return RID();
  1666. }
  1667. 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) {
  1668. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID());
  1669. Action action;
  1670. action.name = p_name;
  1671. ActionSet *action_set = action_set_owner.get_or_null(p_action_set);
  1672. ERR_FAIL_NULL_V(action_set, RID());
  1673. ERR_FAIL_COND_V(action_set->handle == XR_NULL_HANDLE, RID());
  1674. action.action_set_rid = p_action_set;
  1675. switch (p_action_type) {
  1676. case OpenXRAction::OPENXR_ACTION_BOOL:
  1677. action.action_type = XR_ACTION_TYPE_BOOLEAN_INPUT;
  1678. break;
  1679. case OpenXRAction::OPENXR_ACTION_FLOAT:
  1680. action.action_type = XR_ACTION_TYPE_FLOAT_INPUT;
  1681. break;
  1682. case OpenXRAction::OPENXR_ACTION_VECTOR2:
  1683. action.action_type = XR_ACTION_TYPE_VECTOR2F_INPUT;
  1684. break;
  1685. case OpenXRAction::OPENXR_ACTION_POSE:
  1686. action.action_type = XR_ACTION_TYPE_POSE_INPUT;
  1687. break;
  1688. case OpenXRAction::OPENXR_ACTION_HAPTIC:
  1689. action.action_type = XR_ACTION_TYPE_VIBRATION_OUTPUT;
  1690. break;
  1691. default:
  1692. ERR_FAIL_V(RID());
  1693. break;
  1694. }
  1695. Vector<XrPath> toplevel_paths;
  1696. for (int i = 0; i < p_trackers.size(); i++) {
  1697. Tracker *tracker = tracker_owner.get_or_null(p_trackers[i]);
  1698. if (tracker != nullptr && tracker->toplevel_path != XR_NULL_PATH) {
  1699. ActionTracker action_tracker = {
  1700. p_trackers[i], // tracker
  1701. XR_NULL_HANDLE, // space
  1702. false // was_location_valid
  1703. };
  1704. action.trackers.push_back(action_tracker);
  1705. toplevel_paths.push_back(tracker->toplevel_path);
  1706. }
  1707. }
  1708. XrActionCreateInfo action_info = {
  1709. XR_TYPE_ACTION_CREATE_INFO, // type
  1710. nullptr, // next
  1711. "", // actionName
  1712. action.action_type, // actionType
  1713. uint32_t(toplevel_paths.size()), // countSubactionPaths
  1714. toplevel_paths.ptr(), // subactionPaths
  1715. "" // localizedActionName
  1716. };
  1717. copy_string_to_char_buffer(p_name, action_info.actionName, XR_MAX_ACTION_NAME_SIZE);
  1718. copy_string_to_char_buffer(p_localized_name, action_info.localizedActionName, XR_MAX_LOCALIZED_ACTION_NAME_SIZE);
  1719. // print_line("Creating action ", action_info.actionName, action_info.localizedActionName, action_info.countSubactionPaths);
  1720. XrResult result = xrCreateAction(action_set->handle, &action_info, &action.handle);
  1721. if (XR_FAILED(result)) {
  1722. print_line("OpenXR: failed to create action ", p_name, "! [", get_error_string(result), "]");
  1723. return RID();
  1724. }
  1725. return action_owner.make_rid(action);
  1726. }
  1727. String OpenXRAPI::action_get_name(RID p_action) {
  1728. if (p_action.is_null()) {
  1729. return String("None");
  1730. }
  1731. Action *action = action_owner.get_or_null(p_action);
  1732. ERR_FAIL_NULL_V(action, String());
  1733. return action->name;
  1734. }
  1735. void OpenXRAPI::action_free(RID p_action) {
  1736. Action *action = action_owner.get_or_null(p_action);
  1737. ERR_FAIL_NULL(action);
  1738. if (action->handle != XR_NULL_HANDLE) {
  1739. xrDestroyAction(action->handle);
  1740. }
  1741. action_owner.free(p_action);
  1742. }
  1743. RID OpenXRAPI::get_interaction_profile_rid(XrPath p_path) {
  1744. List<RID> current;
  1745. interaction_profile_owner.get_owned_list(&current);
  1746. for (int i = 0; i < current.size(); i++) {
  1747. InteractionProfile *ip = interaction_profile_owner.get_or_null(current[i]);
  1748. if (ip && ip->path == p_path) {
  1749. return current[i];
  1750. }
  1751. }
  1752. return RID();
  1753. }
  1754. XrPath OpenXRAPI::get_interaction_profile_path(RID p_interaction_profile) {
  1755. if (p_interaction_profile.is_null()) {
  1756. return XR_NULL_PATH;
  1757. }
  1758. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  1759. ERR_FAIL_NULL_V(ip, XR_NULL_PATH);
  1760. return ip->path;
  1761. }
  1762. RID OpenXRAPI::interaction_profile_create(const String p_name) {
  1763. InteractionProfile new_interaction_profile;
  1764. XrResult result = xrStringToPath(instance, p_name.utf8().get_data(), &new_interaction_profile.path);
  1765. if (XR_FAILED(result)) {
  1766. print_line("OpenXR: failed to get path for ", p_name, "! [", get_error_string(result), "]");
  1767. return RID();
  1768. }
  1769. RID existing_ip = get_interaction_profile_rid(new_interaction_profile.path);
  1770. if (existing_ip.is_valid()) {
  1771. return existing_ip;
  1772. }
  1773. new_interaction_profile.name = p_name;
  1774. return interaction_profile_owner.make_rid(new_interaction_profile);
  1775. }
  1776. String OpenXRAPI::interaction_profile_get_name(RID p_interaction_profile) {
  1777. if (p_interaction_profile.is_null()) {
  1778. return String("None");
  1779. }
  1780. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  1781. ERR_FAIL_NULL_V(ip, String());
  1782. return ip->name;
  1783. }
  1784. void OpenXRAPI::interaction_profile_clear_bindings(RID p_interaction_profile) {
  1785. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  1786. ERR_FAIL_NULL(ip);
  1787. ip->bindings.clear();
  1788. }
  1789. bool OpenXRAPI::interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path) {
  1790. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  1791. ERR_FAIL_NULL_V(ip, false);
  1792. XrActionSuggestedBinding binding;
  1793. Action *action = action_owner.get_or_null(p_action);
  1794. ERR_FAIL_COND_V(action == nullptr || action->handle == XR_NULL_HANDLE, false);
  1795. binding.action = action->handle;
  1796. XrResult result = xrStringToPath(instance, p_path.utf8().get_data(), &binding.binding);
  1797. if (XR_FAILED(result)) {
  1798. print_line("OpenXR: failed to get path for ", p_path, "! [", get_error_string(result), "]");
  1799. return false;
  1800. }
  1801. ip->bindings.push_back(binding);
  1802. return true;
  1803. }
  1804. bool OpenXRAPI::interaction_profile_suggest_bindings(RID p_interaction_profile) {
  1805. ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
  1806. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  1807. ERR_FAIL_NULL_V(ip, false);
  1808. const XrInteractionProfileSuggestedBinding suggested_bindings = {
  1809. XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING, // type
  1810. nullptr, // next
  1811. ip->path, // interactionProfile
  1812. uint32_t(ip->bindings.size()), // countSuggestedBindings
  1813. ip->bindings.ptr() // suggestedBindings
  1814. };
  1815. XrResult result = xrSuggestInteractionProfileBindings(instance, &suggested_bindings);
  1816. if (result == XR_ERROR_PATH_UNSUPPORTED) {
  1817. // this is fine, not all runtimes support all devices.
  1818. print_verbose("OpenXR Interaction profile " + ip->name + " is not supported on this runtime");
  1819. } else if (XR_FAILED(result)) {
  1820. print_line("OpenXR: failed to suggest bindings for ", ip->name, "! [", get_error_string(result), "]");
  1821. // reporting is enough...
  1822. }
  1823. /* For debugging:
  1824. print_verbose("Suggested bindings for " + ip->name);
  1825. for (int i = 0; i < ip->bindings.size(); i++) {
  1826. uint32_t strlen;
  1827. char path[XR_MAX_PATH_LENGTH];
  1828. String action_name = action_get_name(get_action_rid(ip->bindings[i].action));
  1829. XrResult result = xrPathToString(instance, ip->bindings[i].binding, XR_MAX_PATH_LENGTH, &strlen, path);
  1830. if (XR_FAILED(result)) {
  1831. print_line("OpenXR: failed to retrieve bindings for ", action_name, "! [", get_error_string(result), "]");
  1832. }
  1833. print_verbose(" - " + action_name + " => " + String(path));
  1834. }
  1835. */
  1836. return true;
  1837. }
  1838. void OpenXRAPI::interaction_profile_free(RID p_interaction_profile) {
  1839. InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
  1840. ERR_FAIL_NULL(ip);
  1841. ip->bindings.clear();
  1842. interaction_profile_owner.free(p_interaction_profile);
  1843. }
  1844. bool OpenXRAPI::sync_action_sets(const Vector<RID> p_active_sets) {
  1845. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  1846. if (!running) {
  1847. return false;
  1848. }
  1849. Vector<XrActiveActionSet> active_sets;
  1850. for (int i = 0; i < p_active_sets.size(); i++) {
  1851. ActionSet *action_set = action_set_owner.get_or_null(p_active_sets[i]);
  1852. if (action_set && action_set->handle != XR_NULL_HANDLE) {
  1853. XrActiveActionSet aset;
  1854. aset.actionSet = action_set->handle;
  1855. aset.subactionPath = XR_NULL_PATH;
  1856. active_sets.push_back(aset);
  1857. }
  1858. }
  1859. ERR_FAIL_COND_V(active_sets.size() == 0, false);
  1860. XrActionsSyncInfo sync_info = {
  1861. XR_TYPE_ACTIONS_SYNC_INFO, // type
  1862. nullptr, // next
  1863. uint32_t(active_sets.size()), // countActiveActionSets
  1864. active_sets.ptr() // activeActionSets
  1865. };
  1866. XrResult result = xrSyncActions(session, &sync_info);
  1867. if (XR_FAILED(result)) {
  1868. print_line("OpenXR: failed to sync active action sets! [", get_error_string(result), "]");
  1869. return false;
  1870. }
  1871. return true;
  1872. }
  1873. bool OpenXRAPI::get_action_bool(RID p_action, RID p_tracker) {
  1874. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  1875. Action *action = action_owner.get_or_null(p_action);
  1876. ERR_FAIL_NULL_V(action, false);
  1877. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  1878. ERR_FAIL_NULL_V(tracker, false);
  1879. if (!running) {
  1880. return false;
  1881. }
  1882. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_BOOLEAN_INPUT, false);
  1883. XrActionStateGetInfo get_info = {
  1884. XR_TYPE_ACTION_STATE_GET_INFO, // type
  1885. nullptr, // next
  1886. action->handle, // action
  1887. tracker->toplevel_path // subactionPath
  1888. };
  1889. XrActionStateBoolean result_state;
  1890. result_state.type = XR_TYPE_ACTION_STATE_BOOLEAN,
  1891. result_state.next = nullptr;
  1892. XrResult result = xrGetActionStateBoolean(session, &get_info, &result_state);
  1893. if (XR_FAILED(result)) {
  1894. print_line("OpenXR: couldn't get action boolean! [", get_error_string(result), "]");
  1895. return false;
  1896. }
  1897. return result_state.isActive && result_state.currentState;
  1898. }
  1899. float OpenXRAPI::get_action_float(RID p_action, RID p_tracker) {
  1900. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, 0.0);
  1901. Action *action = action_owner.get_or_null(p_action);
  1902. ERR_FAIL_NULL_V(action, 0.0);
  1903. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  1904. ERR_FAIL_NULL_V(tracker, 0.0);
  1905. if (!running) {
  1906. return 0.0;
  1907. }
  1908. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_FLOAT_INPUT, 0.0);
  1909. XrActionStateGetInfo get_info = {
  1910. XR_TYPE_ACTION_STATE_GET_INFO, // type
  1911. nullptr, // next
  1912. action->handle, // action
  1913. tracker->toplevel_path // subactionPath
  1914. };
  1915. XrActionStateFloat result_state;
  1916. result_state.type = XR_TYPE_ACTION_STATE_FLOAT,
  1917. result_state.next = nullptr;
  1918. XrResult result = xrGetActionStateFloat(session, &get_info, &result_state);
  1919. if (XR_FAILED(result)) {
  1920. print_line("OpenXR: couldn't get action float! [", get_error_string(result), "]");
  1921. return 0.0;
  1922. }
  1923. return result_state.isActive ? result_state.currentState : 0.0;
  1924. }
  1925. Vector2 OpenXRAPI::get_action_vector2(RID p_action, RID p_tracker) {
  1926. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, Vector2());
  1927. Action *action = action_owner.get_or_null(p_action);
  1928. ERR_FAIL_NULL_V(action, Vector2());
  1929. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  1930. ERR_FAIL_NULL_V(tracker, Vector2());
  1931. if (!running) {
  1932. return Vector2();
  1933. }
  1934. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_VECTOR2F_INPUT, Vector2());
  1935. XrActionStateGetInfo get_info = {
  1936. XR_TYPE_ACTION_STATE_GET_INFO, // type
  1937. nullptr, // next
  1938. action->handle, // action
  1939. tracker->toplevel_path // subactionPath
  1940. };
  1941. XrActionStateVector2f result_state;
  1942. result_state.type = XR_TYPE_ACTION_STATE_VECTOR2F,
  1943. result_state.next = nullptr;
  1944. XrResult result = xrGetActionStateVector2f(session, &get_info, &result_state);
  1945. if (XR_FAILED(result)) {
  1946. print_line("OpenXR: couldn't get action vector2! [", get_error_string(result), "]");
  1947. return Vector2();
  1948. }
  1949. return result_state.isActive ? Vector2(result_state.currentState.x, result_state.currentState.y) : Vector2();
  1950. }
  1951. XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
  1952. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  1953. Action *action = action_owner.get_or_null(p_action);
  1954. ERR_FAIL_NULL_V(action, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  1955. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  1956. ERR_FAIL_NULL_V(tracker, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  1957. if (!running) {
  1958. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  1959. }
  1960. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_POSE_INPUT, XRPose::XR_TRACKING_CONFIDENCE_NONE);
  1961. // print_verbose("Checking " + action->name + " => " + tracker->name + " (" + itos(tracker->toplevel_path) + ")");
  1962. uint64_t index = 0xFFFFFFFF;
  1963. uint64_t size = uint64_t(action->trackers.size());
  1964. for (uint64_t i = 0; i < size && index == 0xFFFFFFFF; i++) {
  1965. if (action->trackers[i].tracker_rid == p_tracker) {
  1966. index = i;
  1967. }
  1968. }
  1969. if (index == 0xFFFFFFFF) {
  1970. // couldn't find it?
  1971. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  1972. }
  1973. XrTime display_time = get_next_frame_time();
  1974. if (display_time == 0) {
  1975. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  1976. }
  1977. if (action->trackers[index].space == XR_NULL_HANDLE) {
  1978. // if this is a pose we need to define spaces
  1979. XrActionSpaceCreateInfo action_space_info = {
  1980. XR_TYPE_ACTION_SPACE_CREATE_INFO, // type
  1981. nullptr, // next
  1982. action->handle, // action
  1983. tracker->toplevel_path, // subactionPath
  1984. {
  1985. { 0.0, 0.0, 0.0, 1.0 }, // orientation
  1986. { 0.0, 0.0, 0.0 } // position
  1987. } // poseInActionSpace
  1988. };
  1989. XrSpace space;
  1990. XrResult result = xrCreateActionSpace(session, &action_space_info, &space);
  1991. if (XR_FAILED(result)) {
  1992. print_line("OpenXR: couldn't create action space! [", get_error_string(result), "]");
  1993. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  1994. }
  1995. action->trackers.ptrw()[index].space = space;
  1996. }
  1997. XrSpaceVelocity velocity = {
  1998. XR_TYPE_SPACE_VELOCITY, // type
  1999. nullptr, // next
  2000. 0, // velocityFlags
  2001. { 0.0, 0.0, 0.0 }, // linearVelocity
  2002. { 0.0, 0.0, 0.0 } // angularVelocity
  2003. };
  2004. XrSpaceLocation location = {
  2005. XR_TYPE_SPACE_LOCATION, // type
  2006. &velocity, // next
  2007. 0, // locationFlags
  2008. {
  2009. { 0.0, 0.0, 0.0, 0.0 }, // orientation
  2010. { 0.0, 0.0, 0.0 } // position
  2011. } // pose
  2012. };
  2013. XrResult result = xrLocateSpace(action->trackers[index].space, play_space, display_time, &location);
  2014. if (XR_FAILED(result)) {
  2015. print_line("OpenXR: failed to locate space! [", get_error_string(result), "]");
  2016. return XRPose::XR_TRACKING_CONFIDENCE_NONE;
  2017. }
  2018. XRPose::TrackingConfidence confidence = transform_from_location(location, r_transform);
  2019. parse_velocities(velocity, r_linear_velocity, r_angular_velocity);
  2020. return confidence;
  2021. }
  2022. bool OpenXRAPI::trigger_haptic_pulse(RID p_action, RID p_tracker, float p_frequency, float p_amplitude, XrDuration p_duration_ns) {
  2023. ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
  2024. Action *action = action_owner.get_or_null(p_action);
  2025. ERR_FAIL_NULL_V(action, false);
  2026. Tracker *tracker = tracker_owner.get_or_null(p_tracker);
  2027. ERR_FAIL_NULL_V(tracker, false);
  2028. if (!running) {
  2029. return false;
  2030. }
  2031. ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_VIBRATION_OUTPUT, false);
  2032. XrHapticActionInfo action_info = {
  2033. XR_TYPE_HAPTIC_ACTION_INFO, // type
  2034. nullptr, // next
  2035. action->handle, // action
  2036. tracker->toplevel_path // subactionPath
  2037. };
  2038. XrHapticVibration vibration = {
  2039. XR_TYPE_HAPTIC_VIBRATION, // type
  2040. nullptr, // next
  2041. p_duration_ns, // duration
  2042. p_frequency, // frequency
  2043. p_amplitude, // amplitude
  2044. };
  2045. XrResult result = xrApplyHapticFeedback(session, &action_info, (const XrHapticBaseHeader *)&vibration);
  2046. if (XR_FAILED(result)) {
  2047. print_line("OpenXR: failed to apply haptic feedback! [", get_error_string(result), "]");
  2048. return false;
  2049. }
  2050. return true;
  2051. }