Преглед изворни кода

Renderer agnostic motion vector rendering/OpenXR changes

devloglogan пре 7 месеци
родитељ
комит
3deb5884d7

+ 1 - 1
drivers/gles3/storage/texture_storage.cpp

@@ -2481,7 +2481,7 @@ Size2i TextureStorage::render_target_get_size(RID p_render_target) const {
 	return rt->size;
 }
 
-void TextureStorage::render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) {
+void TextureStorage::render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture, RID p_velocity_depth_texture) {
 	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
 	ERR_FAIL_NULL(rt);
 	ERR_FAIL_COND(rt->direct_to_screen);

+ 5 - 1
drivers/gles3/storage/texture_storage.h

@@ -685,13 +685,17 @@ public:
 	virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {}
 	virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); }
 
-	virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) override;
+	virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture, RID p_velocity_depth_texture) override;
 	virtual RID render_target_get_override_color(RID p_render_target) const override;
 	virtual RID render_target_get_override_depth(RID p_render_target) const override;
 	virtual RID render_target_get_override_velocity(RID p_render_target) const override;
+	virtual RID render_target_get_override_velocity_depth(RID p_render_target) const override { return RID(); }
 
 	virtual RID render_target_get_texture(RID p_render_target) override;
 
+	virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) override {}
+	virtual Size2i render_target_get_velocity_target_size(RID p_render_target) const override { return Size2i(); }
+
 	void bind_framebuffer(GLuint framebuffer) {
 		glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
 	}

+ 103 - 0
modules/openxr/doc_classes/OpenXRAPIExtension.xml

@@ -82,12 +82,32 @@
 				Returns the predicted display timing for the current frame.
 			</description>
 		</method>
+		<method name="get_render_state_z_far">
+			<return type="float" />
+			<description>
+				Returns the far boundary value of the camera frustum.
+				[b]Note:[/b] This is only accessible in the render thread.
+			</description>
+		</method>
+		<method name="get_render_state_z_near">
+			<return type="float" />
+			<description>
+				Returns the near boundary value of the camera frustum.
+				[b]Note:[/b] This is only accessible in the render thread.
+			</description>
+		</method>
 		<method name="get_session">
 			<return type="int" />
 			<description>
 				Returns the OpenXR session, which is an [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSession.html]XrSession[/url] cast to an integer.
 			</description>
 		</method>
+		<method name="get_supported_swapchain_formats">
+			<return type="PackedInt64Array" />
+			<description>
+				Returns an array of supported swapchain formats.
+			</description>
+		</method>
 		<method name="get_swapchain_format_name">
 			<return type="String" />
 			<param index="0" name="swapchain_format" type="int" />
@@ -133,6 +153,54 @@
 				Returns [code]true[/code] if OpenXR is enabled.
 			</description>
 		</method>
+		<method name="openxr_swapchain_acquire">
+			<return type="void" />
+			<param index="0" name="swapchain" type="int" />
+			<description>
+				Acquires the image of the provided swapchain.
+			</description>
+		</method>
+		<method name="openxr_swapchain_create">
+			<return type="int" />
+			<param index="0" name="create_flags" type="int" />
+			<param index="1" name="usage_flags" type="int" />
+			<param index="2" name="swapchain_format" type="int" />
+			<param index="3" name="width" type="int" />
+			<param index="4" name="height" type="int" />
+			<param index="5" name="sample_count" type="int" />
+			<param index="6" name="array_size" type="int" />
+			<description>
+				Returns a pointer to a new swapchain created using the provided parameters.
+			</description>
+		</method>
+		<method name="openxr_swapchain_free">
+			<return type="void" />
+			<param index="0" name="swapchain" type="int" />
+			<description>
+				Destroys the provided swapchain and frees it from memory.
+			</description>
+		</method>
+		<method name="openxr_swapchain_get_image">
+			<return type="RID" />
+			<param index="0" name="swapchain" type="int" />
+			<description>
+				Returns the RID of the provided swapchain's image.
+			</description>
+		</method>
+		<method name="openxr_swapchain_get_swapchain">
+			<return type="int" />
+			<param index="0" name="swapchain" type="int" />
+			<description>
+				Returns the [code]XrSwapchain[/code] handle of the provided swapchain.
+			</description>
+		</method>
+		<method name="openxr_swapchain_release">
+			<return type="void" />
+			<param index="0" name="swapchain" type="int" />
+			<description>
+				Releases the image of the provided swapchain.
+			</description>
+		</method>
 		<method name="register_composition_layer_provider">
 			<return type="void" />
 			<param index="0" name="extension" type="OpenXRExtensionWrapperExtension" />
@@ -140,6 +208,13 @@
 				Registers the given extension as a composition layer provider.
 			</description>
 		</method>
+		<method name="register_projection_views_extension">
+			<return type="void" />
+			<param index="0" name="extension" type="OpenXRExtensionWrapperExtension" />
+			<description>
+				Registers the given extension as a provider of additional data structures to projections views.
+			</description>
+		</method>
 		<method name="set_emulate_environment_blend_mode_alpha_blend">
 			<return type="void" />
 			<param index="0" name="enabled" type="bool" />
