瀏覽代碼

Prevent fatal error in WebXR when 'immersize-ar' loses and regains tracking

David Snopek 4 年之前
父節點
當前提交
a23fc126eb
共有 3 個文件被更改,包括 32 次插入10 次删除
  1. 13 1
      modules/webxr/native/library_godot_webxr.js
  2. 18 8
      modules/webxr/webxr_interface_js.cpp
  3. 1 1
      modules/webxr/webxr_interface_js.h

+ 13 - 1
modules/webxr/native/library_godot_webxr.js

@@ -380,6 +380,11 @@ const GodotWebXR = {
 				gl.deleteTexture(texture);
 			}
 			GodotWebXR.textures[i] = null;
+
+			const texture_id = GodotWebXR.texture_ids[i];
+			if (texture_id !== null) {
+				GL.textures[texture_id] = null;
+			}
 			GodotWebXR.texture_ids[i] = null;
 		}
 
@@ -460,7 +465,7 @@ const GodotWebXR = {
 	godot_webxr_get_external_texture_for_eye__proxy: 'sync',
 	godot_webxr_get_external_texture_for_eye__sig: 'ii',
 	godot_webxr_get_external_texture_for_eye: function (p_eye) {
-		if (!GodotWebXR.session || !GodotWebXR.pose) {
+		if (!GodotWebXR.session) {
 			return 0;
 		}
 
@@ -469,6 +474,13 @@ const GodotWebXR = {
 			return GodotWebXR.texture_ids[view_index];
 		}
 
+		// Check pose separately and after returning the cached texture id,
+		// because we won't get a pose in some cases if we lose tracking, and
+		// we don't want to return 0 just because tracking was lost.
+		if (!GodotWebXR.pose) {
+			return 0;
+		}
+
 		const glLayer = GodotWebXR.session.renderState.baseLayer;
 		const view = GodotWebXR.pose.views[view_index];
 		const viewport = glLayer.getViewport(view);

+ 18 - 8
modules/webxr/webxr_interface_js.cpp

@@ -78,6 +78,8 @@ void _emwebxr_on_session_failed(char *p_message) {
 	Ref<XRInterface> interface = xr_server->find_interface("WebXR");
 	ERR_FAIL_COND(interface.is_null());
 
+	interface->uninitialize();
+
 	String message = String(p_message);
 	interface->emit_signal("session_failed", message);
 }
@@ -224,6 +226,12 @@ bool WebXRInterfaceJS::initialize() {
 		// make this our primary interface
 		xr_server->set_primary_interface(this);
 
+		// Clear render_targetsize to make sure it gets reset to the new size.
+		// Clearing in uninitialize() doesn't work because a frame can still be
+		// rendered after it's called, which will fill render_targetsize again.
+		render_targetsize.width = 0;
+		render_targetsize.height = 0;
+
 		initialized = true;
 
 		godot_webxr_initialize(
@@ -277,22 +285,24 @@ Transform WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) {
 }
 
 Size2 WebXRInterfaceJS::get_render_targetsize() {
-	Size2 target_size;
+	if (render_targetsize.width != 0 && render_targetsize.height != 0) {
+		return render_targetsize;
+	}
 
 	int *js_size = godot_webxr_get_render_targetsize();
 	if (!initialized || js_size == nullptr) {
-		// As a default, use half the window size.
-		target_size = DisplayServer::get_singleton()->window_get_size();
-		target_size.width /= 2.0;
-		return target_size;
+		// As a temporary default (until WebXR is fully initialized), use half the window size.
+		Size2 temp = DisplayServer::get_singleton()->window_get_size();
+		temp.width /= 2.0;
+		return temp;
 	}
 
-	target_size.width = js_size[0];
-	target_size.height = js_size[1];
+	render_targetsize.width = js_size[0];
+	render_targetsize.height = js_size[1];
 
 	free(js_size);
 
-	return target_size;
+	return render_targetsize;
 };
 
 Transform WebXRInterfaceJS::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) {

+ 1 - 1
modules/webxr/webxr_interface_js.h

@@ -47,7 +47,6 @@ class WebXRInterfaceJS : public WebXRInterface {
 private:
 	bool initialized;
 
-	// @todo Should these really use enums instead of strings?
 	String session_mode;
 	String required_features;
 	String optional_features;
@@ -55,6 +54,7 @@ private:
 	String reference_space_type;
 
 	bool controllers_state[2];
+	Size2 render_targetsize;
 
 	Transform _js_matrix_to_transform(float *p_js_matrix);
 	void _update_tracker(int p_controller_id);