NRRenderer.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /****************************************************************************
  2. * Copyright 2019 Nreal Techonology Limited. All rights reserved.
  3. *
  4. * This file is part of NRSDK.
  5. *
  6. * https://www.nreal.ai/
  7. *
  8. *****************************************************************************/
  9. namespace NRKernal
  10. {
  11. using AOT;
  12. using System;
  13. using System.Collections;
  14. using System.Collections.Generic;
  15. using System.Diagnostics;
  16. using System.Runtime.InteropServices;
  17. using UnityEngine;
  18. public interface IFrameProcessor
  19. {
  20. UInt64 GetFrameHandle();
  21. UInt64 GetViewPortListHandle();
  22. void SubmitFrame(ulong frameHandle, ulong viewPortListHandle);
  23. void Update();
  24. void Initialize(NativeRenderring nativeRenderer);
  25. void Destroy();
  26. }
  27. /// <summary>
  28. /// NRNativeRender operate rendering-related things, provides the feature of optimized rendering
  29. /// and low latency. </summary>
  30. [ScriptOrder(NativeConstants.NRRENDER_ORDER)]
  31. public class NRRenderer : MonoBehaviour
  32. {
  33. /// <summary> Renders the event delegate described by eventID. </summary>
  34. /// <param name="eventID"> Identifier for the event.</param>
  35. private delegate void RenderEventDelegate(int eventID);
  36. /// <summary> Handle of the render thread. </summary>
  37. private static RenderEventDelegate RenderThreadHandle = new RenderEventDelegate(RunOnRenderThread);
  38. /// <summary> The render thread handle pointer. </summary>
  39. private static IntPtr RenderThreadHandlePtr = Marshal.GetFunctionPointerForDelegate(RenderThreadHandle);
  40. private const int SETRENDERTEXTUREEVENT = 0x0001;
  41. private const int STARTNATIVERENDEREVENT = 0x0002;
  42. private const int RESUMENATIVERENDEREVENT = 0x0003;
  43. private const int PAUSENATIVERENDEREVENT = 0x0004;
  44. // private const int STOPNATIVERENDEREVENT = 0x0005;
  45. private const int SUBMIT_EVENT = 0x0006;
  46. //When application resumed, frame data must be updated in Update before submited in RenderCoroutine.
  47. private bool frameReady = false;
  48. public enum Eyes
  49. {
  50. /// <summary> Left Display. </summary>
  51. Left = 0,
  52. /// <summary> Right Display. </summary>
  53. Right = 1,
  54. Count = 2
  55. }
  56. public Camera leftCamera;
  57. public Camera rightCamera;
  58. /// <summary> Gets or sets the native renderring. </summary>
  59. /// <value> The m native renderring. </value>
  60. private static NativeRenderring m_NativeRenderring;
  61. static NativeRenderring NativeRenderring
  62. {
  63. get
  64. {
  65. if (NRSessionManager.Instance.NativeAPI != null)
  66. {
  67. m_NativeRenderring = NRSessionManager.Instance.NativeAPI.NativeRenderring;
  68. }
  69. else if (m_NativeRenderring == null)
  70. {
  71. m_NativeRenderring = new NativeRenderring();
  72. }
  73. return m_NativeRenderring;
  74. }
  75. set
  76. {
  77. m_NativeRenderring = value;
  78. }
  79. }
  80. /// <summary> The scale factor. </summary>
  81. public static float ScaleFactor = 1f;
  82. private const float m_DefaultFocusDistance = 1.4f;
  83. private float m_FocusDistance = 1.4f;
  84. public float FocusDistance
  85. {
  86. get { return m_FocusDistance; }
  87. }
  88. private static int _TextureBufferSize = 4;
  89. /// <summary> Number of eye textures. </summary>
  90. private static int EyeTextureCount = _TextureBufferSize * (int)Eyes.Count;
  91. /// <summary> The eye textures. </summary>
  92. private RenderTexture[] eyeTextures;
  93. /// <summary> Dictionary of rights. </summary>
  94. private Dictionary<RenderTexture, IntPtr> m_RTDict = new Dictionary<RenderTexture, IntPtr>();
  95. /// <summary> Frame process. </summary>
  96. private IFrameProcessor m_FrameProcessor;
  97. /// <summary> Values that represent renderer states. </summary>
  98. public enum RendererState
  99. {
  100. UnInitialized,
  101. Initialized,
  102. Running,
  103. Paused,
  104. Destroyed
  105. }
  106. private bool m_IsTrackChanging = false;
  107. private RenderTexture m_HijackRenderTextureLeft;
  108. private RenderTexture m_HijackRenderTextureRight;
  109. /// <summary> The current state. </summary>
  110. private RendererState m_CurrentState = RendererState.UnInitialized;
  111. /// <summary> Gets the current state. </summary>
  112. /// <value> The current state. </value>
  113. public RendererState CurrentState
  114. {
  115. get
  116. {
  117. return m_CurrentState;
  118. }
  119. set
  120. {
  121. m_CurrentState = value;
  122. }
  123. }
  124. public NRTrackingModeChangedListener TrackingLostListener
  125. {
  126. get
  127. {
  128. return NRSessionManager.Instance.TrackingLostListener;
  129. }
  130. }
  131. #if !UNITY_EDITOR
  132. private int currentEyeTextureIdx = 0;
  133. private int nextEyeTextureIdx = 0;
  134. #endif
  135. /// <summary> Gets a value indicating whether this object is linear color space. </summary>
  136. /// <value> True if this object is linear color space, false if not. </value>
  137. public static bool isLinearColorSpace
  138. {
  139. get
  140. {
  141. return QualitySettings.activeColorSpace == ColorSpace.Linear;
  142. }
  143. }
  144. /// <summary> Initialize the render pipleline. </summary>
  145. /// <param name="leftcamera"> Left Eye.</param>
  146. /// <param name="rightcamera"> Right Eye.</param>
  147. ///
  148. /// ### <param name="poseprovider"> provide the pose of camera every frame.</param>
  149. public void Initialize(Camera leftcamera, Camera rightcamera)
  150. {
  151. NRDebugger.Info("[NRRender] Initialize");
  152. if (m_CurrentState != RendererState.UnInitialized)
  153. {
  154. return;
  155. }
  156. leftCamera = leftcamera;
  157. rightCamera = rightcamera;
  158. #if !UNITY_EDITOR
  159. leftCamera.depthTextureMode = DepthTextureMode.None;
  160. rightCamera.depthTextureMode = DepthTextureMode.None;
  161. leftCamera.rect = new Rect(0, 0, 1, 1);
  162. rightCamera.rect = new Rect(0, 0, 1, 1);
  163. leftCamera.enabled = false;
  164. rightCamera.enabled = false;
  165. m_CurrentState = RendererState.Initialized;
  166. StartCoroutine(StartUp());
  167. #endif
  168. if (TrackingLostListener != null)
  169. {
  170. TrackingLostListener.OnTrackStateChanged += OnTrackStateChanged;
  171. }
  172. }
  173. private void OnTrackStateChanged(bool trackChanging, RenderTexture leftRT, RenderTexture rightRT)
  174. {
  175. if (trackChanging)
  176. {
  177. m_IsTrackChanging = true;
  178. m_HijackRenderTextureLeft = leftRT;
  179. m_HijackRenderTextureRight = rightRT;
  180. }
  181. else
  182. {
  183. m_IsTrackChanging = false;
  184. m_HijackRenderTextureLeft = null;
  185. m_HijackRenderTextureRight = null;
  186. }
  187. }
  188. /// <summary> Prepares this object for use. </summary>
  189. /// <returns> An IEnumerator. </returns>
  190. private IEnumerator StartUp()
  191. {
  192. var virtualDisplay = GameObject.FindObjectOfType<NRVirtualDisplayer>();
  193. while (virtualDisplay == null || !virtualDisplay.Subsystem.running)
  194. {
  195. NRDebugger.Info("[NRRender] Wait virtual display ready...");
  196. yield return new WaitForEndOfFrame();
  197. if (virtualDisplay == null)
  198. {
  199. virtualDisplay = GameObject.FindObjectOfType<NRVirtualDisplayer>();
  200. }
  201. }
  202. yield return new WaitForEndOfFrame();
  203. yield return new WaitForEndOfFrame();
  204. yield return new WaitForEndOfFrame();
  205. NRDebugger.Info("[NRRender] StartUp");
  206. #if !UNITY_EDITOR
  207. NativeRenderring.Create();
  208. StartCoroutine(RenderCoroutine());
  209. #endif
  210. GL.IssuePluginEvent(RenderThreadHandlePtr, STARTNATIVERENDEREVENT);
  211. if (m_FrameProcessor == null)
  212. CreateRenderTextures();
  213. NRDebugger.Info("[NRRender] StartUp Finish");
  214. }
  215. /// <summary> Set frame processor. </summary>
  216. /// <param name="processor"> Frame processor.</param>
  217. public void SetFrameProcessor(IFrameProcessor processor)
  218. {
  219. NRDebugger.Info("[NRRender] SetFrameProcessor");
  220. m_FrameProcessor = processor;
  221. }
  222. /// <summary> Pause render. </summary>
  223. public void Pause()
  224. {
  225. NRDebugger.Info("[NRRender] Pause");
  226. if (m_CurrentState != RendererState.Running)
  227. {
  228. return;
  229. }
  230. frameReady = false;
  231. GL.IssuePluginEvent(RenderThreadHandlePtr, PAUSENATIVERENDEREVENT);
  232. }
  233. /// <summary> Resume render. </summary>
  234. public void Resume()
  235. {
  236. Invoke("DelayResume", 0.3f);
  237. }
  238. /// <summary> Delay resume. </summary>
  239. private void DelayResume()
  240. {
  241. NRDebugger.Info("[NRRender] Resume");
  242. if (m_CurrentState != RendererState.Paused)
  243. {
  244. return;
  245. }
  246. GL.IssuePluginEvent(RenderThreadHandlePtr, RESUMENATIVERENDEREVENT);
  247. }
  248. #if !UNITY_EDITOR
  249. void Update()
  250. {
  251. if (m_CurrentState == RendererState.Running)
  252. {
  253. // NRDebugger.Info("[NRRender] Update: frameCnt={0}", Time.frameCount);
  254. if (m_FrameProcessor == null)
  255. {
  256. leftCamera.targetTexture = eyeTextures[currentEyeTextureIdx];
  257. rightCamera.targetTexture = eyeTextures[currentEyeTextureIdx + 1];
  258. currentEyeTextureIdx = nextEyeTextureIdx;
  259. nextEyeTextureIdx = (nextEyeTextureIdx + 2) % EyeTextureCount;
  260. }
  261. else
  262. {
  263. m_FrameProcessor.Update();
  264. }
  265. leftCamera.enabled = true;
  266. rightCamera.enabled = true;
  267. frameReady = true;
  268. }
  269. else
  270. {
  271. frameReady = false;
  272. }
  273. }
  274. #endif
  275. /// <summary> Generates a render texture. </summary>
  276. /// <param name="width"> The width.</param>
  277. /// <param name="height"> The height.</param>
  278. /// <returns> The render texture. </returns>
  279. private RenderTexture GenRenderTexture(int width, int height)
  280. {
  281. return UnityExtendedUtility.CreateRenderTexture((int)(width * ScaleFactor), (int)(height * ScaleFactor), 24, RenderTextureFormat.Default);
  282. }
  283. /// <summary> Creates render textures. </summary>
  284. private void CreateRenderTextures()
  285. {
  286. var config = NRSessionManager.Instance.NRSessionBehaviour?.SessionConfig;
  287. if (config != null && config.UseMultiThread)
  288. {
  289. _TextureBufferSize = 5;
  290. }
  291. else
  292. {
  293. _TextureBufferSize = 4;
  294. }
  295. NRDebugger.Info("[NRRender] Texture buffer size:{0}", _TextureBufferSize);
  296. EyeTextureCount = _TextureBufferSize * (int)Eyes.Count;
  297. eyeTextures = new RenderTexture[EyeTextureCount];
  298. var resolution = NRDevice.Subsystem.GetDeviceResolution(NativeDevice.LEFT_DISPLAY);
  299. NRDebugger.Info("[CreateRenderTextures] Resolution :" + resolution.ToString());
  300. for (int i = 0; i < EyeTextureCount; i++)
  301. {
  302. eyeTextures[i] = GenRenderTexture(resolution.width, resolution.height);
  303. m_RTDict.Add(eyeTextures[i], eyeTextures[i].GetNativeTexturePtr());
  304. }
  305. }
  306. /// <summary> Renders the coroutine. </summary>
  307. /// <returns> An IEnumerator. </returns>
  308. private IEnumerator RenderCoroutine()
  309. {
  310. WaitForEndOfFrame delay = new WaitForEndOfFrame();
  311. yield return delay;
  312. while (true)
  313. {
  314. yield return delay;
  315. // NRDebugger.Info("[NRRender] RenderCoroutine: state={0}, isTrackingChanging={1}, frameProcessor={2}", m_CurrentState, m_IsTrackChanging, m_FrameProcessor != null);
  316. if (m_CurrentState != RendererState.Running || !frameReady)
  317. {
  318. continue;
  319. }
  320. NativeMat4f apiPose;
  321. Pose unityPose = NRFrame.HeadPose;
  322. ConversionUtility.UnityPoseToApiPose(unityPose, out apiPose);
  323. // NRDebugger.Info("[NRRender] unityPos={0}\napiPos={1}", unityPose.ToString("F6"), apiPose.ToString());
  324. FrameInfo info = new FrameInfo(IntPtr.Zero, IntPtr.Zero, apiPose, new Vector3(0, 0, -m_FocusDistance),
  325. Vector3.forward, NRFrame.CurrentPoseTimeStamp, m_FrameChangedType, NRTextureType.NR_TEXTURE_2D, 0);
  326. if (m_FrameProcessor == null)
  327. {
  328. if (m_IsTrackChanging)
  329. {
  330. info.leftTex = m_HijackRenderTextureLeft.GetNativeTexturePtr();
  331. info.rightTex = m_HijackRenderTextureRight.GetNativeTexturePtr();
  332. }
  333. else
  334. {
  335. IntPtr left_target, right_target;
  336. if (!m_RTDict.TryGetValue(leftCamera.targetTexture, out left_target)) continue;
  337. if (!m_RTDict.TryGetValue(rightCamera.targetTexture, out right_target)) continue;
  338. info.leftTex = left_target;
  339. info.rightTex = right_target;
  340. }
  341. UInt64 frame_handle = NativeRenderring.CreateFrameHandle();
  342. info.frameHandle = frame_handle;
  343. // NRDebugger.Info("[NRRender] RenderCoroutine: frameHandle={0}", frame_handle);
  344. NativeRenderring?.WriteFrameData(info, 0, true);
  345. GL.IssuePluginEvent(RenderThreadHandlePtr, SETRENDERTEXTUREEVENT);
  346. }
  347. else
  348. {
  349. info.frameHandle = m_FrameProcessor.GetFrameHandle();
  350. var viewportListHandle = m_FrameProcessor.GetViewPortListHandle();
  351. // NRDebugger.Info("[NRRender] RenderCoroutine FrameProcessor: frameCnt={0}, frameHandle={1}, viewportListHandle={2}", Time.frameCount, info.frameHandle, viewportListHandle);
  352. NativeRenderring?.WriteFrameData(info, viewportListHandle, false);
  353. GL.IssuePluginEvent(RenderThreadHandlePtr, SUBMIT_EVENT);
  354. }
  355. // reset focuse distance and frame changed type to default value every frame.
  356. // m_FocusDistance = m_DefaultFocusDistance;
  357. // m_FrameChangedType = NRFrameFlags.NR_FRAME_CHANGED_NONE;
  358. }
  359. }
  360. private NRFrameFlags m_FrameChangedType = NRFrameFlags.NR_FRAME_CHANGED_NONE;
  361. /// <summary> Sets the focus plane for render thread. </summary>
  362. /// <param name="distance"> The distance from plane to center camera.</param>
  363. public void SetFocusDistance(float distance)
  364. {
  365. m_FocusDistance = distance;
  366. m_FrameChangedType = NRFrameFlags.NR_FRAME_CHANGED_FOCUS_PLANE;
  367. }
  368. /// <summary> Executes the 'on render thread' operation. </summary>
  369. /// <param name="eventID"> Identifier for the event.</param>
  370. [MonoPInvokeCallback(typeof(RenderEventDelegate))]
  371. private static void RunOnRenderThread(int eventID)
  372. {
  373. if (eventID != SETRENDERTEXTUREEVENT && eventID != SUBMIT_EVENT)
  374. NRDebugger.Info("[NRRender] RunOnRenderThread : eventID={0}, frameCnt={1}", eventID, Time.frameCount);
  375. if (eventID == STARTNATIVERENDEREVENT)
  376. {
  377. NativeRenderring?.Start();
  378. var renderer = NRSessionManager.Instance.NRRenderer;
  379. renderer.CurrentState = RendererState.Running;
  380. if (renderer.m_FrameProcessor != null)
  381. renderer.m_FrameProcessor.Initialize(NativeRenderring);
  382. }
  383. else if (eventID == RESUMENATIVERENDEREVENT)
  384. {
  385. NativeRenderring?.Resume();
  386. NRSessionManager.Instance.NRRenderer.CurrentState = RendererState.Running;
  387. }
  388. else if (eventID == PAUSENATIVERENDEREVENT)
  389. {
  390. NRSessionManager.Instance.NRRenderer.CurrentState = RendererState.Paused;
  391. NativeRenderring?.Pause();
  392. }
  393. // else if (eventID == STOPNATIVERENDEREVENT)
  394. // {
  395. // NativeRenderring?.Destroy();
  396. // NativeRenderring = null;
  397. // NRDevice.Instance.Destroy();
  398. // }
  399. else if (eventID == SETRENDERTEXTUREEVENT)
  400. {
  401. NativeRenderring?.DoExtendedRenderring();
  402. }
  403. else if (eventID == SUBMIT_EVENT)
  404. {
  405. var renderer = NRSessionManager.Instance.NRRenderer;
  406. NativeRenderring?.DoSubmitFrame(renderer.m_FrameProcessor);
  407. }
  408. }
  409. public void Destroy()
  410. {
  411. if (m_CurrentState == RendererState.Destroyed)
  412. {
  413. return;
  414. }
  415. m_CurrentState = RendererState.Destroyed;
  416. //GL.IssuePluginEvent(RenderThreadHandlePtr, STOPNATIVERENDEREVENT);
  417. if (m_FrameProcessor != null)
  418. m_FrameProcessor.Destroy();
  419. NativeRenderring?.Destroy();
  420. NativeRenderring = null;
  421. }
  422. private void OnDestroy()
  423. {
  424. this.Destroy();
  425. }
  426. }
  427. }