Skip to content

Commit 49d8f74

Browse files
alex-vazquez-unity3dEvergreen
authored andcommitted
[XR] Begin And End Camera Rendering is called 1 time on XR Multipass.
1- XRSystem.New XRLayout, always have the same layout, it is not a new, So the active passes are cleared. 2- On XR Multipass, Begin and End Camera Rendering was called twice, one time for each XRPass.
1 parent fb54e64 commit 49d8f74

File tree

14 files changed

+618
-126
lines changed

14 files changed

+618
-126
lines changed

Packages/com.unity.render-pipelines.core/Runtime/XR/XRLayout.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System.Collections.Generic;
22
using System.Text;
3-
using UnityEngine.Rendering;
43

54
namespace UnityEngine.Experimental.Rendering
65
{
@@ -28,7 +27,7 @@ public void AddCamera(Camera camera, bool enableXR)
2827
if (XRSystem.displayActive && xrSupported)
2928
{
3029
XRSystem.SetDisplayZRange(camera.nearClipPlane, camera.farClipPlane);
31-
XRSystem.CreateDefaultLayout(camera);
30+
XRSystem.CreateDefaultLayout(camera, this);
3231
}
3332
else
3433
{
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using UnityEngine.Pool;
4+
5+
namespace UnityEngine.Experimental.Rendering
6+
{
7+
internal class XRLayoutStack : IDisposable
8+
{
9+
readonly Stack<XRLayout> m_Stack = new ();
10+
11+
public XRLayout New()
12+
{
13+
GenericPool<XRLayout>.Get(out var layout);
14+
m_Stack.Push(layout);
15+
return layout;
16+
}
17+
18+
public XRLayout top => m_Stack.Peek();
19+
20+
public void Release()
21+
{
22+
if (!m_Stack.TryPop(out var value))
23+
throw new InvalidOperationException($"Calling {nameof(Release)} without calling {nameof(New)} first.");
24+
25+
value.Clear();
26+
GenericPool<XRLayout>.Release(value);
27+
}
28+
29+
public void Dispose()
30+
{
31+
if (m_Stack.Count != 0)
32+
throw new Exception($"Stack is not empty. Did you skip a call to {nameof(Release)}?");
33+
}
34+
}
35+
}

Packages/com.unity.render-pipelines.core/Runtime/XR/XRLayoutStack.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Packages/com.unity.render-pipelines.core/Runtime/XR/XRPass.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using UnityEditor;
34
using UnityEngine.Rendering;
45

56
namespace UnityEngine.Experimental.Rendering
@@ -94,6 +95,16 @@ public bool supportsFoveatedRendering
9495
/// </summary>
9596
public bool copyDepth { get; private set; }
9697

98+
/// <summary>
99+
/// If true, is the first pass of a xr camera
100+
/// </summary>
101+
public bool isFirstCameraPass => multipassId == 0;
102+
103+
/// <summary>
104+
/// If true, is the last pass of a xr camera
105+
/// </summary>
106+
public bool isLastCameraPass => (multipassId == 0 && viewCount <= 1) || (multipassId == 1 && viewCount > 1);
107+
97108
/// <summary>
98109
/// Index of the pass inside the frame.
99110
/// </summary>

Packages/com.unity.render-pipelines.core/Runtime/XR/XRSystem.cs

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public static class SinglepassKeywords
2525
public static class XRSystem
2626
{
2727
// Keep track of only one XR layout
28-
static XRLayout s_Layout = new XRLayout();
28+
static XRLayoutStack s_Layout = new ();
2929

3030
// Delegate allocations of XRPass to the render pipeline
3131
static Func<XRPassCreateInfo, XRPass> s_PassAllocator = null;
@@ -233,14 +233,7 @@ public static void SetRenderScale(float renderScale)
233233
public static XRLayout NewLayout()
234234
{
235235
RefreshDeviceInfo();
236-
237-
if (s_Layout.GetActivePasses().Count > 0)
238-
{
239-
Debug.LogWarning("Render Pipeline error : the XR layout still contains active passes. Executing XRSystem.EndLayout() right now.");
240-
EndLayout();
241-
}
242-
243-
return s_Layout;
236+
return s_Layout.New();
244237
}
245238

246239
/// <summary>
@@ -249,9 +242,9 @@ public static XRLayout NewLayout()
249242
public static void EndLayout()
250243
{
251244
if (dumpDebugInfo)
252-
s_Layout.LogDebugInfo();
245+
s_Layout.top.LogDebugInfo();
253246

254-
s_Layout.Clear();
247+
s_Layout.Release();
255248
}
256249

257250
/// <summary>
@@ -340,45 +333,49 @@ static void RefreshDeviceInfo()
340333
}
341334

342335
// Setup the layout to use multi-pass or single-pass based on the runtime caps
343-
internal static void CreateDefaultLayout(Camera camera)
336+
internal static void CreateDefaultLayout(Camera camera, XRLayout layout)
344337
{
345338
#if ENABLE_VR && ENABLE_XR_MODULE
346339
if (s_Display == null)
347340
throw new NullReferenceException(nameof(s_Display));
348341

342+
void AddViewToPass(XRPass xrPass, XRDisplaySubsystem.XRRenderPass renderPass, int renderParamIndex)
343+
{
344+
renderPass.GetRenderParameter(camera, renderParamIndex, out var renderParam);
345+
xrPass.AddView(BuildView(renderPass, renderParam));
346+
}
347+
349348
for (int renderPassIndex = 0; renderPassIndex < s_Display.GetRenderPassCount(); ++renderPassIndex)
350349
{
351350
s_Display.GetRenderPass(renderPassIndex, out var renderPass);
352351
s_Display.GetCullingParameters(camera, renderPass.cullingPassIndex, out var cullingParams);
353352

353+
int renderParameterCount = renderPass.GetRenderParameterCount();
354354
if (CanUseSinglePass(camera, renderPass))
355355
{
356-
var xrPass = s_PassAllocator(BuildPass(renderPass, cullingParams));
356+
var createInfo = BuildPass(renderPass, cullingParams, layout);
357+
var xrPass = s_PassAllocator(createInfo);
357358

358-
for (int renderParamIndex = 0; renderParamIndex < renderPass.GetRenderParameterCount(); ++renderParamIndex)
359+
for (int renderParamIndex = 0; renderParamIndex < renderParameterCount; ++renderParamIndex)
359360
{
360-
renderPass.GetRenderParameter(camera, renderParamIndex, out var renderParam);
361-
xrPass.AddView(BuildView(renderPass, renderParam));
361+
AddViewToPass(xrPass, renderPass, renderParamIndex);
362362
}
363363

364-
s_Layout.AddPass(camera, xrPass);
364+
layout.AddPass(camera, xrPass);
365365
}
366366
else
367367
{
368-
for (int renderParamIndex = 0; renderParamIndex < renderPass.GetRenderParameterCount(); ++renderParamIndex)
368+
for (int renderParamIndex = 0; renderParamIndex < renderParameterCount; ++renderParamIndex)
369369
{
370-
renderPass.GetRenderParameter(camera, renderParamIndex, out var renderParam);
371-
372-
var xrPass = s_PassAllocator(BuildPass(renderPass, cullingParams));
373-
xrPass.AddView(BuildView(renderPass, renderParam));
374-
375-
s_Layout.AddPass(camera, xrPass);
370+
var createInfo = BuildPass(renderPass, cullingParams, layout);
371+
var xrPass = s_PassAllocator(createInfo);
372+
AddViewToPass(xrPass, renderPass, renderParamIndex);
373+
layout.AddPass(camera, xrPass);
376374
}
377375
}
378376
}
379377

380-
if (s_LayoutOverride != null)
381-
s_LayoutOverride.Invoke(s_Layout, camera);
378+
s_LayoutOverride?.Invoke(layout, camera);
382379
#endif
383380
}
384381

@@ -400,8 +397,7 @@ internal static void ReconfigurePass(XRPass xrPass, Camera camera)
400397
xrPass.AssignView(renderParamIndex, BuildView(renderPass, renderParam));
401398
}
402399

403-
if (s_LayoutOverride != null)
404-
s_LayoutOverride.Invoke(s_Layout, camera);
400+
s_LayoutOverride?.Invoke(s_Layout.top, camera);
405401
}
406402
#endif
407403
}
@@ -445,7 +441,7 @@ static XRView BuildView(XRDisplaySubsystem.XRRenderPass renderPass, XRDisplaySub
445441
return new XRView(renderParameter.projection, renderParameter.view, viewport, occlusionMesh, renderParameter.textureArraySlice);
446442
}
447443