@@ -156,6 +231,27 @@
 				Set the object name of an OpenXR object, used for debug output. [param object_type] must be a valid OpenXR [code]XrObjectType[/code] enum and [param object_handle] must be a valid OpenXR object handle.
 			</description>
 		</method>
+		<method name="set_velocity_depth_texture">
+			<return type="void" />
+			<param index="0" name="render_target" type="RID" />
+			<description>
+				Sets the render target of the velocity depth texture.
+			</description>
+		</method>
+		<method name="set_velocity_target_size">
+			<return type="void" />
+			<param index="0" name="target_size" type="Vector2i" />
+			<description>
+				Sets the target size of the velocity and velocity depth textures.
+			</description>
+		</method>
+		<method name="set_velocity_texture">
+			<return type="void" />
+			<param index="0" name="render_target" type="RID" />
+			<description>
+				Sets the render target of the velocity texture.
+			</description>
+		</method>
 		<method name="transform_from_pose">
 			<return type="Transform3D" />
 			<param index="0" name="pose" type="const void*" />
@@ -170,6 +266,13 @@
 				Unregisters the given extension as a composition layer provider.
 			</description>
 		</method>
+		<method name="unregister_projection_views_extension">
+			<return type="void" />
+			<param index="0" name="extension" type="OpenXRExtensionWrapperExtension" />
+			<description>
+				Unregisters the given extension as a provider of additional data structures to projections views.
+			</description>
+		</method>
 		<method name="xr_result">
 			<return type="bool" />
 			<param index="0" name="result" type="int" />

+ 8 - 0
modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml

@@ -217,6 +217,14 @@
 				Adds additional data structures when the OpenXR instance is created.
 			</description>
 		</method>
+		<method name="_set_projection_views_and_get_next_pointer" qualifiers="virtual">
+			<return type="int" />
+			<param index="0" name="view_index" type="int" />
+			<param index="1" name="next_pointer" type="void*" />
+			<description>
+				Adds additional data structures to the projection view of the given [param view_index].
+			</description>
+		</method>
 		<method name="_set_session_create_and_get_next_pointer" qualifiers="virtual">
 			<return type="int" />
 			<param index="0" name="next_pointer" type="void*" />

+ 2 - 2
modules/openxr/extensions/openxr_composition_layer_extension.cpp

@@ -210,7 +210,7 @@ void OpenXRViewportCompositionLayerProvider::set_viewport(RID p_viewport, Size2i
 	if (subviewport.viewport != p_viewport) {
 		if (subviewport.viewport.is_valid()) {
 			RID rt = rs->viewport_get_render_target(subviewport.viewport);
-			RSG::texture_storage->render_target_set_override(rt, RID(), RID(), RID());
+			RSG::texture_storage->render_target_set_override(rt, RID(), RID(), RID(), RID());
 		}
 
 		subviewport.viewport = p_viewport;
@@ -323,7 +323,7 @@ void OpenXRViewportCompositionLayerProvider::on_pre_render() {
 			if (update_and_acquire_swapchain(update_mode == RS::VIEWPORT_UPDATE_ONCE)) {
 				// Render to our XR swapchain image.
 				RID rt = rs->viewport_get_render_target(subviewport.viewport);
-				RSG::texture_storage->render_target_set_override(rt, get_current_swapchain_texture(), RID(), RID());
+				RSG::texture_storage->render_target_set_override(rt, get_current_swapchain_texture(), RID(), RID(), RID());
 			}
 		}
 	}

+ 1 - 0
modules/openxr/extensions/openxr_extension_wrapper.h

@@ -62,6 +62,7 @@ public:
 	virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when we create our OpenXR session.
 	virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when creating OpenXR swap chains.
 	virtual void *set_hand_joint_locations_and_get_next_pointer(int p_hand_index, void *p_next_pointer) { return p_next_pointer; }
+	virtual void *set_projection_views_and_get_next_pointer(int p_view_index, void *p_next_pointer) { return p_next_pointer; }
 
 	virtual PackedStringArray get_suggested_tracker_names() { return PackedStringArray(); }
 

+ 11 - 0
modules/openxr/extensions/openxr_extension_wrapper_extension.cpp

@@ -39,6 +39,7 @@ void OpenXRExtensionWrapperExtension::_bind_methods() {
 	GDVIRTUAL_BIND(_set_session_create_and_get_next_pointer, "next_pointer");
 	GDVIRTUAL_BIND(_set_swapchain_create_info_and_get_next_pointer, "next_pointer");
 	GDVIRTUAL_BIND(_set_hand_joint_locations_and_get_next_pointer, "hand_index", "next_pointer");
+	GDVIRTUAL_BIND(_set_projection_views_and_get_next_pointer, "view_index", "next_pointer");
 	GDVIRTUAL_BIND(_get_composition_layer_count);
 	GDVIRTUAL_BIND(_get_composition_layer, "index");
 	GDVIRTUAL_BIND(_get_composition_layer_order, "index");
@@ -140,6 +141,16 @@ void *OpenXRExtensionWrapperExtension::set_hand_joint_locations_and_get_next_poi
 	return nullptr;
 }
 
+void *OpenXRExtensionWrapperExtension::set_projection_views_and_get_next_pointer(int p_view_index, void *p_next_pointer) {
+	uint64_t pointer = 0;
+
+	if (GDVIRTUAL_CALL(_set_projection_views_and_get_next_pointer, p_view_index, GDExtensionPtr<void>(p_next_pointer), pointer)) {
+		return reinterpret_cast<void *>(pointer);
+	}
+
+	return nullptr;
+}
+
 PackedStringArray OpenXRExtensionWrapperExtension::get_suggested_tracker_names() {
 	PackedStringArray ret;
 

+ 2 - 0
modules/openxr/extensions/openxr_extension_wrapper_extension.h

@@ -60,6 +60,7 @@ public:
 	virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override;
 	virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) override;
 	virtual void *set_hand_joint_locations_and_get_next_pointer(int p_hand_index, void *p_next_pointer) override;
+	virtual void *set_projection_views_and_get_next_pointer(int p_view_index, void *p_next_pointer) override;
 
 	virtual int get_composition_layer_count() override;
 	virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) override;
