@covas-labs/electron-vr 0.5.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/bridge.d.ts +4 -0
- package/dist/bridge.js +36 -3
- package/dist/compatibility.d.ts +1 -1
- package/dist/compatibility.js +10 -3
- package/dist/openxrApiLayer.d.ts +1 -0
- package/dist/openxrApiLayer.js +1 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -88,6 +88,10 @@ Use the same command with `enable`, `disable`, or `uninstall`. `npm install` doe
|
|
|
88
88
|
|
|
89
89
|
Set `ELECTRON_VR_DISABLE_OPENVR=1` to prevent the OpenVR/SteamVR fallback while diagnosing OpenXR. When no usable OpenXR overlay path is available, the bridge selects `mock` and includes `openvr-disabled-by-env` in `probeMode`.
|
|
90
90
|
|
|
91
|
+
When Virtual Desktop VDXR is the active Windows OpenXR runtime, the bridge automatically avoids the OpenVR fallback and does not initialize OpenVR during probing, because that can start SteamVR and disrupt an OpenXR game. Install and enable the OpenXR API layer to use the OpenXR application-integration path, then restart the game.
|
|
92
|
+
|
|
93
|
+
OpenComposite does not implement the OpenVR overlay API required by this package. When OpenComposite is the registered OpenVR runtime, the bridge reports it in diagnostics but does not select the OpenVR backend; use a compatible OpenXR runtime with the API layer instead.
|
|
94
|
+
|
|
91
95
|
Applications can manage the same per-user installation through the public API:
|
|
92
96
|
|
|
93
97
|
```ts
|
|
@@ -102,6 +106,8 @@ await VROverlay.uninstallOpenXRApiLayer();
|
|
|
102
106
|
|
|
103
107
|
The methods return `Promise<OpenXRApiLayerStatus>` and reject when the platform is unsupported or the utility fails. Installation should require explicit user consent. It affects subsequently started OpenXR applications, so restart an already running game after installing, enabling, disabling, or uninstalling the layer. These methods support Linux x64 and Windows x64 and do not require administrator/root access for the normal per-user installation.
|
|
104
108
|
|
|
109
|
+
`getOpenXRApiLayerStatus()` reports `requiresUpdate: true` when the installed layer assets differ from those bundled with the package. Re-run `installOpenXRApiLayer()` after confirmation to update them.
|
|
110
|
+
|
|
105
111
|
For product UI, prefer the combined readiness report instead of interpreting raw probe fields:
|
|
106
112
|
|
|
107
113
|
```ts
|
|
@@ -111,4 +117,4 @@ console.log(report.launch.verdict, report.launch.requiredActions);
|
|
|
111
117
|
|
|
112
118
|
`report.launch.wouldWorkNow` answers whether launching a browser overlay now is expected to produce real VR output. Otherwise, the verdict distinguishes an actionable setup/runtime/host requirement from a fundamental incompatibility. The report also exposes detailed readiness states, actionable issues, and per-feature support. See `PRODUCT_INTEGRATION.md` in the repository for the recommended consent, IPC, restart, recovery, diagnostics, and production UI flow.
|
|
113
119
|
|
|
114
|
-
`getRuntimeInfo()` also includes `openvrRuntimeInstalled`, `openvrRuntimePath`, `openxrMode`, API-layer installation
|
|
120
|
+
`getRuntimeInfo()` also includes `openvrRuntimeInstalled`, `openvrRuntimePath`, `openxrMode`, API-layer installation state, `openxrHostDetected`, companion connection state, protocol version, and OpenXR host metadata. `openxrHostDetected` can become true before the overlay companion connects. `probeMode` includes the backend-selection decision.
|
package/dist/bridge.d.ts
CHANGED
|
@@ -22,11 +22,14 @@ export interface RuntimeInfo {
|
|
|
22
22
|
openxrApiLayerEnabled: boolean;
|
|
23
23
|
openxrApiLayerManifestPath: string;
|
|
24
24
|
openxrCompanionConnected: boolean;
|
|
25
|
+
openxrHostDetected: boolean;
|
|
25
26
|
openxrHostProcessId: number;
|
|
26
27
|
openxrHostApplicationName: string;
|
|
27
28
|
openxrHostGraphicsApi: string;
|
|
28
29
|
openxrHostAdapterLuid: string;
|
|
29
30
|
openxrProtocolVersion: number;
|
|
31
|
+
openxrSubmittedFrameSequence: number;
|
|
32
|
+
openxrConsumedFrameSequence: number;
|
|
30
33
|
openvrAvailable: boolean;
|
|
31
34
|
openvrRuntimeInstalled: boolean;
|
|
32
35
|
openvrRuntimePath: string;
|
|
@@ -117,6 +120,7 @@ export declare class VrBridge {
|
|
|
117
120
|
private linuxOpenVRVisibleTexture;
|
|
118
121
|
private windowsReadbackInFlight;
|
|
119
122
|
private windowsReadbackPending;
|
|
123
|
+
private windowsOpenXRTextures;
|
|
120
124
|
private linuxReadbackInFlight;
|
|
121
125
|
private linuxReadbackPending;
|
|
122
126
|
private invalidationTimer;
|
package/dist/bridge.js
CHANGED
|
@@ -116,11 +116,14 @@ function sanitizeRuntimeInfo(runtimeInfo) {
|
|
|
116
116
|
openxrApiLayerEnabled: runtimeInfo.openxrApiLayerEnabled ?? false,
|
|
117
117
|
openxrApiLayerManifestPath: runtimeInfo.openxrApiLayerManifestPath ?? "",
|
|
118
118
|
openxrCompanionConnected: runtimeInfo.openxrCompanionConnected ?? false,
|
|
119
|
+
openxrHostDetected: runtimeInfo.openxrHostDetected ?? false,
|
|
119
120
|
openxrHostProcessId: runtimeInfo.openxrHostProcessId ?? 0,
|
|
120
121
|
openxrHostApplicationName: runtimeInfo.openxrHostApplicationName ?? "",
|
|
121
122
|
openxrHostGraphicsApi: runtimeInfo.openxrHostGraphicsApi ?? "",
|
|
122
123
|
openxrHostAdapterLuid: runtimeInfo.openxrHostAdapterLuid ?? "",
|
|
123
124
|
openxrProtocolVersion: runtimeInfo.openxrProtocolVersion ?? 0,
|
|
125
|
+
openxrSubmittedFrameSequence: runtimeInfo.openxrSubmittedFrameSequence ?? 0,
|
|
126
|
+
openxrConsumedFrameSequence: runtimeInfo.openxrConsumedFrameSequence ?? 0,
|
|
124
127
|
openvrSceneApplicationState: runtimeInfo.openvrSceneApplicationState ?? "",
|
|
125
128
|
openvrSceneProcessId: runtimeInfo.openvrSceneProcessId ?? 0,
|
|
126
129
|
openvrSceneApplicationKey: runtimeInfo.openvrSceneApplicationKey ?? "",
|
|
@@ -211,6 +214,7 @@ export class VrBridge {
|
|
|
211
214
|
linuxOpenVRVisibleTexture = null;
|
|
212
215
|
windowsReadbackInFlight = false;
|
|
213
216
|
windowsReadbackPending = false;
|
|
217
|
+
windowsOpenXRTextures = [];
|
|
214
218
|
linuxReadbackInFlight = false;
|
|
215
219
|
linuxReadbackPending = false;
|
|
216
220
|
invalidationTimer = null;
|
|
@@ -242,6 +246,9 @@ export class VrBridge {
|
|
|
242
246
|
return;
|
|
243
247
|
}
|
|
244
248
|
this.linuxReadbackPending = false;
|
|
249
|
+
for (const retained of this.windowsOpenXRTextures)
|
|
250
|
+
releaseTexture(retained.texture);
|
|
251
|
+
this.windowsOpenXRTextures = [];
|
|
245
252
|
const offscreenContents = this.attachedWindow.webContents;
|
|
246
253
|
offscreenContents.removeListener("paint", this.onPaint);
|
|
247
254
|
this.attachedWindow = null;
|
|
@@ -472,6 +479,19 @@ export class VrBridge {
|
|
|
472
479
|
console.log(`VR overlay received first paint event (platform=${process.platform}, backend=${this.getSelectedBackend()}, hasTexture=${texture ? "yes" : "no"}, hasBitmap=${nativeImage ? "yes" : "no"}).`);
|
|
473
480
|
}
|
|
474
481
|
const runtimeInfo = this.getRuntimeInfo();
|
|
482
|
+
if (process.platform === "win32" && this.windowsOpenXRTextures.length > 0) {
|
|
483
|
+
const consumedSequence = runtimeInfo.openxrConsumedFrameSequence;
|
|
484
|
+
const pending = [];
|
|
485
|
+
for (const retained of this.windowsOpenXRTextures) {
|
|
486
|
+
if (retained.sequence <= consumedSequence) {
|
|
487
|
+
releaseTexture(retained.texture);
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
pending.push(retained);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
this.windowsOpenXRTextures = pending;
|
|
494
|
+
}
|
|
475
495
|
if (process.platform === "linux" &&
|
|
476
496
|
runtimeInfo.selectedBackend === "openvr" &&
|
|
477
497
|
isTruthyEnvironmentVariable("ELECTRON_VR_OPENVR_VULKAN_SOFTWARE")) {
|
|
@@ -548,9 +568,22 @@ export class VrBridge {
|
|
|
548
568
|
this.useWindowsSoftwareFallback(nativeImage, "Windows shared texture submission failed; falling back to software RGBA upload.");
|
|
549
569
|
}
|
|
550
570
|
}
|
|
551
|
-
else
|
|
552
|
-
|
|
553
|
-
|
|
571
|
+
else {
|
|
572
|
+
if (runtimeInfo.selectedBackend === "openxr" && runtimeInfo.openxrMode === "api-layer" &&
|
|
573
|
+
runtimeInfo.openxrHostGraphicsApi === "d3d11") {
|
|
574
|
+
const updatedRuntimeInfo = this.getRuntimeInfo();
|
|
575
|
+
if (updatedRuntimeInfo.openxrSubmittedFrameSequence > runtimeInfo.openxrSubmittedFrameSequence) {
|
|
576
|
+
this.windowsOpenXRTextures.push({
|
|
577
|
+
sequence: updatedRuntimeInfo.openxrSubmittedFrameSequence,
|
|
578
|
+
texture
|
|
579
|
+
});
|
|
580
|
+
releaseCurrentTexture = false;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
if (!this.loggedFirstWindowsSubmit) {
|
|
584
|
+
this.loggedFirstWindowsSubmit = true;
|
|
585
|
+
console.log("VR overlay submitted first Windows frame to the native bridge.");
|
|
586
|
+
}
|
|
554
587
|
}
|
|
555
588
|
}
|
|
556
589
|
else if (this.getSelectedBackend() === "openvr") {
|
package/dist/compatibility.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export type VRReadiness = "ready" | "setup-required" | "waiting-for-host" | "fal
|
|
|
4
4
|
export type VRLaunchVerdict = "works-now" | "action-required" | "incompatible";
|
|
5
5
|
export type VRFeatureSupport = "supported" | "unsupported" | "runtime-dependent";
|
|
6
6
|
export type VRIssueSeverity = "info" | "warning" | "error";
|
|
7
|
-
export type VRSetupAction = "install-openxr-api-layer" | "enable-openxr-api-layer" | "restart-openxr-apps" | "start-openxr-app" | "install-xr-runtime" | "use-supported-openxr-host" | "none";
|
|
7
|
+
export type VRSetupAction = "install-openxr-api-layer" | "reinstall-openxr-api-layer" | "enable-openxr-api-layer" | "restart-openxr-apps" | "start-openxr-app" | "install-xr-runtime" | "use-supported-openxr-host" | "none";
|
|
8
8
|
export interface VRFeatureCompatibility {
|
|
9
9
|
flatOverlay: VRFeatureSupport;
|
|
10
10
|
curvature: VRFeatureSupport;
|
package/dist/compatibility.js
CHANGED
|
@@ -37,6 +37,7 @@ export function analyzeVRCompatibility(runtime, context = {}) {
|
|
|
37
37
|
(context.architecture ?? process.arch) === "x64";
|
|
38
38
|
const layerInstalled = apiLayer?.installed ?? runtime.openxrApiLayerInstalled;
|
|
39
39
|
const layerEnabled = apiLayer?.enabled ?? runtime.openxrApiLayerEnabled;
|
|
40
|
+
const layerRequiresUpdate = apiLayer?.requiresUpdate ?? false;
|
|
40
41
|
let readiness = "unavailable";
|
|
41
42
|
let backendLabel = "No compatible VR backend";
|
|
42
43
|
let summary = "No compatible XR runtime is ready.";
|
|
@@ -56,9 +57,15 @@ export function analyzeVRCompatibility(runtime, context = {}) {
|
|
|
56
57
|
features = { ...realFeatures };
|
|
57
58
|
compatibleHostGraphicsApis = runtime.platform === "win32" ? ["D3D11", "D3D12"] : ["Vulkan", "OpenGL Xlib/GLX"];
|
|
58
59
|
backendLabel = "OpenXR application integration";
|
|
59
|
-
if (
|
|
60
|
+
if (layerRequiresUpdate) {
|
|
61
|
+
readiness = "setup-required";
|
|
62
|
+
summary = "OpenXR application integration must be updated before overlays can appear.";
|
|
63
|
+
recommendedAction = "reinstall-openxr-api-layer";
|
|
64
|
+
issues.push(issue("openxr-api-layer-update-required", "warning", "Update OpenXR integration", "Reinstall the per-user integration and restart OpenXR applications.", "reinstall-openxr-api-layer"));
|
|
65
|
+
}
|
|
66
|
+
else if (runtime.openxrCompanionConnected || runtime.openxrHostDetected) {
|
|
60
67
|
readiness = "ready";
|
|
61
|
-
summary =
|
|
68
|
+
summary = `${runtime.openxrCompanionConnected ? "Connected to" : "Detected"} ${runtime.openxrHostApplicationName || "an OpenXR application"} using ${runtime.openxrHostGraphicsApi || "a supported graphics API"}.`;
|
|
62
69
|
}
|
|
63
70
|
else if (!layerEnabled) {
|
|
64
71
|
readiness = "setup-required";
|
|
@@ -185,7 +192,7 @@ export function analyzeVRCompatibility(runtime, context = {}) {
|
|
|
185
192
|
canRenderOverlay,
|
|
186
193
|
isRealVrBackend: runtime.selectedBackend === "openxr" || runtime.selectedBackend === "openvr",
|
|
187
194
|
requiresApiLayer,
|
|
188
|
-
requiresOpenXRAppRestart: requiresApiLayer && (!runtime.openxrCompanionConnected || !layerEnabled),
|
|
195
|
+
requiresOpenXRAppRestart: requiresApiLayer && (!(runtime.openxrHostDetected || runtime.openxrCompanionConnected) || !layerEnabled),
|
|
189
196
|
apiLayer,
|
|
190
197
|
compatibleHostGraphicsApis,
|
|
191
198
|
features,
|
package/dist/openxrApiLayer.d.ts
CHANGED
package/dist/openxrApiLayer.js
CHANGED
|
@@ -84,6 +84,7 @@ export function parseOpenXRApiLayerStatus(output) {
|
|
|
84
84
|
installed: values.get("installed") === "true",
|
|
85
85
|
enabled: values.get("enabled") === "true",
|
|
86
86
|
registered: values.has("registered") ? values.get("registered") === "true" : null,
|
|
87
|
+
requiresUpdate: values.get("requires_update") === "true",
|
|
87
88
|
manifestPath: values.get("manifest") ?? "",
|
|
88
89
|
scope: values.get("scope") ?? "current-user"
|
|
89
90
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@covas-labs/electron-vr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Electron VR overlay bridge with OpenXR, OpenVR, and mock fallback backends.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"electron": ">=37"
|
|
23
23
|
},
|
|
24
24
|
"optionalDependencies": {
|
|
25
|
-
"@covas-labs/electron-vr-prebuilt-linux-x64": "0.
|
|
26
|
-
"@covas-labs/electron-vr-prebuilt-win32-x64": "0.
|
|
25
|
+
"@covas-labs/electron-vr-prebuilt-linux-x64": "0.7.0",
|
|
26
|
+
"@covas-labs/electron-vr-prebuilt-win32-x64": "0.7.0"
|
|
27
27
|
},
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"registry": "https://registry.npmjs.org",
|