448-
static XRPassCreateInfo BuildPass(XRDisplaySubsystem.XRRenderPass xrRenderPass, ScriptableCullingParameters cullingParameters)
444+
static XRPassCreateInfo BuildPass(XRDisplaySubsystem.XRRenderPass xrRenderPass, ScriptableCullingParameters cullingParameters, XRLayout layout)
449445
{
450446
// We can't use descriptor directly because y-flip is forced
451447
// XRTODO : fix root problem
@@ -455,7 +451,7 @@ static XRPassCreateInfo BuildPass(XRDisplaySubsystem.XRRenderPass xrRenderPass,
455451
rtDesc.volumeDepth = xrRenderPass.renderTargetDesc.volumeDepth;
456452
rtDesc.vrUsage = xrRenderPass.renderTargetDesc.vrUsage;
457453
rtDesc.sRGB = xrRenderPass.renderTargetDesc.sRGB;
458-
454+
459455
XRPassCreateInfo passInfo = new XRPassCreateInfo
460456
{
461457
renderTarget = xrRenderPass.renderTarget,
@@ -464,7 +460,7 @@ static XRPassCreateInfo BuildPass(XRDisplaySubsystem.XRRenderPass xrRenderPass,
464460
occlusionMeshMaterial = s_OcclusionMeshMaterial,
465461
occlusionMeshScale = GetOcclusionMeshScale(),
466462
foveatedRenderingInfo = xrRenderPass.foveatedRenderingInfo,
467-
multipassId = s_Layout.GetActivePasses().Count,
463+
multipassId = layout.GetActivePasses().Count,
468464
cullingPassId = xrRenderPass.cullingPassIndex,
469465
copyDepth = xrRenderPass.shouldFillOutDepth,
470466
xrSdkRenderPass = xrRenderPass

Packages/com.unity.render-pipelines.core/Tests/Editor/XR.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Runtime.InteropServices;
4+
using NUnit.Framework;
5+
using UnityEngine.Experimental.Rendering;
6+
7+
namespace UnityEngine.Rendering.Experimental.Tests.XR
8+
{
9+
[TestFixture]
10+
class XRLayoutStackTests
11+
{
12+
private XRLayoutStack m_StackTest = new ();
13+
14+
[TearDown]
15+
public void TearDown()
16+
{
17+
m_StackTest.Dispose();
18+
}
19+
20+
[Test]
21+
public void New_ReturnsNonNullObject()
22+
{
23+
var layout = m_StackTest.New();
24+
Assert.NotNull(layout);
25+
m_StackTest.Release();
26+
}
27+
28+
[Test]
29+
public void Top_AfterNew_ReturnsCorrectObject()
30+
{
31+
var layout = m_StackTest.New();
32+
Assert.AreEqual(layout, m_StackTest.top);
33+
m_StackTest.Release();
34+
}
35+
36+
[Test]
37+
public void NewNTimes_ReturnsTheTopToTheLatestElement()
38+
{
39+
var layouts = new List<XRLayout>();
40+
41+
const int k_Iterations = 5;
42+
43+
// Creating instances and adding them to the list
44+
for (int i = 0; i < k_Iterations; i++)
45+
{
46+
layouts.Add(m_StackTest.New());
47+
}
48+
49+
// Releasing instances and validating
50+
for (int i = k_Iterations - 1; i >= 0; i--)
51+
{
52+
Assert.AreEqual(layouts[i], m_StackTest.top);
53+
m_StackTest.Release();
54+
}
55+
56+
Top_WithoutNew_ThrowsException();
57+
}
58+
59+
[Test]
60+
public void Top_WithoutNew_ThrowsException()
61+
{
62+
Assert.Throws<InvalidOperationException>(() =>
63+
{
64+
var top = m_StackTest.top;
65+
});
66+
}
67+
68+
[Test]
69+
public void Release_WithoutNew_ThrowsException()
70+
{
71+
Assert.Throws<InvalidOperationException>(m_StackTest.Release);
72+
}
73+
74+
[Test]
75+
public void Dispose_WithoutRelease_ThrowsException()
76+
{
77+
m_StackTest.New();
78+
Assert.Throws<Exception>(m_StackTest.Dispose);
79+
m_StackTest.Release();
80+
}
81+
82+
[Test]
83+
public void CheckStackBetweenFramesReturnsTheSameXRLayout()
84+
{
85+
var stack = m_StackTest.New();
86+
m_StackTest.Release();
87+
88+
const int k_Iterations = 5;
89+
90+
// Creating instances and adding them to the list
91+
for (int i = 0; i < k_Iterations; i++)
92+
{
93+
m_StackTest.New();
94+
Assert.AreEqual(stack, m_StackTest.top);
95+
m_StackTest.Release();
96+
}
97+
}
98+
}
99+
}

Packages/com.unity.render-pipelines.core/Tests/Editor/XR/XRLayoutStackTests.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)