@@ -71,6 +72,7 @@ public:
 	GDVIRTUAL1R(uint64_t, _set_session_create_and_get_next_pointer, GDExtensionPtr<void>);
 	GDVIRTUAL1R(uint64_t, _set_swapchain_create_info_and_get_next_pointer, GDExtensionPtr<void>);
 	GDVIRTUAL2R(uint64_t, _set_hand_joint_locations_and_get_next_pointer, int, GDExtensionPtr<void>);
+	GDVIRTUAL2R(uint64_t, _set_projection_views_and_get_next_pointer, int, GDExtensionPtr<void>);
 	GDVIRTUAL0R(int, _get_composition_layer_count);
 	GDVIRTUAL1R(uint64_t, _get_composition_layer, int);
 	GDVIRTUAL1R(int, _get_composition_layer_order, int);

+ 57 - 0
modules/openxr/openxr_api.cpp

@@ -1916,6 +1916,9 @@ bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z
 		}
 	}
 
+	render_state.z_near = p_z_near;
+	render_state.z_far = p_z_far;
+
 	// now update our projection
 	return graphics_extension->create_projection_fov(render_state.views[p_view].fov, p_z_near, p_z_far, p_camera_matrix);
 }
@@ -2343,6 +2346,30 @@ RID OpenXRAPI::get_depth_texture() {
 	}
 }
 
+void OpenXRAPI::set_velocity_texture(RID p_render_target) {
+	velocity_texture = p_render_target;
+}
+
+RID OpenXRAPI::get_velocity_texture() {
+	return velocity_texture;
+}
+
+void OpenXRAPI::set_velocity_depth_texture(RID p_render_target) {
+	velocity_depth_texture = p_render_target;
+}
+
+RID OpenXRAPI::get_velocity_depth_texture() {
+	return velocity_depth_texture;
+}
+
+void OpenXRAPI::set_velocity_target_size(const Size2i &p_target_size) {
+	velocity_target_size = p_target_size;
+}
+
+Size2i OpenXRAPI::get_velocity_target_size() {
+	return velocity_target_size;
+}
+
 void OpenXRAPI::post_draw_viewport(RID p_render_target) {
 	// Must be called from rendering thread!
 	ERR_NOT_ON_RENDER_THREAD;
@@ -2448,6 +2475,20 @@ void OpenXRAPI::end_frame() {
 		render_state.view_count, // viewCount
 		render_state.projection_views, // views
 	};
+
+	if (projection_views_extensions.size() > 0) {
+		for (uint32_t v = 0; v < render_state.view_count; v++) {
+			void *next_pointer = nullptr;
+			for (OpenXRExtensionWrapper *wrapper : projection_views_extensions) {
+				void *np = wrapper->set_projection_views_and_get_next_pointer(v, next_pointer);
+				if (np != nullptr) {
+					next_pointer = np;
+				}
+			}
+			render_state.projection_views[v].next = next_pointer;
+		}
+	}
+
 	ordered_layers_list.push_back({ (const XrCompositionLayerBaseHeader *)&projection_layer, 0 });
 
 	// Sort our layers.
@@ -2578,6 +2619,14 @@ Size2 OpenXRAPI::get_play_space_bounds() const {
 	return ret;
 }
 
+PackedInt64Array OpenXRAPI::get_supported_swapchain_formats() {
+	PackedInt64Array supported_swapchain_list;
+	for (uint32_t i = 0; i < num_swapchain_formats; i++) {
+		supported_swapchain_list.push_back(supported_swapchain_formats[i]);
+	}
+	return supported_swapchain_list;
+}
+
 OpenXRAPI::OpenXRAPI() {
 	// OpenXRAPI is only constructed if OpenXR is enabled.
 	singleton = this;
@@ -3499,6 +3548,14 @@ void OpenXRAPI::unregister_composition_layer_provider(OpenXRCompositionLayerProv
 	composition_layer_providers.erase(provider);
 }
 
+void OpenXRAPI::register_projection_views_extension(OpenXRExtensionWrapper *p_extension) {
+	projection_views_extensions.append(p_extension);
+}
+
+void OpenXRAPI::unregister_projection_views_extension(OpenXRExtensionWrapper *p_extension) {
+	projection_views_extensions.erase(p_extension);
+}
+
 const XrEnvironmentBlendMode *OpenXRAPI::get_supported_environment_blend_modes(uint32_t &count) {
 	count = num_supported_environment_blend_modes;
 	return supported_environment_blend_modes;

+ 23 - 1
modules/openxr/openxr_api.h

@@ -102,6 +102,9 @@ private:
 	// composition layer providers
 	Vector<OpenXRCompositionLayerProvider *> composition_layer_providers;
 
+	// projection views extensions
+	Vector<OpenXRExtensionWrapper *> projection_views_extensions;
+
 	// view configuration
 	uint32_t num_view_configuration_types = 0;
 	XrViewConfigurationType *supported_view_configuration_types = nullptr;
@@ -153,7 +156,6 @@ private:
 	enum OpenXRSwapChainTypes {
 		OPENXR_SWAPCHAIN_COLOR,
 		OPENXR_SWAPCHAIN_DEPTH,
-		// OPENXR_SWAPCHAIN_VELOCITY,
 		OPENXR_SWAPCHAIN_MAX
 	};
 
@@ -165,6 +167,10 @@ private:
 	XrSpace view_space = XR_NULL_HANDLE;
 	XRPose::TrackingConfidence head_pose_confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE;
 
+	RID velocity_texture;
+	RID velocity_depth_texture;
+	Size2i velocity_target_size;
+
 	// When LOCAL_FLOOR isn't supported, we use an approach based on the example code in the
 	// OpenXR spec in order to emulate it.
 	// See: https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_EXT_local_floor
@@ -345,6 +351,9 @@ private:
 		bool submit_depth_buffer = false; // if set to true we submit depth buffers to OpenXR if a suitable extension is enabled.
 		bool view_pose_valid = false;
 
+		double z_near = 0.0;
+		double z_far = 0.0;
+
 		Size2i main_swapchain_size;
 		OpenXRSwapChainInfo main_swapchains[OPENXR_SWAPCHAIN_MAX];
 	} render_state;
@@ -477,6 +486,12 @@ public:
 	XrSwapchain get_color_swapchain();
 	RID get_color_texture();
 	RID get_depth_texture();
+	void set_velocity_texture(RID p_render_target);
+	RID get_velocity_texture();
+	void set_velocity_depth_texture(RID p_render_target);
+	RID get_velocity_depth_texture();
+	void set_velocity_target_size(const Size2i &p_target_size);
+	Size2i get_velocity_target_size();
 	void post_draw_viewport(RID p_render_target);
 	void end_frame();
 
@@ -502,9 +517,13 @@ public:
 	Size2 get_play_space_bounds() const;
 
 	// swapchains
+	PackedInt64Array get_supported_swapchain_formats();
 	int64_t get_color_swapchain_format() const { return color_swapchain_format; }
 	int64_t get_depth_swapchain_format() const { return depth_swapchain_format; }
 
+	double get_render_state_z_near() const { return render_state.z_near; }
+	double get_render_state_z_far() const { return render_state.z_far; }
+
 	// action map
 	String get_default_action_map_resource_name();
 
@@ -542,6 +561,9 @@ public:
 	void register_composition_layer_provider(OpenXRCompositionLayerProvider *provider);
 	void unregister_composition_layer_provider(OpenXRCompositionLayerProvider *provider);
 
+	void register_projection_views_extension(OpenXRExtensionWrapper *p_extension);
+	void unregister_projection_views_extension(OpenXRExtensionWrapper *p_extension);
+
 	const XrEnvironmentBlendMode *get_supported_environment_blend_modes(uint32_t &count);
 	bool is_environment_blend_mode_supported(XrEnvironmentBlendMode p_blend_mode) const;
 	bool set_environment_blend_mode(XrEnvironmentBlendMode p_blend_mode);

+ 107 - 0
modules/openxr/openxr_api_extension.cpp

@@ -61,6 +61,25 @@ void OpenXRAPIExtension::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("register_composition_layer_provider", "extension"), &OpenXRAPIExtension::register_composition_layer_provider);
 	ClassDB::bind_method(D_METHOD("unregister_composition_layer_provider", "extension"), &OpenXRAPIExtension::unregister_composition_layer_provider);
 
+	ClassDB::bind_method(D_METHOD("register_projection_views_extension", "extension"), &OpenXRAPIExtension::register_projection_views_extension);
+	ClassDB::bind_method(D_METHOD("unregister_projection_views_extension", "extension"), &OpenXRAPIExtension::unregister_projection_views_extension);
+
+	ClassDB::bind_method(D_METHOD("get_render_state_z_near"), &OpenXRAPIExtension::get_render_state_z_near);
+	ClassDB::bind_method(D_METHOD("get_render_state_z_far"), &OpenXRAPIExtension::get_render_state_z_far);
+
+	ClassDB::bind_method(D_METHOD("set_velocity_texture", "render_target"), &OpenXRAPIExtension::set_velocity_texture);
+	ClassDB::bind_method(D_METHOD("set_velocity_depth_texture", "render_target"), &OpenXRAPIExtension::set_velocity_depth_texture);
+	ClassDB::bind_method(D_METHOD("set_velocity_target_size", "target_size"), &OpenXRAPIExtension::set_velocity_target_size);
+
+	ClassDB::bind_method(D_METHOD("get_supported_swapchain_formats"), &OpenXRAPIExtension::get_supported_swapchain_formats);
+
+	ClassDB::bind_method(D_METHOD("openxr_swapchain_create", "create_flags", "usage_flags", "swapchain_format", "width", "height", "sample_count", "array_size"), &OpenXRAPIExtension::openxr_swapchain_create);
+	ClassDB::bind_method(D_METHOD("openxr_swapchain_free", "swapchain"), &OpenXRAPIExtension::openxr_swapchain_free);
+	ClassDB::bind_method(D_METHOD("openxr_swapchain_get_swapchain", "swapchain"), &OpenXRAPIExtension::openxr_swapchain_get_swapchain);
+	ClassDB::bind_method(D_METHOD("openxr_swapchain_acquire", "swapchain"), &OpenXRAPIExtension::openxr_swapchain_acquire);
+	ClassDB::bind_method(D_METHOD("openxr_swapchain_get_image", "swapchain"), &OpenXRAPIExtension::openxr_swapchain_get_image);
+	ClassDB::bind_method(D_METHOD("openxr_swapchain_release", "swapchain"), &OpenXRAPIExtension::openxr_swapchain_release);
+
 	ClassDB::bind_method(D_METHOD("set_emulate_environment_blend_mode_alpha_blend", "enabled"), &OpenXRAPIExtension::set_emulate_environment_blend_mode_alpha_blend);
 	ClassDB::bind_method(D_METHOD("is_environment_blend_mode_alpha_supported"), &OpenXRAPIExtension::is_environment_blend_mode_alpha_blend_supported);
 
@@ -193,6 +212,94 @@ void OpenXRAPIExtension::unregister_composition_layer_provider(OpenXRExtensionWr
 	OpenXRAPI::get_singleton()->unregister_composition_layer_provider(p_extension);
 }
 
+void OpenXRAPIExtension::register_projection_views_extension(OpenXRExtensionWrapperExtension *p_extension) {
+	ERR_FAIL_NULL(OpenXRAPI::get_singleton());
+	OpenXRAPI::get_singleton()->register_projection_views_extension(p_extension);
+}
+
+void OpenXRAPIExtension::unregister_projection_views_extension(OpenXRExtensionWrapperExtension *p_extension) {
+	ERR_FAIL_NULL(OpenXRAPI::get_singleton());
+	OpenXRAPI::get_singleton()->unregister_projection_views_extension(p_extension);
+}
+
+double OpenXRAPIExtension::get_render_state_z_near() {
+	ERR_NOT_ON_RENDER_THREAD_V(0.0);
+	ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0.0);
+	return OpenXRAPI::get_singleton()->get_render_state_z_near();
+}
+
+double OpenXRAPIExtension::get_render_state_z_far() {
+	ERR_NOT_ON_RENDER_THREAD_V(0.0);
+	ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0.0);
+	return OpenXRAPI::get_singleton()->get_render_state_z_far();
+}
+
+void OpenXRAPIExtension::set_velocity_texture(RID p_render_target) {
+	ERR_FAIL_NULL(OpenXRAPI::get_singleton());
+	OpenXRAPI::get_singleton()->set_velocity_texture(p_render_target);
+}
+
+void OpenXRAPIExtension::set_velocity_depth_texture(RID p_render_target) {
+	ERR_FAIL_NULL(OpenXRAPI::get_singleton());
+	OpenXRAPI::get_singleton()->set_velocity_depth_texture(p_render_target);
+}
+
+void OpenXRAPIExtension::set_velocity_target_size(const Size2i &p_target_size) {
+	ERR_FAIL_NULL(OpenXRAPI::get_singleton());
+	OpenXRAPI::get_singleton()->set_velocity_target_size(p_target_size);
+}
+
+PackedInt64Array OpenXRAPIExtension::get_supported_swapchain_formats() {
+	ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), PackedInt64Array());
+	return OpenXRAPI::get_singleton()->get_supported_swapchain_formats();
+}
+
+uint64_t OpenXRAPIExtension::openxr_swapchain_create(XrSwapchainCreateFlags p_create_flags, XrSwapchainUsageFlags p_usage_flags, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size) {
+	ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
+
+	OpenXRAPI::OpenXRSwapChainInfo *new_swapchain_info = memnew(OpenXRAPI::OpenXRSwapChainInfo);
+	new_swapchain_info->create(p_create_flags, p_usage_flags, p_swapchain_format, p_width, p_height, p_sample_count, p_array_size);
+	return reinterpret_cast<uint64_t>(new_swapchain_info);
+}
+
+void OpenXRAPIExtension::openxr_swapchain_free(uint64_t p_swapchain_info) {
+	ERR_FAIL_NULL(OpenXRAPI::get_singleton());
+
+	OpenXRAPI::OpenXRSwapChainInfo *swapchain_info = reinterpret_cast<OpenXRAPI::OpenXRSwapChainInfo *>(p_swapchain_info);
+	swapchain_info->free();
+	memfree(swapchain_info);
+}
+
+uint64_t OpenXRAPIExtension::openxr_swapchain_get_swapchain(uint64_t p_swapchain_info) {
+	ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
+
+	OpenXRAPI::OpenXRSwapChainInfo *swapchain_info = reinterpret_cast<OpenXRAPI::OpenXRSwapChainInfo *>(p_swapchain_info);
+	XrSwapchain swapchain = swapchain_info->get_swapchain();
+	return reinterpret_cast<uint64_t>(swapchain);
+}
+
+void OpenXRAPIExtension::openxr_swapchain_acquire(uint64_t p_swapchain_info) {
+	ERR_FAIL_NULL(OpenXRAPI::get_singleton());
+
+	OpenXRAPI::OpenXRSwapChainInfo *swapchain_info = reinterpret_cast<OpenXRAPI::OpenXRSwapChainInfo *>(p_swapchain_info);
+	bool should_render = true; // Can ignore should_render.
+	swapchain_info->acquire(should_render);
+}
+
+RID OpenXRAPIExtension::openxr_swapchain_get_image(uint64_t p_swapchain_info) {
+	ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), RID());
+
+	OpenXRAPI::OpenXRSwapChainInfo *swapchain_info = reinterpret_cast<OpenXRAPI::OpenXRSwapChainInfo *>(p_swapchain_info);
+	return swapchain_info->get_image();
+}
+
+void OpenXRAPIExtension::openxr_swapchain_release(uint64_t p_swapchain_info) {
+	ERR_FAIL_NULL(OpenXRAPI::get_singleton());
+
+	OpenXRAPI::OpenXRSwapChainInfo *swapchain_info = reinterpret_cast<OpenXRAPI::OpenXRSwapChainInfo *>(p_swapchain_info);
+	swapchain_info->release();
+}
+
 void OpenXRAPIExtension::set_emulate_environment_blend_mode_alpha_blend(bool p_enabled) {
 	ERR_FAIL_NULL(OpenXRAPI::get_singleton());
 	OpenXRAPI::get_singleton()->set_emulate_environment_blend_mode_alpha_blend(p_enabled);

+ 19 - 0
modules/openxr/openxr_api_extension.h

@@ -82,6 +82,25 @@ public:
 	void register_composition_layer_provider(OpenXRExtensionWrapperExtension *p_extension);
 	void unregister_composition_layer_provider(OpenXRExtensionWrapperExtension *p_extension);
 
+	void register_projection_views_extension(OpenXRExtensionWrapperExtension *p_extension);
+	void unregister_projection_views_extension(OpenXRExtensionWrapperExtension *p_extension);
+
+	double get_render_state_z_near();
+	double get_render_state_z_far();
+
+	void set_velocity_texture(RID p_render_target);
+	void set_velocity_depth_texture(RID p_render_target);
+	void set_velocity_target_size(const Size2i &p_target_size);
+
+	PackedInt64Array get_supported_swapchain_formats();
+
+	uint64_t openxr_swapchain_create(XrSwapchainCreateFlags p_create_flags, XrSwapchainUsageFlags p_usage_flags, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size);
+	void openxr_swapchain_free(uint64_t p_swapchain_info);
+	uint64_t openxr_swapchain_get_swapchain(uint64_t p_swapchain_info);
+	void openxr_swapchain_acquire(uint64_t p_swapchain_info);
+	RID openxr_swapchain_get_image(uint64_t p_swapchain_info);
+	void openxr_swapchain_release(uint64_t p_swapchain_info);
+
 	enum OpenXRAlphaBlendModeSupport {
 		OPENXR_ALPHA_BLEND_MODE_SUPPORT_NONE = 0,
 		OPENXR_ALPHA_BLEND_MODE_SUPPORT_REAL = 1,

+ 24 - 0
modules/openxr/openxr_interface.cpp

@@ -1053,6 +1053,30 @@ RID OpenXRInterface::get_depth_texture() {
 	}
 }
 
+RID OpenXRInterface::get_velocity_texture() {
+	if (openxr_api) {
+		return openxr_api->get_velocity_texture();
+	} else {
+		return RID();
+	}
+}
+
+RID OpenXRInterface::get_velocity_depth_texture() {
+	if (openxr_api) {
+		return openxr_api->get_velocity_depth_texture();
+	} else {
+		return RID();
+	}
+}
+
+Size2i OpenXRInterface::get_velocity_target_size() {
+	if (openxr_api) {
+		return openxr_api->get_velocity_target_size();
+	} else {
+		return Size2i();
+	}
+}
+
 void OpenXRInterface::handle_hand_tracking(const String &p_path, OpenXRHandTrackingExtension::HandTrackedHands p_hand) {
 	OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
 	if (hand_tracking_ext && hand_tracking_ext->get_active()) {

+ 3 - 0
modules/openxr/openxr_interface.h

@@ -185,6 +185,9 @@ public:
 
 	virtual RID get_color_texture() override;
 	virtual RID get_depth_texture() override;
+	virtual RID get_velocity_texture() override;
+	virtual RID get_velocity_depth_texture() override;
+	virtual Size2i get_velocity_target_size() override;
 
 	virtual void process() override;
 	virtual void pre_render() override;

+ 1 - 1
scene/main/viewport.cpp

@@ -4527,7 +4527,7 @@ void Viewport::set_use_xr(bool p_use_xr) {
 
 			// Reset render target override textures.
 			RID rt = RS::get_singleton()->viewport_get_render_target(viewport);
-			RSG::texture_storage->render_target_set_override(rt, RID(), RID(), RID());
+			RSG::texture_storage->render_target_set_override(rt, RID(), RID(), RID(), RID());
 		}
 	}
 }

+ 5 - 1
servers/rendering/dummy/storage/texture_storage.h

@@ -200,12 +200,16 @@ public:
 	virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {}
 	virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); }
 
-	virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) override {}
+	virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture, RID p_velocity_depth_texture) override {}
 	virtual RID render_target_get_override_color(RID p_render_target) const override { return RID(); }
 	virtual RID render_target_get_override_depth(RID p_render_target) const override { return RID(); }
 	virtual RID render_target_get_override_velocity(RID p_render_target) const override { return RID(); }
+	virtual RID render_target_get_override_velocity_depth(RID p_render_target) const override { return RID(); }
 
 	virtual RID render_target_get_texture(RID p_render_target) override { return RID(); }
+
+	virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) override {}
+	virtual Size2i render_target_get_velocity_target_size(RID p_render_target) const override { return Size2i(0, 0); }
 };
 
 } // namespace RendererDummy

+ 1 - 1
servers/rendering/renderer_rd/storage_rd/texture_storage.cpp

@@ -3436,7 +3436,7 @@ RID TextureStorage::render_target_get_texture(RID p_render_target) {
 	return rt->texture;
 }
 
-void TextureStorage::render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) {
+void TextureStorage::render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture, RID p_velocity_depth_texture) {
 	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
 	ERR_FAIL_NULL(rt);
 

+ 5 - 1
servers/rendering/renderer_rd/storage_rd/texture_storage.h

@@ -779,15 +779,19 @@ public:
 	virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override;
 	virtual RID render_target_get_vrs_texture(RID p_render_target) const override;
 
-	virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) override;
+	virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture, RID p_velocity_depth_texture) override;
 	virtual RID render_target_get_override_color(RID p_render_target) const override;
 	virtual RID render_target_get_override_depth(RID p_render_target) const override;
 	RID render_target_get_override_depth_slice(RID p_render_target, const uint32_t p_layer) const;
 	virtual RID render_target_get_override_velocity(RID p_render_target) const override;
 	RID render_target_get_override_velocity_slice(RID p_render_target, const uint32_t p_layer) const;
