1 // This file contain the two main data structures controlled by the XRSystem.
2 // XRView contains the parameters required to render (proj and view matrices, viewport, etc)
3 // XRPass holds the render target information and a list of XRView.
4 // When a pass has 2+ views, hardware instancing will be active.
5 // To avoid allocating every frame, XRView is a struct and XRPass is pooled.
7 #if UNITY_2019_3_OR_NEWER && ENABLE_VR
12 using System.Collections.Generic;
13 using UnityEngine.Rendering;
15 using UnityEngine.Experimental.XR;
18 namespace UnityEngine.Experimental.Rendering.HDPipeline
20 internal struct XRView
22 internal readonly Matrix4x4 projMatrix;
23 internal readonly Matrix4x4 viewMatrix;
24 internal readonly Rect viewport;
25 internal readonly Mesh occlusionMesh;
26 internal readonly Camera.StereoscopicEye legacyStereoEye;
28 internal XRView(Camera camera, Camera.StereoscopicEye eye)
30 projMatrix = camera.GetStereoProjectionMatrix(eye);
31 viewMatrix = camera.GetStereoViewMatrix(eye);
32 viewport = camera.pixelRect;
34 legacyStereoEye = eye;
37 internal XRView(Matrix4x4 proj, Matrix4x4 view, Rect vp)
43 legacyStereoEye = (Camera.StereoscopicEye)(-1);
47 internal XRView(XRDisplaySubsystem.XRRenderParameter renderParameter)
49 projMatrix = renderParameter.projection;
50 viewMatrix = renderParameter.view;
51 viewport = renderParameter.viewport;
52 occlusionMesh = renderParameter.occlusionMesh;
53 legacyStereoEye = (Camera.StereoscopicEye)(-1);
60 readonly List<XRView> views = new List<XRView>(2);
62 internal bool enabled { get => views.Count > 0; }
63 internal bool xrSdkEnabled { get; private set; }
65 internal int multipassId { get; private set; }
66 internal int cullingPassId { get; private set; }
68 // Ability to specify where to render the pass
69 internal RenderTargetIdentifier renderTarget { get; private set; }
70 internal RenderTextureDescriptor renderTargetDesc { get; private set; }
71 static RenderTargetIdentifier invalidRT = -1;
72 internal bool renderTargetValid { get => renderTarget != invalidRT; }
74 // Access to view information
75 internal Matrix4x4 GetProjMatrix(int viewIndex = 0) { return views[viewIndex].projMatrix; }
76 internal Matrix4x4 GetViewMatrix(int viewIndex = 0) { return views[viewIndex].viewMatrix; }
77 internal Rect GetViewport(int viewIndex = 0) { return views[viewIndex].viewport; }
79 // Instanced views support (instanced draw calls or multiview extension)
80 internal int viewCount { get => views.Count; }
81 internal bool instancingEnabled { get => viewCount > 1; }
83 // XRTODO(2019.3) : remove once XRE-445 is done
84 // We need an intermediate target to render the mirror view
85 public RenderTexture tempRenderTexture { get; private set; } = null;
87 RenderTextureDescriptor tempRenderTextureDesc;
90 // Legacy multipass support
91 internal int legacyMultipassEye { get => (int)views[0].legacyStereoEye; }
92 internal bool legacyMultipassEnabled { get => enabled && !instancingEnabled && legacyMultipassEye >= 0; }
94 internal static XRPass Create(int multipassId, RenderTexture rt = null)
96 XRPass passInfo = GenericPool<XRPass>.Get();
98 passInfo.multipassId = multipassId;
99 passInfo.cullingPassId = multipassId;
100 passInfo.views.Clear();
104 passInfo.renderTarget = new RenderTargetIdentifier(rt);
105 passInfo.renderTargetDesc = rt.descriptor;
109 passInfo.renderTarget = invalidRT;
110 passInfo.renderTargetDesc = default;
113 passInfo.xrSdkEnabled = false;
114 passInfo.tempRenderTexture = null;
117 passInfo.tempRenderTextureDesc = default;
123 internal void AddView(Camera camera, Camera.StereoscopicEye eye)
125 AddViewInternal(new XRView(camera, eye));
128 internal void AddView(Matrix4x4 proj, Matrix4x4 view, Rect vp)
130 AddViewInternal(new XRView(proj, view, vp));
134 internal static XRPass Create(XRDisplaySubsystem.XRRenderPass xrRenderPass)
136 XRPass passInfo = GenericPool<XRPass>.Get();
138 passInfo.multipassId = xrRenderPass.renderPassIndex;
139 passInfo.cullingPassId = xrRenderPass.cullingPassIndex;
140 passInfo.views.Clear();
141 passInfo.renderTarget = xrRenderPass.renderTarget;
142 passInfo.renderTargetDesc = xrRenderPass.renderTargetDesc;
143 passInfo.xrSdkEnabled = true;
145 Debug.Assert(passInfo.renderTargetValid, "Invalid render target from XRDisplaySubsystem!");
147 // XRTODO(2019.3) : remove once XRE-445 is done
149 // Avoid allocating every frame by reusing the same RT unless the configuration changed
150 if (passInfo.tempRenderTexture == null || !Equals(passInfo.tempRenderTextureDesc, xrRenderPass.renderTargetDesc))
152 if (passInfo.tempRenderTexture != null)
153 passInfo.tempRenderTexture.Release();
155 passInfo.tempRenderTexture = new RenderTexture(xrRenderPass.renderTargetDesc);
156 passInfo.tempRenderTexture.Create();
158 // Store the original descriptor because the one from the RT has the flag 'CreatedFromScript' and would fail the Equals()
159 passInfo.tempRenderTextureDesc = xrRenderPass.renderTargetDesc;
166 // XRTODO(2019.3) : remove once XRE-445 is done
169 if (tempRenderTexture != null)
170 tempRenderTexture.Release();
173 internal void AddView(XRDisplaySubsystem.XRRenderParameter xrSdkRenderParameter)
175 AddViewInternal(new XRView(xrSdkRenderParameter));
178 internal static void Release(XRPass xrPass)
180 GenericPool<XRPass>.Release(xrPass);
183 internal void AddViewInternal(XRView xrView)
187 // Validate memory limitations
188 Debug.Assert(views.Count <= TextureXR.kMaxSlices);
191 internal void StartLegacyStereo(Camera camera, CommandBuffer cmd, ScriptableRenderContext renderContext)
195 // Required for some legacy shaders (text for example)
196 cmd.SetViewProjectionMatrices(GetViewMatrix(), GetProjMatrix());
198 if (camera.stereoEnabled)
200 // Reset scissor and viewport for C++ stereo code
201 cmd.DisableScissorRect();
202 cmd.SetViewport(camera.pixelRect);
204 renderContext.ExecuteCommandBuffer(cmd);
207 if (legacyMultipassEnabled)
208 renderContext.StartMultiEye(camera, legacyMultipassEye);
210 renderContext.StartMultiEye(camera);
215 internal void StopLegacyStereo(Camera camera, CommandBuffer cmd, ScriptableRenderContext renderContext)
217 if (enabled && camera.stereoEnabled)
219 renderContext.ExecuteCommandBuffer(cmd);
221 renderContext.StopMultiEye(camera);
225 internal void EndCamera(HDCamera hdCamera, ScriptableRenderContext renderContext, CommandBuffer cmd)
232 // XRTODO(2019.3) : remove once XRE-445 is done
233 if (tempRenderTexture && hdCamera.camera.targetTexture == null)
235 // Multipass only for now
239 cmd.SetRenderTarget(renderTarget);
240 cmd.SetViewport(hdCamera.finalViewport);
241 HDUtils.BlitQuad(cmd, tempRenderTexture, new Vector4(1, 1, 0, 0), new Vector4(1, 1, 0, 0), 0, false);
243 // Mirror view (only works with stereo for now)
246 cmd.SetRenderTarget(new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget));
247 cmd.SetViewport(hdCamera.camera.pixelRect);
249 Vector4 scaleBiasRT = new Vector4(0.5f, 1, multipassId * 0.5f, 0);
250 HDUtils.BlitQuad(cmd, tempRenderTexture, new Vector4(1, 1, 0, 0), scaleBiasRT, 0, true);
254 throw new NotImplementedException();
259 throw new NotImplementedException();
265 renderContext.ExecuteCommandBuffer(cmd);
268 // Pushes to XR headset and/or display mirror
269 if (legacyMultipassEnabled)
270 renderContext.StereoEndRender(hdCamera.camera, legacyMultipassEye, legacyMultipassEye == 1);
272 renderContext.StereoEndRender(hdCamera.camera);