-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPassthroughFBExt.cs
More file actions
289 lines (261 loc) · 11.1 KB
/
PassthroughFBExt.cs
File metadata and controls
289 lines (261 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
// This requires an addition to the Android Manifest to work on quest:
// <uses-feature android:name="com.oculus.feature.PASSTHROUGH" android:required="true" />
//
// To work on Quest+Link, you may need to enable beta features in the Oculus
// app's settings.
using System;
using System.Runtime.InteropServices;
namespace StereoKit.Framework
{
class PassthroughFBExt : IStepper
{
bool extAvailable;
bool enabled;
bool enableOnInitialize;
XrPassthroughFB activePassthrough = new XrPassthroughFB();
XrPassthroughLayerFB activeLayer = new XrPassthroughLayerFB();
Color oldColor;
bool oldSky;
public bool Available => extAvailable;
public bool Enabled
{
get => enabled; set
{
if (extAvailable == false || enabled == value) return;
if (value)
{
enabled = StartPassthrough();
}
else
{
PausePassthrough();
enabled = false;
}
}
}
public PassthroughFBExt() : this(true) { }
public PassthroughFBExt(bool enabled = true)
{
if (SK.IsInitialized)
Log.Err("PassthroughFBExt must be constructed before StereoKit is initialized!");
Backend.OpenXR.RequestExt("XR_FB_passthrough");
enableOnInitialize = enabled;
}
public bool Initialize()
{
extAvailable =
Backend.XRType == BackendXRType.OpenXR &&
Backend.OpenXR.ExtEnabled("XR_FB_passthrough") &&
LoadBindings() &&
InitPassthrough();
if (enableOnInitialize)
Enabled = true;
return true;
}
public void Step()
{
if (Enabled == false) return;
XrCompositionLayerPassthroughFB layer = new XrCompositionLayerPassthroughFB(
XrCompositionLayerFlags.BLEND_TEXTURE_SOURCE_ALPHA_BIT, activeLayer);
Backend.OpenXR.AddCompositionLayer(layer, -1);
}
public void Shutdown()
{
if (!Enabled) return;
Enabled = false;
DestroyPassthrough();
}
bool InitPassthrough()
{
XrResult result = xrCreatePassthroughFB(
Backend.OpenXR.Session,
new XrPassthroughCreateInfoFB(XrPassthroughFlagsFB.None),
out activePassthrough);
if (result != XrResult.Success)
{
Log.Err($"xrCreatePassthroughFB failed: {result}");
return false;
}
result = xrCreatePassthroughLayerFB(
Backend.OpenXR.Session,
new XrPassthroughLayerCreateInfoFB(activePassthrough, XrPassthroughFlagsFB.None, XrPassthroughLayerPurposeFB.RECONSTRUCTION_FB),
out activeLayer);
if (result != XrResult.Success)
{
Log.Err($"xrCreatePassthroughLayerFB failed: {result}");
return false;
}
return true;
}
void DestroyPassthrough()
{
xrDestroyPassthroughLayerFB(activeLayer);
xrDestroyPassthroughFB(activePassthrough);
}
bool StartPassthrough()
{
XrResult result = xrPassthroughStartFB(activePassthrough);
if (result != XrResult.Success)
{
Log.Err($"xrPassthroughStartFB failed: {result}");
return false;
}
result = xrPassthroughLayerResumeFB(activeLayer);
if (result != XrResult.Success)
{
Log.Err($"xrPassthroughLayerResumeFB failed: {result}");
return false;
}
oldColor = Renderer.ClearColor;
oldSky = Renderer.EnableSky;
Renderer.ClearColor = Color.BlackTransparent;
Renderer.EnableSky = false;
return true;
}
void PausePassthrough()
{
xrPassthroughPauseFB(activePassthrough);
Renderer.ClearColor = oldColor;
Renderer.EnableSky = oldSky;
}
#region OpenXR native bindings and types
enum XrStructureType : UInt64
{
XR_TYPE_PASSTHROUGH_CREATE_INFO_FB = 1000118001,
XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB = 1000118002,
XR_TYPE_PASSTHROUGH_STYLE_FB = 1000118020,
XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB = 1000118003,
}
enum XrPassthroughFlagsFB : UInt64
{
None = 0,
IS_RUNNING_AT_CREATION_BIT_FB = 0x00000001,
LAYER_DEPTH_BIT_FB = 0x00000002
}
enum XrCompositionLayerFlags : UInt64
{
None = 0,
CORRECT_CHROMATIC_ABERRATION_BIT = 0x00000001,
BLEND_TEXTURE_SOURCE_ALPHA_BIT = 0x00000002,
UNPREMULTIPLIED_ALPHA_BIT = 0x00000004,
}
enum XrPassthroughLayerPurposeFB : UInt32
{
RECONSTRUCTION_FB = 0,
PROJECTED_FB = 1,
TRACKED_KEYBOARD_HANDS_FB = 1000203001,
MAX_ENUM_FB = 0x7FFFFFFF,
}
enum XrResult : Int32
{
Success = 0,
}
#pragma warning disable 0169 // handle is not "used", but required for interop
struct XrPassthroughFB { ulong handle; }
struct XrPassthroughLayerFB { ulong handle; }
#pragma warning restore 0169
[StructLayout(LayoutKind.Sequential)]
struct XrPassthroughCreateInfoFB
{
private XrStructureType type;
public IntPtr next;
public XrPassthroughFlagsFB flags;
public XrPassthroughCreateInfoFB(XrPassthroughFlagsFB passthroughFlags)
{
type = XrStructureType.XR_TYPE_PASSTHROUGH_CREATE_INFO_FB;
next = IntPtr.Zero;
flags = passthroughFlags;
}
}
[StructLayout(LayoutKind.Sequential)]
struct XrPassthroughLayerCreateInfoFB
{
private XrStructureType type;
public IntPtr next;
public XrPassthroughFB passthrough;
public XrPassthroughFlagsFB flags;
public XrPassthroughLayerPurposeFB purpose;
public XrPassthroughLayerCreateInfoFB(XrPassthroughFB passthrough, XrPassthroughFlagsFB flags, XrPassthroughLayerPurposeFB purpose)
{
type = XrStructureType.XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB;
next = IntPtr.Zero;
this.passthrough = passthrough;
this.flags = flags;
this.purpose = purpose;
}
}
[StructLayout(LayoutKind.Sequential)]
struct XrPassthroughStyleFB
{
public XrStructureType type;
public IntPtr next;
public float textureOpacityFactor;
public Color edgeColor;
public XrPassthroughStyleFB(float textureOpacityFactor, Color edgeColor)
{
type = XrStructureType.XR_TYPE_PASSTHROUGH_STYLE_FB;
next = IntPtr.Zero;
this.textureOpacityFactor = textureOpacityFactor;
this.edgeColor = edgeColor;
}
}
[StructLayout(LayoutKind.Sequential)]
struct XrCompositionLayerPassthroughFB
{
public XrStructureType type;
public IntPtr next;
public XrCompositionLayerFlags flags;
public ulong space;
public XrPassthroughLayerFB layerHandle;
public XrCompositionLayerPassthroughFB(XrCompositionLayerFlags flags, XrPassthroughLayerFB layerHandle)
{
type = XrStructureType.XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB;
next = IntPtr.Zero;
space = 0;
this.flags = flags;
this.layerHandle = layerHandle;
}
}
delegate XrResult del_xrCreatePassthroughFB(ulong session, [In] XrPassthroughCreateInfoFB createInfo, out XrPassthroughFB outPassthrough);
delegate XrResult del_xrDestroyPassthroughFB(XrPassthroughFB passthrough);
delegate XrResult del_xrPassthroughStartFB(XrPassthroughFB passthrough);
delegate XrResult del_xrPassthroughPauseFB(XrPassthroughFB passthrough);
delegate XrResult del_xrCreatePassthroughLayerFB(ulong session, [In] XrPassthroughLayerCreateInfoFB createInfo, out XrPassthroughLayerFB outLayer);
delegate XrResult del_xrDestroyPassthroughLayerFB(XrPassthroughLayerFB layer);
delegate XrResult del_xrPassthroughLayerPauseFB(XrPassthroughLayerFB layer);
delegate XrResult del_xrPassthroughLayerResumeFB(XrPassthroughLayerFB layer);
delegate XrResult del_xrPassthroughLayerSetStyleFB(XrPassthroughLayerFB layer, [In] XrPassthroughStyleFB style);
del_xrCreatePassthroughFB xrCreatePassthroughFB;
del_xrDestroyPassthroughFB xrDestroyPassthroughFB;
del_xrPassthroughStartFB xrPassthroughStartFB;
del_xrPassthroughPauseFB xrPassthroughPauseFB;
del_xrCreatePassthroughLayerFB xrCreatePassthroughLayerFB;
del_xrDestroyPassthroughLayerFB xrDestroyPassthroughLayerFB;
del_xrPassthroughLayerPauseFB xrPassthroughLayerPauseFB;
del_xrPassthroughLayerResumeFB xrPassthroughLayerResumeFB;
del_xrPassthroughLayerSetStyleFB xrPassthroughLayerSetStyleFB;
bool LoadBindings()
{
xrCreatePassthroughFB = Backend.OpenXR.GetFunction<del_xrCreatePassthroughFB>("xrCreatePassthroughFB");
xrDestroyPassthroughFB = Backend.OpenXR.GetFunction<del_xrDestroyPassthroughFB>("xrDestroyPassthroughFB");
xrPassthroughStartFB = Backend.OpenXR.GetFunction<del_xrPassthroughStartFB>("xrPassthroughStartFB");
xrPassthroughPauseFB = Backend.OpenXR.GetFunction<del_xrPassthroughPauseFB>("xrPassthroughPauseFB");
xrCreatePassthroughLayerFB = Backend.OpenXR.GetFunction<del_xrCreatePassthroughLayerFB>("xrCreatePassthroughLayerFB");
xrDestroyPassthroughLayerFB = Backend.OpenXR.GetFunction<del_xrDestroyPassthroughLayerFB>("xrDestroyPassthroughLayerFB");
xrPassthroughLayerPauseFB = Backend.OpenXR.GetFunction<del_xrPassthroughLayerPauseFB>("xrPassthroughLayerPauseFB");
xrPassthroughLayerResumeFB = Backend.OpenXR.GetFunction<del_xrPassthroughLayerResumeFB>("xrPassthroughLayerResumeFB");
xrPassthroughLayerSetStyleFB = Backend.OpenXR.GetFunction<del_xrPassthroughLayerSetStyleFB>("xrPassthroughLayerSetStyleFB");
return
xrCreatePassthroughFB != null &&
xrDestroyPassthroughFB != null &&
xrPassthroughStartFB != null &&
xrPassthroughPauseFB != null &&
xrCreatePassthroughLayerFB != null &&
xrDestroyPassthroughLayerFB != null &&
xrPassthroughLayerPauseFB != null &&
xrPassthroughLayerResumeFB != null &&
xrPassthroughLayerSetStyleFB != null;
}
#endregion
}
}