+	virtual RID render_target_get_override_velocity_depth(RID p_render_target) const override { return RID(); }
 
 	virtual RID render_target_get_texture(RID p_render_target) override;
 
+	virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) override {}
+	virtual Size2i render_target_get_velocity_target_size(RID p_render_target) const override { return Size2i(0, 0); }
+
 	RID render_target_get_rd_framebuffer(RID p_render_target);
 	RID render_target_get_rd_texture(RID p_render_target);
 	RID render_target_get_rd_texture_slice(RID p_render_target, uint32_t p_layer);

+ 30 - 2
servers/rendering/renderer_viewport.cpp

@@ -789,7 +789,16 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
 				RSG::texture_storage->render_target_set_override(vp->render_target,
 						xr_interface->get_color_texture(),
 						xr_interface->get_depth_texture(),
-						xr_interface->get_velocity_texture());
+						xr_interface->get_velocity_texture(),
+						xr_interface->get_velocity_depth_texture());
+
+				RSG::texture_storage->render_target_set_velocity_target_size(vp->render_target, xr_interface->get_velocity_target_size());
+
+				if (xr_interface->get_velocity_texture().is_valid()) {
+					viewport_set_force_motion_vectors(vp->self, true);
+				} else {
+					viewport_set_force_motion_vectors(vp->self, false);
+				}
 
 				// render...
 				RSG::scene->set_debug_draw_mode(vp->debug_draw);
