@covas-labs/electron-vr 0.6.0 → 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 CHANGED
@@ -106,6 +106,8 @@ await VROverlay.uninstallOpenXRApiLayer();
106
106
 
107
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.
108
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
+
109
111
  For product UI, prefer the combined readiness report instead of interpreting raw probe fields:
110
112
 
111
113
  ```ts
@@ -115,4 +117,4 @@ console.log(report.launch.verdict, report.launch.requiredActions);
115
117
 
116
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.
117
119
 
118
- `getRuntimeInfo()` also includes `openvrRuntimeInstalled`, `openvrRuntimePath`, `openxrMode`, API-layer installation and connection state, protocol version, and connected OpenXR host metadata. `probeMode` includes the backend-selection decision.
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 if (!this.loggedFirstWindowsSubmit) {
552
- this.loggedFirstWindowsSubmit = true;
553
- console.log("VR overlay submitted first Windows frame to the native bridge.");
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") {
@@ -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;
@@ -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 (runtime.openxrCompanionConnected) {
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 = `Connected to ${runtime.openxrHostApplicationName || "an OpenXR application"} using ${runtime.openxrHostGraphicsApi || "a supported graphics API"}.`;
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,
@@ -2,6 +2,7 @@ export interface OpenXRApiLayerStatus {
2
2
  installed: boolean;
3
3
  enabled: boolean;
4
4
  registered: boolean | null;
5
+ requiresUpdate: boolean;
5
6
  manifestPath: string;
6
7
  scope: string;
7
8
  }
@@ -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.6.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.6.0",
26
- "@covas-labs/electron-vr-prebuilt-win32-x64": "0.6.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",