OpenVR.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. #define SUPPORT_OPEN_VR ((WINDOWS_OLD && !DX9) || MAC || LINUX) // DX9 not supported
  4. #if SUPPORT_OPEN_VR
  5. #if LINUX
  6. #define COMPILER_GCC // needs to be defined for Linux otherwise "openvr.h" will complain about unsupported platform
  7. #endif
  8. #include "../../../ThirdPartyLibs/begin.h"
  9. #include "../../../ThirdPartyLibs/OpenVR/headers/openvr.h"
  10. #include "../../../ThirdPartyLibs/end.h"
  11. #endif
  12. /******************************************************************************/
  13. namespace EE{
  14. /******************************************************************************/
  15. static struct OpenVRApi : VirtualRealityApi
  16. {
  17. virtual Bool init()override;
  18. virtual void shut()override;
  19. virtual Bool active ()C override;
  20. virtual Matrix matrixCur ()C override;
  21. virtual void recenter () override;
  22. virtual void changedGuiDepth() override;
  23. virtual void changedGuiSize () override;
  24. virtual void update () override;
  25. virtual void draw () override;
  26. virtual void delImages()override;
  27. virtual Bool createGuiImage ()override;
  28. virtual Bool createRenderImage ()override;
  29. virtual ImageRC* getNewRender ()override;
  30. virtual ImageRC* getNewGui ()override;
  31. virtual ImageRC* getLastRender()override;
  32. virtual ImageRC* getLastGui ()override;
  33. OpenVRApi();
  34. void setOverlaySizeDepth();
  35. Bool connect();
  36. void disconnect();
  37. #if SUPPORT_OPEN_VR
  38. private:
  39. vr::IVRSystem *_vr;
  40. vr::IVRCompositor *_compositor;
  41. vr::IVROverlay *_overlay;
  42. vr::VROverlayHandle_t _overlay_id;
  43. Bool _overlay_visible, _connected;
  44. ImageRC _render, _gui;
  45. #endif
  46. }OpenVR;
  47. #if SUPPORT_OPEN_VR
  48. static void SetPose(Matrix &m, C vr::HmdMatrix34_t &pose)
  49. {
  50. m.x .set( pose.m[0][0], pose.m[1][0], -pose.m[2][0]);
  51. m.y .set( pose.m[0][1], pose.m[1][1], -pose.m[2][1]);
  52. m.z .set(-pose.m[0][2], -pose.m[1][2], pose.m[2][2]);
  53. m.pos.set( pose.m[0][3], pose.m[1][3], -pose.m[2][3]);
  54. }
  55. static void SetPose(vr::HmdMatrix34_t &pose, C Matrix &m)
  56. {
  57. pose.m[0][0]= m.x .x; pose.m[1][0]= m.x .y; pose.m[2][0]=-m.x .z;
  58. pose.m[0][1]= m.y .x; pose.m[1][1]= m.y .y; pose.m[2][1]=-m.y .z;
  59. pose.m[0][2]=-m.z .x; pose.m[1][2]=-m.z .y; pose.m[2][2]= m.z .z;
  60. pose.m[0][3]= m.pos.x; pose.m[1][3]= m.pos.y; pose.m[2][3]=-m.pos.z;
  61. }
  62. #endif
  63. /******************************************************************************/
  64. Bool VirtualReality::OpenVRDetected()C
  65. {
  66. #if SUPPORT_OPEN_VR
  67. return vr::VR_IsHmdPresent();
  68. #endif
  69. return false;
  70. }
  71. Bool VirtualReality::OpenVRInit() {return VR.init(OpenVR);}
  72. /******************************************************************************/
  73. OpenVRApi::OpenVRApi()
  74. {
  75. #if SUPPORT_OPEN_VR
  76. _vr =null;
  77. _compositor =null;
  78. _overlay =null;
  79. _overlay_id =vr::k_ulOverlayHandleInvalid;
  80. _overlay_visible=false;
  81. _connected =false;
  82. #endif
  83. }
  84. /******************************************************************************/
  85. #if SUPPORT_OPEN_VR
  86. void OpenVRApi::disconnect()
  87. {
  88. VR.delImages(); // !! need to call 'VR.delImages' and not 'T.delImages' !!
  89. if(_connected)
  90. {
  91. _connected=false;
  92. VR.disconnected(); // call 'disconnected' after clearing '_connected' so 'VR.active' is false (needed for some things including 'D.setSync')
  93. }
  94. }
  95. Bool OpenVRApi::connect()
  96. {
  97. disconnect();
  98. _connected=true;
  99. if(vr::IVRExtendedDisplay *d=vr::VRExtendedDisplay())
  100. {
  101. int32_t x=0, y=0; uint32_t w=0, h=0; d->GetWindowBounds(&x, &y, &w, &h);
  102. VR._res.set(w, h);
  103. }else VR._res.zero();
  104. VR._adapter_id=0; int32_t adapter_index=-1; _vr->GetDXGIOutputInfo(&adapter_index); if(adapter_index>=0) // if want a custom adapter
  105. {
  106. #if DX11
  107. SyncLocker lock(D._lock);
  108. IDXGIFactory1 *factory=null; CreateDXGIFactory1(__uuidof(IDXGIFactory1), (Ptr*)&factory); if(factory)
  109. {
  110. IDXGIAdapter *adapter=null; factory->EnumAdapters(adapter_index, &adapter); if(adapter)
  111. {
  112. DXGI_ADAPTER_DESC desc; if(OK(adapter->GetDesc(&desc)))
  113. {
  114. ASSERT(SIZE(desc.AdapterLuid)==SIZE(VR._adapter_id));
  115. Copy(&VR._adapter_id, &desc.AdapterLuid, SIZE(VR._adapter_id));
  116. }
  117. adapter->Release();
  118. }
  119. factory->Release();
  120. }
  121. #endif
  122. }
  123. VR._name[0] ='\0'; _vr->GetStringTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_ModelNumber_String, VR._name, Elms(VR._name));
  124. VR._refresh = _vr->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_DisplayFrequency_Float);
  125. VR._eye_dist= _vr->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_UserIpdMeters_Float);
  126. if(VR._eye_dist<=0) // if unknown/invalid, then calculate differently:
  127. {
  128. vr::HmdMatrix34_t left =_vr->GetEyeToHeadTransform(vr::Eye_Left );
  129. vr::HmdMatrix34_t right=_vr->GetEyeToHeadTransform(vr::Eye_Right);
  130. Matrix l, r; SetPose(l, left); SetPose(r, right);
  131. VR._eye_dist=Dist(l.pos, r.pos);
  132. }
  133. Flt l, r, t, b; _vr->GetProjectionRaw(vr::Eye_Left, &l, &r, &t, &b);
  134. VR.setFOVTan(Abs(l), Abs(r), Abs(t), Abs(b));
  135. return VR.connected(); // call 'connected' after having set '_connected' so 'VR.active' is true (needed for some things including 'D.setSync')
  136. }
  137. #endif
  138. Bool OpenVRApi::init()
  139. {
  140. #if SUPPORT_OPEN_VR
  141. if(!_vr)
  142. {
  143. vr::EVRInitError error; if(_vr=vr::VR_Init(&error, vr::VRApplication_Scene))
  144. {
  145. if(_compositor=vr::VRCompositor())
  146. {
  147. _compositor->SetTrackingSpace(vr::TrackingUniverseSeated); // this will have 2 effects: 1) 'ResetSeatedZeroPose' will affect Matrix returned by 'WaitGetPoses' (correct behavior, because without this call, calling recenter does not affect 'WaitGetPoses') 2) it will make "chaperone" bounds disappear (the blue circle at the bottom which specifies play area size)
  148. if(_overlay=vr::VROverlay())
  149. {
  150. _overlay->CreateOverlay("Esenthel", "Gui", &_overlay_id); if(_overlay_id!=vr::k_ulOverlayHandleInvalid)
  151. {
  152. _overlay->SetHighQualityOverlay(_overlay_id);
  153. _overlay->HideOverlay(_overlay_id); _overlay_visible=false;
  154. #if GL // for OpenGL need to flip vertically
  155. vr::VRTextureBounds_t rect; rect.uMin=0; rect.uMax=1; rect.vMin=1; rect.vMax=0;
  156. _overlay->SetOverlayTextureBounds(_overlay_id, &rect);
  157. #endif
  158. }
  159. }
  160. connect();
  161. }else
  162. {
  163. _vr=null;
  164. vr::VR_Shutdown();
  165. }
  166. }
  167. }
  168. return _vr!=null;
  169. #endif
  170. return false;
  171. }
  172. void OpenVRApi::shut()
  173. {
  174. #if SUPPORT_OPEN_VR
  175. if(_vr)
  176. {
  177. disconnect();
  178. if(_overlay)
  179. {
  180. if(_overlay_id!=vr::k_ulOverlayHandleInvalid)_overlay->DestroyOverlay(_overlay_id);
  181. _overlay=null;
  182. }
  183. _overlay_visible=false;
  184. _overlay_id =vr::k_ulOverlayHandleInvalid;
  185. _compositor =null;
  186. _vr =null;
  187. vr::VR_Shutdown();
  188. }
  189. #endif
  190. }
  191. /******************************************************************************/
  192. Bool OpenVRApi::active()C
  193. {
  194. #if SUPPORT_OPEN_VR
  195. return _connected;
  196. #endif
  197. return false;
  198. }
  199. Matrix OpenVRApi::matrixCur()C
  200. {
  201. #if SUPPORT_OPEN_VR
  202. if(_vr)
  203. {
  204. vr::TrackedDevicePose_t pose; _vr->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseSeated, 0, &pose, 1);
  205. if(pose.bDeviceIsConnected && pose.bPoseIsValid)
  206. {
  207. Matrix m; SetPose(m, pose.mDeviceToAbsoluteTracking); return m;
  208. }
  209. }
  210. #endif
  211. return VR._matrix; // return last known matrix
  212. }
  213. void OpenVRApi::recenter()
  214. {
  215. #if SUPPORT_OPEN_VR
  216. if(_vr)_vr->ResetSeatedZeroPose();
  217. #endif
  218. }
  219. void OpenVRApi::setOverlaySizeDepth()
  220. {
  221. #if SUPPORT_OPEN_VR
  222. if(_overlay && _overlay_id!=vr::k_ulOverlayHandleInvalid)
  223. {
  224. Matrix m; m.setPos(0, 0, VR.guiDepth());
  225. vr::HmdMatrix34_t pose; SetPose(pose, m);
  226. _overlay->SetOverlayTransformTrackedDeviceRelative(_overlay_id, vr::k_unTrackedDeviceIndex_Hmd, &pose);
  227. _overlay->SetOverlayWidthInMeters(_overlay_id, VR.guiSize()*VR.guiDepth()*_gui.aspect());
  228. }
  229. #endif
  230. }
  231. void OpenVRApi::changedGuiDepth() {setOverlaySizeDepth();}
  232. void OpenVRApi::changedGuiSize () {setOverlaySizeDepth();}
  233. void OpenVRApi::update()
  234. {
  235. #if SUPPORT_OPEN_VR
  236. if(_vr)
  237. {
  238. VR._has_render=false;
  239. vr::VREvent_t event; while(_vr->PollNextEvent(&event, SIZE(event))) {}
  240. vr::TrackedDevicePose_t pose;
  241. vr::EVRCompositorError error;
  242. {
  243. SyncLocker locker(D._lock); // without this lock, 'WaitGetPoses' will either crash or deadlock when simultaneously doing GPU operations on other threads
  244. error=_compositor->WaitGetPoses(&pose, 1, null, 0);
  245. }
  246. if(error==vr::VRCompositorError_None)
  247. {
  248. // TODO: support connecting/disconnecting !bDeviceIsConnected
  249. if(pose.bDeviceIsConnected && pose.bPoseIsValid)
  250. {
  251. GyroscopeValue.set(pose.vAngularVelocity.v[0], pose.vAngularVelocity.v[1], -pose.vAngularVelocity.v[2]);
  252. SetPose(VR._matrix, pose.mDeviceToAbsoluteTracking);
  253. }
  254. }
  255. /*for(vr::TrackedDeviceIndex_t i=0; i<vr::k_unMaxTrackedDeviceCount; i++)
  256. {
  257. vr::VRControllerState_t state; if(_vr->GetControllerState(i, &state))
  258. {
  259. }
  260. }*/
  261. }
  262. #endif
  263. }
  264. void OpenVRApi::draw()
  265. {
  266. #if SUPPORT_OPEN_VR
  267. if(active())
  268. {
  269. if(!VR._has_render)_render.clearFull(Vec4Zero, true); // if render was not set, then clear
  270. vr::Texture_t t;
  271. t.eType=GPU_API(vr::API_DirectX, vr::API_DirectX, vr::API_OpenGL);
  272. if(_overlay && _overlay_id!=vr::k_ulOverlayHandleInvalid)
  273. {
  274. if(_overlay_visible!=VR.draw_2d)
  275. {
  276. if(_overlay_visible=VR.draw_2d)_overlay->ShowOverlay(_overlay_id);
  277. else _overlay->HideOverlay(_overlay_id);
  278. }
  279. if(_overlay_visible) // this needs to be called per-frame
  280. {
  281. t.handle=(Ptr)_gui._txtr;
  282. t.eColorSpace=vr::ColorSpace_Gamma; // TODO: support gamma correct sRGB rendering
  283. _overlay->SetOverlayTexture(_overlay_id, &t);
  284. }
  285. }
  286. t.handle=(Ptr)_render._txtr;
  287. t.eColorSpace=vr::ColorSpace_Gamma; // TODO: support gamma correct sRGB rendering
  288. vr::VRTextureBounds_t rect;
  289. #if GL // for OpenGL need to flip vertically
  290. rect.vMin=1; rect.vMax=0;
  291. #else
  292. rect.vMin=0; rect.vMax=1;
  293. #endif
  294. rect.uMin=0.0f; rect.uMax=0.5f; _compositor->Submit(vr::Eye_Left , &t, &rect);
  295. rect.uMin=0.5f; rect.uMax=1.0f; _compositor->Submit(vr::Eye_Right, &t, &rect);
  296. _compositor->PostPresentHandoff(); // even though headers suggest this should be called after Present/flipping, best performance was observed when this was called here (tested in a simple project with high GPU usage, lots of post-process enabled, results were around 30fps when called here, 28 when called after flip, 25 without calling this at all)
  297. }
  298. #endif
  299. }
  300. void OpenVRApi::delImages()
  301. {
  302. #if SUPPORT_OPEN_VR
  303. if(_overlay && _overlay_id!=vr::k_ulOverlayHandleInvalid)_overlay->ClearOverlayTexture(_overlay_id);
  304. _render.del();
  305. _gui .del();
  306. #endif
  307. }
  308. Bool OpenVRApi::createGuiImage()
  309. {
  310. #if SUPPORT_OPEN_VR
  311. if(_gui.createTry(VR.guiRes().x, VR.guiRes().y, 1, IMAGE_R8G8B8A8, IMAGE_RT, 1))
  312. {
  313. if(_overlay && _overlay_id!=vr::k_ulOverlayHandleInvalid)
  314. {
  315. vr::Texture_t t;
  316. t.handle=(Ptr)_gui._txtr;
  317. t.eType=GPU_API(vr::API_DirectX, vr::API_DirectX, vr::API_OpenGL);
  318. t.eColorSpace=vr::ColorSpace_Gamma; // TODO: support gamma correct sRGB rendering
  319. _overlay->SetOverlayTexture(_overlay_id, &t);
  320. setOverlaySizeDepth();
  321. }
  322. return true;
  323. }
  324. #endif
  325. return false;
  326. }
  327. Bool OpenVRApi::createRenderImage()
  328. {
  329. #if SUPPORT_OPEN_VR
  330. if(_vr)
  331. {
  332. uint32_t w=0, h=0; _vr->GetRecommendedRenderTargetSize(&w, &h);
  333. Clamp(w*=2, 2, D.maxTexSize()); // *2 also makes sure that both eyes have the same width
  334. Clamp(h , 1, D.maxTexSize());
  335. return _render.createTry(w, h, 1, IMAGE_R8G8B8A8, IMAGE_RT, 1);
  336. }
  337. #endif
  338. return false;
  339. }
  340. ImageRC* OpenVRApi::getNewRender()
  341. {
  342. #if SUPPORT_OPEN_VR
  343. if(_render.is())return &_render;
  344. #endif
  345. return null;
  346. }
  347. ImageRC* OpenVRApi::getNewGui()
  348. {
  349. #if SUPPORT_OPEN_VR
  350. if(_gui.is())return &_gui;
  351. #endif
  352. return null;
  353. }
  354. ImageRC* OpenVRApi::getLastRender()
  355. {
  356. #if SUPPORT_OPEN_VR
  357. return &_render;
  358. #endif
  359. return null;
  360. }
  361. ImageRC* OpenVRApi::getLastGui()
  362. {
  363. #if SUPPORT_OPEN_VR
  364. return &_gui;
  365. #endif
  366. return null;
  367. }
  368. /******************************************************************************/
  369. }
  370. /******************************************************************************/