@@ -990,7 +999,7 @@ void RendererViewport::_viewport_set_size(Viewport *p_viewport, int p_width, int
 }
 
 bool RendererViewport::_viewport_requires_motion_vectors(Viewport *p_viewport) {
-	return p_viewport->use_taa || p_viewport->scaling_3d_mode == RenderingServer::VIEWPORT_SCALING_3D_MODE_FSR2 || p_viewport->debug_draw == RenderingServer::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS;
+	return p_viewport->use_taa || p_viewport->scaling_3d_mode == RenderingServer::VIEWPORT_SCALING_3D_MODE_FSR2 || p_viewport->debug_draw == RenderingServer::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS || p_viewport->force_motion_vectors;
 }
 
 void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
@@ -1338,6 +1347,25 @@ void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_deb
 	_configure_3d_render_buffers(viewport);
 }
 
+void RendererViewport::viewport_set_force_motion_vectors(RID p_viewport, bool p_force_motion_vectors) {
+	Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+	ERR_FAIL_NULL(viewport);
+
+	if (viewport->force_motion_vectors == p_force_motion_vectors) {
+		return;
+	}
+
+	bool motion_vectors_before = _viewport_requires_motion_vectors(viewport);
+	viewport->force_motion_vectors = p_force_motion_vectors;
+
+	bool motion_vectors_after = _viewport_requires_motion_vectors(viewport);
+	if (motion_vectors_before != motion_vectors_after) {
+		num_viewports_with_motion_vectors += motion_vectors_after ? 1 : -1;
+	}
+
+	_configure_3d_render_buffers(viewport);
+}
+
 void RendererViewport::viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) {
 	Viewport *viewport = viewport_owner.get_or_null(p_viewport);
 	ERR_FAIL_NULL(viewport);

+ 2 - 0
servers/rendering/renderer_viewport.h

@@ -77,6 +77,7 @@ public:
 		RS::ViewportScreenSpaceAA screen_space_aa = RenderingServer::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
 		bool use_taa = false;
 		bool use_debanding = false;
+		bool force_motion_vectors = false;
 
 		RendererSceneRender::CameraData prev_camera_data;
 		uint64_t prev_camera_data_frame = 0;
@@ -277,6 +278,7 @@ public:
 	void viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode);
 	void viewport_set_use_taa(RID p_viewport, bool p_use_taa);
 	void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding);
