forked from StereoKit/StereoKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDocBackend.cs
More file actions
166 lines (145 loc) · 5.92 KB
/
Copy pathDocBackend.cs
File metadata and controls
166 lines (145 loc) · 5.92 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
// SPDX-License-Identifier: MIT
// The authors below grant copyright rights under the MIT license:
// Copyright (c) 2019-2025 Nick Klingensmith
// Copyright (c) 2025 Qualcomm Technologies, Inc.
using System;
using System.Runtime.InteropServices;
using StereoKit;
using StereoKit.Framework;
class DocBackend : ITest
{
public void Initialize() { }
public void Shutdown () { }
public void Step () { }
}
/// :CodeSample: OpenXR.RequestExt OpenXR.ExtEnabled Backend.XRType OpenXR.GetFunction OpenXR.Instance OpenXR.Time IStepper
/// ### Implementing OpenXR Extensions
///
/// Using the `Backend.OpenXR` class, it's possible to implement OpenXR
/// extensions without directly modifying StereoKit! Here's a simple
/// example of how to do this, implemented via an `IStepper`.
class Win32PerformanceCounterExt : IStepper
{
// Start by defining C# equivalents of OpenXR's function signatures and
// types. This can be a bit involved, see PassthroughFBExt.cs in the SK
// repository for a more extensive sample.
delegate uint XR_xrConvertTimeToWin32PerformanceCounterKHR(ulong instance, long time, out long performanceCounter);
static XR_xrConvertTimeToWin32PerformanceCounterKHR xrConvertTimeToWin32PerformanceCounterKHR;
const string timeExt = "XR_KHR_win32_convert_performance_counter_time";
public bool Enabled { get; private set; }
public Win32PerformanceCounterExt()
{
// OpenXR extensions must be requested before initializing StereoKit,
// so this IStepper needs to be added _before_ `SK.Initialize`.
if (SK.IsInitialized)
Log.Err("OpenXR extensions must be constructed before StereoKit is initialized!");
// At this point, we don't even know if the app will have access to
// OpenXR, so this should _not_ be be guarded by a check for OpenXR.
Backend.OpenXR.RequestExt(timeExt);
}
public bool Initialize()
{
// Check if we're running OpenXR, the extension is present, and all of
// our extension functions bound properly.
Enabled =
Backend.XRType == BackendXRType.OpenXR &&
Backend.OpenXR.ExtEnabled(timeExt) &&
LoadBindings();
// Test it out!
if (Enabled)
{
xrConvertTimeToWin32PerformanceCounterKHR(Backend.OpenXR.Instance, Backend.OpenXR.Time, out long counter);
Log.Info($"XrTime: {counter}");
}
return Enabled;
}
// In this method, we load any functions from the extension that we care
// about, and then report if they were loaded successfully.
private bool LoadBindings()
{
xrConvertTimeToWin32PerformanceCounterKHR =
Backend.OpenXR.GetFunction<XR_xrConvertTimeToWin32PerformanceCounterKHR>("xrConvertTimeToWin32PerformanceCounterKHR");
return xrConvertTimeToWin32PerformanceCounterKHR != null;
}
// A more complicated extension might use these, but this EXT does not
// require any actions on-Step.
public void Shutdown() { }
public void Step() { }
}
/// :End:
/// :CodeSample: Backend.Vulkan Backend.Graphics BackendVulkanRequest IStepper
/// ### Requesting Vulkan Extensions
///
/// StereoKit renders with Vulkan, and `Backend.Vulkan` lets you opt into extra
/// Vulkan instance/device extensions and device features that StereoKit
/// wouldn't normally request. Register a `BackendVulkanRequest` _before_
/// `SK.Initialize`, then after initialization check whether it enabled and
/// resolve any functions it provides.
///
/// A good practical use is `VK_EXT_debug_utils`, which lets you attach
/// human-readable names to Vulkan objects so they show up nicely in tools like
/// RenderDoc or the validation layers. Here we request the (instance)
/// extension, then use it to name the `VkDevice` StereoKit is rendering with.
/// This is implemented via an `IStepper`, so it must be added before
/// `SK.Initialize`.
class VulkanDebugNamesExt : IStepper
{
const string debugUtilsExt = "VK_EXT_debug_utils";
// A C# equivalent of vkSetDebugUtilsObjectNameEXT and the struct it takes.
[StructLayout(LayoutKind.Sequential)]
struct VkDebugUtilsObjectNameInfoEXT
{
public int sType;
public IntPtr pNext;
public int objectType;
public ulong objectHandle;
[MarshalAs(UnmanagedType.LPUTF8Str)] public string pObjectName;
}
delegate int VkSetDebugUtilsObjectNameEXT(IntPtr device, in VkDebugUtilsObjectNameInfoEXT nameInfo);
static VkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT;
public bool Enabled { get; private set; }
public VulkanDebugNamesExt()
{
// Vulkan requests must happen before StereoKit initializes, so this
// IStepper needs to be added _before_ `SK.Initialize`.
if (SK.IsInitialized)
Log.Err("Vulkan extensions must be requested before StereoKit is initialized!");
// debug_utils is an _instance_ extension. A named request lets us query
// it later, and leaving `required` false means SK still starts up if
// the extension isn't available.
Backend.Vulkan.Request(new BackendVulkanRequest {
name = "debug_utils",
required = false,
instanceExtensions = new string[] { debugUtilsExt },
});
}
public bool Initialize()
{
// Confirm we're on Vulkan, the extension enabled, and our function
// bound. RequestEnabled("debug_utils") would also work here.
Enabled =
Backend.Graphics == BackendGraphics.Vulkan &&
Backend.Vulkan.ExtEnabled(debugUtilsExt) &&
LoadBindings();
if (Enabled)
{
// Give the VkDevice a friendly name for debugging tools.
VkDebugUtilsObjectNameInfoEXT info = new VkDebugUtilsObjectNameInfoEXT {
sType = 1000128000, // VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT
objectType = 3, // VK_OBJECT_TYPE_DEVICE
objectHandle = (ulong)Backend.Vulkan.Device,
pObjectName = "StereoKit Device",
};
vkSetDebugUtilsObjectNameEXT(Backend.Vulkan.Device, info);
}
return Enabled;
}
private bool LoadBindings()
{
vkSetDebugUtilsObjectNameEXT = Backend.Vulkan.GetFunction<VkSetDebugUtilsObjectNameEXT>("vkSetDebugUtilsObjectNameEXT");
return vkSetDebugUtilsObjectNameEXT != null;
}
public void Shutdown() { }
public void Step() { }
}
/// :End: