Няма описание
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine.Rendering;
  4. #if ENABLE_VR && ENABLE_XR_MODULE
  5. using UnityEngine.XR;
  6. #endif
  7. namespace UnityEngine.Experimental.Rendering
  8. {
  9. /// <summary>
  10. /// Used by render pipelines to control the active XR shader variant.
  11. /// </summary>
  12. public static class SinglepassKeywords
  13. {
  14. /// <summary> XR shader keyword used by multiview rendering </summary>
  15. public static GlobalKeyword STEREO_MULTIVIEW_ON;
  16. /// <summary> XR shader keywordused by single pass instanced rendering </summary>
  17. public static GlobalKeyword STEREO_INSTANCING_ON;
  18. }
  19. /// <summary>
  20. /// Used by render pipelines to communicate with XR SDK.
  21. /// </summary>
  22. public static class XRSystem
  23. {
  24. // Keep track of only one XR layout
  25. static XRLayoutStack s_Layout = new ();
  26. // Delegate allocations of XRPass to the render pipeline
  27. static Func<XRPassCreateInfo, XRPass> s_PassAllocator = null;
  28. #if ENABLE_VR && ENABLE_XR_MODULE
  29. static List<XRDisplaySubsystem> s_DisplayList = new List<XRDisplaySubsystem>();
  30. static XRDisplaySubsystem s_Display;
  31. /// <summary>
  32. /// Returns the active XR display.
  33. /// </summary>
  34. static public XRDisplaySubsystem GetActiveDisplay()
  35. {
  36. return s_Display;
  37. }
  38. #endif
  39. // MSAA level (number of samples per pixel) shared by all XR displays
  40. static MSAASamples s_MSAASamples = MSAASamples.None;
  41. #if ENABLE_VR && ENABLE_XR_MODULE
  42. // Occlusion Mesh scaling factor
  43. static float s_OcclusionMeshScaling = 1.0f;
  44. #endif
  45. // Internal resources used by XR rendering
  46. static Material s_OcclusionMeshMaterial;
  47. static Material s_MirrorViewMaterial;
  48. // Ability to override the default XR layout
  49. static Action<XRLayout, Camera> s_LayoutOverride = null;
  50. /// <summary>
  51. /// Returns true if a XR device is connected and running.
  52. /// </summary>
  53. static public bool displayActive
  54. {
  55. #if ENABLE_VR && ENABLE_XR_MODULE
  56. get => (s_Display != null) ? s_Display.running : false;
  57. #else
  58. get => false;
  59. #endif
  60. }
  61. /// <summary>
  62. /// Returns if the XR display is running in HDR mode.
  63. /// </summary>
  64. static public bool isHDRDisplayOutputActive
  65. {
  66. #if ENABLE_VR && ENABLE_XR_MODULE
  67. get => s_Display?.hdrOutputSettings?.active ?? false;
  68. #else
  69. get => false;
  70. #endif
  71. }
  72. /// <summary>
  73. /// Valid empty pass when a camera is not using XR.
  74. /// </summary>
  75. public static readonly XRPass emptyPass = new XRPass();
  76. /// <summary>
  77. /// If true, the system will try to create a layout compatible with single-pass rendering.
  78. /// </summary>
  79. static public bool singlePassAllowed { get; set; } = true;
  80. /// <summary>
  81. /// Cached value of SystemInfo.foveatedRenderingCaps.
  82. /// </summary>
  83. static public FoveatedRenderingCaps foveatedRenderingCaps { get; set; }
  84. /// <summary>
  85. /// If true, the system will log some information about the layout to the console.
  86. /// </summary>
  87. static public bool dumpDebugInfo { get; set; } = false;
  88. /// <summary>
  89. /// Use this method to assign the shaders that will be used to render occlusion mesh for each XRPass and the final mirror view.
  90. /// </summary>
  91. /// <param name="passAllocator"> Delegate funcion used to allocate XRPasses. </param>
  92. /// <param name="occlusionMeshPS"> Fragement shader used for rendering occlusion mesh. </param>
  93. /// <param name="mirrorViewPS"> Fragement shader used for rendering mirror view. </param>
  94. public static void Initialize(Func<XRPassCreateInfo, XRPass> passAllocator, Shader occlusionMeshPS, Shader mirrorViewPS)
  95. {
  96. if (passAllocator == null)
  97. throw new ArgumentNullException("passCreator");
  98. s_PassAllocator = passAllocator;
  99. RefreshDeviceInfo();
  100. foveatedRenderingCaps = SystemInfo.foveatedRenderingCaps;
  101. if (occlusionMeshPS != null && s_OcclusionMeshMaterial == null)
  102. s_OcclusionMeshMaterial = CoreUtils.CreateEngineMaterial(occlusionMeshPS);
  103. if (mirrorViewPS != null && s_MirrorViewMaterial == null)
  104. s_MirrorViewMaterial = CoreUtils.CreateEngineMaterial(mirrorViewPS);
  105. if (XRGraphicsAutomatedTests.enabled)
  106. SetLayoutOverride(XRGraphicsAutomatedTests.OverrideLayout);
  107. SinglepassKeywords.STEREO_MULTIVIEW_ON = GlobalKeyword.Create("STEREO_MULTIVIEW_ON");
  108. SinglepassKeywords.STEREO_INSTANCING_ON = GlobalKeyword.Create("STEREO_INSTANCING_ON");
  109. }
  110. /// <summary>
  111. /// Used by the render pipeline to communicate to the XR device how many samples are used by MSAA.
  112. /// </summary>
  113. /// <param name="msaaSamples"> The active msaa samples the XRDisplay to set to. The eye texture surfaces are reallocated when necessary to work with the active msaa samples. </param>
  114. public static void SetDisplayMSAASamples(MSAASamples msaaSamples)
  115. {
  116. if (s_MSAASamples == msaaSamples)
  117. return;
  118. s_MSAASamples = msaaSamples;
  119. #if ENABLE_VR && ENABLE_XR_MODULE
  120. SubsystemManager.GetSubsystems(s_DisplayList);
  121. foreach (var display in s_DisplayList)
  122. display.SetMSAALevel((int)s_MSAASamples);
  123. #endif
  124. }
  125. /// <summary>
  126. /// Returns the number of samples (MSAA) currently configured on the XR device.
  127. /// </summary>
  128. /// <returns> Returns current active msaa samples. </returns>
  129. public static MSAASamples GetDisplayMSAASamples()
  130. {
  131. return s_MSAASamples;
  132. }
  133. /// <summary>
  134. /// Used by the render pipeline to scale all occlusion meshes used by all XRPasses.
  135. /// </summary>
  136. /// <param name="occlusionMeshScale">A value of 1.0f represents 100% of the original mesh size. A value less or equal to 0.0f disables occlusion mesh draw. </param>
  137. internal static void SetOcclusionMeshScale(float occlusionMeshScale)
  138. {
  139. #if ENABLE_VR && ENABLE_XR_MODULE
  140. s_OcclusionMeshScaling = occlusionMeshScale;
  141. #endif
  142. }
  143. /// <summary>
  144. /// Returned value used by the render pipeline to scale all occlusion meshes used by all XRPasses.
  145. /// </summary>
  146. internal static float GetOcclusionMeshScale()
  147. {
  148. #if ENABLE_VR && ENABLE_XR_MODULE
  149. return s_OcclusionMeshScaling;
  150. #else
  151. return 1.0f;
  152. #endif
  153. }
  154. /// <summary>
  155. /// Used to communicate to the XR device how to render the XR MirrorView. Note: not all blit modes are supported by all providers. Blitmode set here serves as preference purpose.
  156. /// </summary>
  157. /// <param name="mirrorBlitMode"> Mirror view mode to be set as preferred. See `XRMirrorViewBlitMode` for the builtin blit modes. </param>
  158. internal static void SetMirrorViewMode(int mirrorBlitMode)
  159. {
  160. #if ENABLE_VR && ENABLE_XR_MODULE
  161. if (s_Display == null)
  162. return;
  163. s_Display.SetPreferredMirrorBlitMode(mirrorBlitMode);
  164. #endif
  165. }
  166. /// <summary>
  167. /// Get current blit modes preferred by XRDisplay
  168. /// </summary>
  169. internal static int GetMirrorViewMode()
  170. {
  171. #if ENABLE_VR && ENABLE_XR_MODULE
  172. if (s_Display == null)
  173. return XRMirrorViewBlitMode.None;
  174. return s_Display.GetPreferredMirrorBlitMode();
  175. #else
  176. return 0;
  177. #endif
  178. }
  179. /// <summary>
  180. /// Used by the render pipeline to scale the render target on the XR device.
  181. /// </summary>
  182. /// <param name="renderScale">A value of 1.0f represents 100% of the original resolution.</param>
  183. public static void SetRenderScale(float renderScale)
  184. {
  185. #if ENABLE_VR && ENABLE_XR_MODULE
  186. SubsystemManager.GetSubsystems(s_DisplayList);
  187. foreach (var display in s_DisplayList)
  188. display.scaleOfAllRenderTargets = renderScale;
  189. #endif
  190. }
  191. /// <summary>
  192. /// Used by the render pipeline to retrieve the renderViewportScale value from the XR display.
  193. /// One use case for retriving this value is that render pipeline can properly sync some SRP owned textures to scale accordingly
  194. /// </summary>
  195. /// <returns> Returns current scaleOfAllViewports value from the XRDisplaySubsystem. </returns>
  196. public static float GetRenderViewportScale()
  197. {
  198. #if ENABLE_VR && ENABLE_XR_MODULE
  199. return s_Display.scaleOfAllViewports;
  200. #else
  201. return 1.0f;
  202. #endif
  203. }
  204. /// <summary>
  205. /// Used by the render pipeline to initiate a new rendering frame through a XR layout.
  206. /// </summary>
  207. /// <returns> Returns a new default layout. </returns>
  208. public static XRLayout NewLayout()
  209. {
  210. RefreshDeviceInfo();
  211. return s_Layout.New();
  212. }
  213. /// <summary>
  214. /// Used by the render pipeline to complete the XR layout at the end of the frame.
  215. /// </summary>
  216. public static void EndLayout()
  217. {
  218. if (dumpDebugInfo)
  219. s_Layout.top.LogDebugInfo();
  220. s_Layout.Release();
  221. }
  222. /// <summary>
  223. /// Used by the render pipeline to render the mirror view to the gameview, as configured by the XR device.
  224. /// </summary>
  225. /// <param name="cmd"> CommandBuffer on which to perform the mirror view draw. </param>
  226. /// <param name="camera"> Camera that has XR device connected to. The connected XR device determines how to perform the mirror view draw. </param>
  227. public static void RenderMirrorView(CommandBuffer cmd, Camera camera)
  228. {
  229. #if ENABLE_VR && ENABLE_XR_MODULE
  230. XRMirrorView.RenderMirrorView(cmd, camera, s_MirrorViewMaterial, s_Display);
  231. #endif
  232. }
  233. /// <summary>
  234. /// Free up resources used by the system.
  235. /// </summary>
  236. public static void Dispose()
  237. {
  238. if (s_OcclusionMeshMaterial != null)
  239. {
  240. CoreUtils.Destroy(s_OcclusionMeshMaterial);
  241. s_OcclusionMeshMaterial = null;
  242. }
  243. if (s_MirrorViewMaterial != null)
  244. {
  245. CoreUtils.Destroy(s_MirrorViewMaterial);
  246. s_MirrorViewMaterial = null;
  247. }
  248. }
  249. // Used by the render pipeline to communicate to the XR device the range of the depth buffer.
  250. internal static void SetDisplayZRange(float zNear, float zFar)
  251. {
  252. #if ENABLE_VR && ENABLE_XR_MODULE
  253. if (s_Display != null)
  254. {
  255. s_Display.zNear = zNear;
  256. s_Display.zFar = zFar;
  257. }
  258. #endif
  259. }
  260. // XRTODO : expose as public API
  261. static void SetLayoutOverride(Action<XRLayout, Camera> action)
  262. {
  263. s_LayoutOverride = action;
  264. }
  265. // Disable legacy VR system before rendering first frame
  266. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
  267. static void XRSystemInit()
  268. {
  269. if (GraphicsSettings.currentRenderPipeline != null)
  270. {
  271. RefreshDeviceInfo();
  272. }
  273. }
  274. static void RefreshDeviceInfo()
  275. {
  276. #if ENABLE_VR && ENABLE_XR_MODULE
  277. SubsystemManager.GetSubsystems(s_DisplayList);
  278. if (s_DisplayList.Count > 0)
  279. {
  280. if (s_DisplayList.Count > 1)
  281. throw new NotImplementedException("Only one XR display is supported!");
  282. s_Display = s_DisplayList[0];
  283. s_Display.disableLegacyRenderer = true;
  284. s_Display.sRGB = QualitySettings.activeColorSpace == ColorSpace.Linear;
  285. // XRTODO : discuss this code and UI implications
  286. s_Display.textureLayout = XRDisplaySubsystem.TextureLayout.Texture2DArray;
  287. // XRTODO : replace by API from XR SDK, assume we have 2 views max for now
  288. TextureXR.maxViews = Math.Max(TextureXR.slices, 2);
  289. }
  290. else
  291. {
  292. s_Display = null;
  293. }
  294. #endif
  295. }
  296. // Setup the layout to use multi-pass or single-pass based on the runtime caps
  297. internal static void CreateDefaultLayout(Camera camera, XRLayout layout)
  298. {
  299. #if ENABLE_VR && ENABLE_XR_MODULE
  300. if (s_Display == null)
  301. throw new NullReferenceException(nameof(s_Display));
  302. void AddViewToPass(XRPass xrPass, XRDisplaySubsystem.XRRenderPass renderPass, int renderParamIndex)
  303. {
  304. renderPass.GetRenderParameter(camera, renderParamIndex, out var renderParam);
  305. xrPass.AddView(BuildView(renderPass, renderParam));
  306. }
  307. for (int renderPassIndex = 0; renderPassIndex < s_Display.GetRenderPassCount(); ++renderPassIndex)
  308. {
  309. s_Display.GetRenderPass(renderPassIndex, out var renderPass);
  310. s_Display.GetCullingParameters(camera, renderPass.cullingPassIndex, out var cullingParams);
  311. int renderParameterCount = renderPass.GetRenderParameterCount();
  312. if (CanUseSinglePass(camera, renderPass))
  313. {
  314. var createInfo = BuildPass(renderPass, cullingParams, layout);
  315. var xrPass = s_PassAllocator(createInfo);
  316. for (int renderParamIndex = 0; renderParamIndex < renderParameterCount; ++renderParamIndex)
  317. {
  318. AddViewToPass(xrPass, renderPass, renderParamIndex);
  319. }
  320. layout.AddPass(camera, xrPass);
  321. }
  322. else
  323. {
  324. for (int renderParamIndex = 0; renderParamIndex < renderParameterCount; ++renderParamIndex)
  325. {
  326. var createInfo = BuildPass(renderPass, cullingParams, layout);
  327. var xrPass = s_PassAllocator(createInfo);
  328. AddViewToPass(xrPass, renderPass, renderParamIndex);
  329. layout.AddPass(camera, xrPass);
  330. }
  331. }
  332. }
  333. s_LayoutOverride?.Invoke(layout, camera);
  334. #endif
  335. }
  336. // Update the parameters of one pass with a different camera
  337. internal static void ReconfigurePass(XRPass xrPass, Camera camera)
  338. {
  339. #if ENABLE_VR && ENABLE_XR_MODULE
  340. if (xrPass.enabled && s_Display != null)
  341. {
  342. s_Display.GetRenderPass(xrPass.multipassId, out var renderPass);
  343. Debug.Assert(xrPass.singlePassEnabled || renderPass.GetRenderParameterCount() == 1);
  344. s_Display.GetCullingParameters(camera, renderPass.cullingPassIndex, out var cullingParams);
  345. xrPass.AssignCullingParams(renderPass.cullingPassIndex, cullingParams);
  346. for (int renderParamIndex = 0; renderParamIndex < renderPass.GetRenderParameterCount(); ++renderParamIndex)
  347. {
  348. renderPass.GetRenderParameter(camera, renderParamIndex, out var renderParam);
  349. xrPass.AssignView(renderParamIndex, BuildView(renderPass, renderParam));
  350. }
  351. s_LayoutOverride?.Invoke(s_Layout.top, camera);
  352. }
  353. #endif
  354. }
  355. #if ENABLE_VR && ENABLE_XR_MODULE
  356. static bool CanUseSinglePass(Camera camera, XRDisplaySubsystem.XRRenderPass renderPass)
  357. {
  358. if (!singlePassAllowed)
  359. return false;
  360. if (renderPass.renderTargetDesc.dimension != TextureDimension.Tex2DArray)
  361. return false;
  362. if (renderPass.GetRenderParameterCount() != 2 || renderPass.renderTargetDesc.volumeDepth != 2)
  363. return false;
  364. renderPass.GetRenderParameter(camera, 0, out var renderParam0);
  365. renderPass.GetRenderParameter(camera, 1, out var renderParam1);
  366. if (renderParam0.textureArraySlice != 0 || renderParam1.textureArraySlice != 1)
  367. return false;
  368. if (renderParam0.viewport != renderParam1.viewport)
  369. return false;
  370. return true;
  371. }
  372. static XRView BuildView(XRDisplaySubsystem.XRRenderPass renderPass, XRDisplaySubsystem.XRRenderParameter renderParameter)
  373. {
  374. // Convert viewport from normalized to screen space
  375. Rect viewport = renderParameter.viewport;
  376. viewport.x *= renderPass.renderTargetDesc.width;
  377. viewport.width *= renderPass.renderTargetDesc.width;
  378. viewport.y *= renderPass.renderTargetDesc.height;
  379. viewport.height *= renderPass.renderTargetDesc.height;
  380. // XRTODO : remove this line and use XRSettings.useOcclusionMesh instead when it's fixed
  381. Mesh occlusionMesh = XRGraphicsAutomatedTests.running ? null : renderParameter.occlusionMesh;
  382. return new XRView(renderParameter.projection, renderParameter.view, renderParameter.previousView, renderParameter.isPreviousViewValid, viewport, occlusionMesh, renderParameter.textureArraySlice);
  383. }
  384. private static RenderTextureDescriptor XrRenderTextureDescToUnityRenderTextureDesc(RenderTextureDescriptor xrDesc)
  385. {
  386. // We can't use descriptor directly because y-flip is forced
  387. // XRTODO : fix root problem
  388. RenderTextureDescriptor rtDesc = new RenderTextureDescriptor(xrDesc.width, xrDesc.height, xrDesc.colorFormat, xrDesc.depthBufferBits, xrDesc.mipCount);
  389. rtDesc.dimension = xrDesc.dimension;
  390. rtDesc.volumeDepth = xrDesc.volumeDepth;
  391. rtDesc.vrUsage = xrDesc.vrUsage;
  392. rtDesc.sRGB = xrDesc.sRGB;
  393. return rtDesc;
  394. }
  395. static XRPassCreateInfo BuildPass(XRDisplaySubsystem.XRRenderPass xrRenderPass, ScriptableCullingParameters cullingParameters, XRLayout layout)
  396. {
  397. XRPassCreateInfo passInfo = new XRPassCreateInfo
  398. {
  399. renderTarget = xrRenderPass.renderTarget,
  400. renderTargetDesc = XrRenderTextureDescToUnityRenderTextureDesc(xrRenderPass.renderTargetDesc),
  401. hasMotionVectorPass = xrRenderPass.hasMotionVectorPass,
  402. motionVectorRenderTarget = xrRenderPass.motionVectorRenderTarget,
  403. motionVectorRenderTargetDesc = XrRenderTextureDescToUnityRenderTextureDesc(xrRenderPass.motionVectorRenderTargetDesc),
  404. cullingParameters = cullingParameters,
  405. occlusionMeshMaterial = s_OcclusionMeshMaterial,
  406. occlusionMeshScale = GetOcclusionMeshScale(),
  407. foveatedRenderingInfo = xrRenderPass.foveatedRenderingInfo,
  408. multipassId = layout.GetActivePasses().Count,
  409. cullingPassId = xrRenderPass.cullingPassIndex,
  410. copyDepth = xrRenderPass.shouldFillOutDepth,
  411. xrSdkRenderPass = xrRenderPass
  412. };
  413. return passInfo;
  414. }
  415. #endif
  416. }
  417. }