+	void viewport_set_force_motion_vectors(RID p_viewport, bool p_force_motion_vectors);
 	void viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling);
 	void viewport_set_occlusion_rays_per_thread(int p_rays_per_thread);
 	void viewport_set_occlusion_culling_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality);

+ 1 - 0
servers/rendering/rendering_server_default.h

@@ -724,6 +724,7 @@ public:
 	FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
 	FUNC2(viewport_set_use_taa, RID, bool)
 	FUNC2(viewport_set_use_debanding, RID, bool)
+	FUNC2(viewport_set_force_motion_vectors, RID, bool)
 	FUNC2(viewport_set_use_occlusion_culling, RID, bool)
 	FUNC1(viewport_set_occlusion_rays_per_thread, int)
 	FUNC1(viewport_set_occlusion_culling_build_quality, ViewportOcclusionCullingBuildQuality)

+ 6 - 1
servers/rendering/storage/texture_storage.h

@@ -178,13 +178,18 @@ public:
 	virtual RID render_target_get_vrs_texture(RID p_render_target) const = 0;
 
 	// override color, depth and velocity buffers (depth and velocity only for 3D)
-	virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) = 0;
+	virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture, RID p_velocity_depth_texture) = 0;
 	virtual RID render_target_get_override_color(RID p_render_target) const = 0;
 	virtual RID render_target_get_override_depth(RID p_render_target) const = 0;
 	virtual RID render_target_get_override_velocity(RID p_render_target) const = 0;
+	virtual RID render_target_get_override_velocity_depth(RID p_render_target) const = 0;
 
 	// get textures
 	virtual RID render_target_get_texture(RID p_render_target) = 0;
+
+	// Motion vectors
+	virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) = 0;
+	virtual Size2i render_target_get_velocity_target_size(RID p_render_target) const = 0;
 };
 
 #endif // TEXTURE_STORAGE_H

+ 2 - 0
servers/rendering_server.h

@@ -1015,6 +1015,8 @@ public:
 
 	virtual void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) = 0;
 
+	virtual void viewport_set_force_motion_vectors(RID p_viewport, bool p_force_motion_vectors) = 0;
+
 	virtual void viewport_set_mesh_lod_threshold(RID p_viewport, float p_pixels) = 0;
 
 	virtual void viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) = 0;

+ 8 - 0
servers/xr/xr_interface.cpp

@@ -187,6 +187,14 @@ RID XRInterface::get_velocity_texture() {
 	return RID();
 }
 
+RID XRInterface::get_velocity_depth_texture() {
+	return RID();
+}
+
+Size2i XRInterface::get_velocity_target_size() {
+	return Size2i();
+}
+
 PackedStringArray XRInterface::get_suggested_tracker_names() const {
 	PackedStringArray arr;
 

+ 2 - 0
servers/xr/xr_interface.h

@@ -137,6 +137,8 @@ public:
 	virtual RID get_color_texture(); /* obtain color output texture (if applicable) */
 	virtual RID get_depth_texture(); /* obtain depth output texture (if applicable, used for reprojection) */
 	virtual RID get_velocity_texture(); /* obtain velocity output texture (if applicable, used for spacewarp) */
+	virtual RID get_velocity_depth_texture();
+	virtual Size2i get_velocity_target_size();
 	virtual void pre_render() {}
 	virtual bool pre_draw_viewport(RID p_render_target) { return true; } /* inform XR interface we are about to start our viewport draw process */
 	virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* inform XR interface we finished our viewport draw process */