Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement OpenXR Foveated rendering support #80881

Merged
merged 1 commit into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2717,6 +2717,12 @@
<member name="xr/openxr/form_factor" type="int" setter="" getter="" default="&quot;0&quot;">
Specify whether OpenXR should be configured for an HMD or a hand held device.
</member>
<member name="xr/openxr/foveation_dynamic" type="bool" setter="" getter="" default="false">
If true and foveation is supported, will automatically adjust foveation level based on framerate up to the level set on [code]xr/openxr/foveation_level[/code].
</member>
<member name="xr/openxr/foveation_level" type="int" setter="" getter="" default="&quot;0&quot;">
Applied foveation level if supported: 0 = off, 1 = low, 2 = medium, 3 = high.
</member>
<member name="xr/openxr/reference_space" type="int" setter="" getter="" default="&quot;1&quot;">
Specify the default reference space.
</member>
Expand Down
2 changes: 2 additions & 0 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2087,6 +2087,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/view_configuration", PROPERTY_HINT_ENUM, "Mono,Stereo"), "1"); // "Mono,Stereo,Quad,Observer"
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/reference_space", PROPERTY_HINT_ENUM, "Local,Stage"), "1");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/environment_blend_mode", PROPERTY_HINT_ENUM, "Opaque,Additive,Alpha"), "0");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/foveation_level", PROPERTY_HINT_ENUM, "Off,Low,Medium,High"), "0");
GLOBAL_DEF_BASIC("xr/openxr/foveation_dynamic", false);

GLOBAL_DEF_BASIC("xr/openxr/submit_depth_buffer", false);
GLOBAL_DEF_BASIC("xr/openxr/startup_alert", true);
Expand Down
2 changes: 2 additions & 0 deletions modules/openxr/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ env_openxr.add_source_files(module_obj, "extensions/openxr_htc_controller_extens
env_openxr.add_source_files(module_obj, "extensions/openxr_htc_vive_tracker_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_huawei_controller_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_hand_tracking_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_fb_foveation_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_fb_update_swapchain_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_fb_passthrough_extension_wrapper.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_fb_display_refresh_rate_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_pico_controller_extension.cpp")
Expand Down
13 changes: 13 additions & 0 deletions modules/openxr/doc_classes/OpenXRInterface.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@
Returns [code]true[/code] if the given action set is active.
</description>
</method>
<method name="is_foveation_supported" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if OpenXRs foveation extension is supported, the interface must be initialised before this returns a valid value.
[b]Note:[/b] This feature is only available on the compatibility renderer and currently only available on some stand alone headsets. For Vulkan set [member Viewport.vrs_mode] to [code]VRS_XR[/code] on desktop.
</description>
</method>
<method name="set_action_set_active">
<return type="void" />
<param index="0" name="name" type="String" />
Expand All @@ -98,6 +105,12 @@
<member name="display_refresh_rate" type="float" setter="set_display_refresh_rate" getter="get_display_refresh_rate" default="0.0">
The display refresh rate for the current HMD. Only functional if this feature is supported by the OpenXR runtime and after the interface has been initialized.
</member>
<member name="foveation_dynamic" type="bool" setter="set_foveation_dynamic" getter="get_foveation_dynamic" default="false">
Enable dynamic foveation adjustment, the interface must be initialised before this is accessible. If enabled foveation will automatically adjusted between low and [member foveation_level].
</member>
<member name="foveation_level" type="int" setter="set_foveation_level" getter="get_foveation_level" default="0">
Set foveation level from 0 (off) to 3 (high), the interface must be initialised before this is accessible.
</member>
<member name="render_target_size_multiplier" type="float" setter="set_render_target_size_multiplier" getter="get_render_target_size_multiplier" default="1.0">
The render size multiplier for the current HMD. Must be set before the interface has been initialized.
</member>
Expand Down
168 changes: 168 additions & 0 deletions modules/openxr/extensions/openxr_fb_foveation_extension.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/**************************************************************************/
/* openxr_fb_foveation_extension.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/

#include "openxr_fb_foveation_extension.h"
#include "core/config/project_settings.h"

OpenXRFBFoveationExtension *OpenXRFBFoveationExtension::singleton = nullptr;

OpenXRFBFoveationExtension *OpenXRFBFoveationExtension::get_singleton() {
return singleton;
}

OpenXRFBFoveationExtension::OpenXRFBFoveationExtension(const String &p_rendering_driver) {
singleton = this;
rendering_driver = p_rendering_driver;
swapchain_update_state_ext = OpenXRFBUpdateSwapchainExtension::get_singleton();
int fov_level = GLOBAL_GET("xr/openxr/foveation_level");
if (fov_level >= 0 && fov_level < 4) {
foveation_level = XrFoveationLevelFB(fov_level);
}
bool fov_dyn = GLOBAL_GET("xr/openxr/foveation_dynamic");
foveation_dynamic = fov_dyn ? XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB : XR_FOVEATION_DYNAMIC_DISABLED_FB;

swapchain_create_info_foveation_fb.type = XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB;
swapchain_create_info_foveation_fb.next = nullptr;
swapchain_create_info_foveation_fb.flags = 0;
}

OpenXRFBFoveationExtension::~OpenXRFBFoveationExtension() {
singleton = nullptr;
swapchain_update_state_ext = nullptr;
}

HashMap<String, bool *> OpenXRFBFoveationExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;

if (rendering_driver == "vulkan") {
// This is currently only supported on OpenGL, but we may add Vulkan support in the future...

} else if (rendering_driver == "opengl3") {
request_extensions[XR_FB_FOVEATION_EXTENSION_NAME] = &fb_foveation_ext;
request_extensions[XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME] = &fb_foveation_configuration_ext;
}

return request_extensions;
}

void OpenXRFBFoveationExtension::on_instance_created(const XrInstance p_instance) {
if (fb_foveation_ext) {
EXT_INIT_XR_FUNC(xrCreateFoveationProfileFB);
EXT_INIT_XR_FUNC(xrDestroyFoveationProfileFB);
}

if (fb_foveation_configuration_ext) {
// nothing to register here...
}
}

void OpenXRFBFoveationExtension::on_instance_destroyed() {
fb_foveation_ext = false;
fb_foveation_configuration_ext = false;
}

bool OpenXRFBFoveationExtension::is_enabled() const {
return swapchain_update_state_ext != nullptr && swapchain_update_state_ext->is_enabled() && fb_foveation_ext && fb_foveation_configuration_ext;
}

void *OpenXRFBFoveationExtension::set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) {
if (is_enabled()) {
swapchain_create_info_foveation_fb.next = p_next_pointer;
return &swapchain_create_info_foveation_fb;
} else {
return p_next_pointer;
}
}

void OpenXRFBFoveationExtension::on_state_ready() {
update_profile();
}

XrFoveationLevelFB OpenXRFBFoveationExtension::get_foveation_level() const {
return foveation_level;
}

void OpenXRFBFoveationExtension::set_foveation_level(XrFoveationLevelFB p_foveation_level) {
foveation_level = p_foveation_level;

// Update profile will do nothing if we're not yet initialised
update_profile();
}

XrFoveationDynamicFB OpenXRFBFoveationExtension::get_foveation_dynamic() const {
return foveation_dynamic;
}

void OpenXRFBFoveationExtension::set_foveation_dynamic(XrFoveationDynamicFB p_foveation_dynamic) {
foveation_dynamic = p_foveation_dynamic;

// Update profile will do nothing if we're not yet initialised
update_profile();
}

void OpenXRFBFoveationExtension::update_profile() {
if (!is_enabled()) {
return;
}

XrFoveationLevelProfileCreateInfoFB level_profile_create_info;
level_profile_create_info.type = XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB;
level_profile_create_info.next = nullptr;
level_profile_create_info.level = foveation_level;
level_profile_create_info.verticalOffset = 0.0f;
level_profile_create_info.dynamic = foveation_dynamic;

XrFoveationProfileCreateInfoFB profile_create_info;
profile_create_info.type = XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB;
profile_create_info.next = &level_profile_create_info;

XrFoveationProfileFB foveation_profile;
XrResult result = xrCreateFoveationProfileFB(OpenXRAPI::get_singleton()->get_session(), &profile_create_info, &foveation_profile);
if (XR_FAILED(result)) {
print_line("OpenXR: Unable to create the foveation profile [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
return;
}

XrSwapchainStateFoveationFB foveation_update_state;
foveation_update_state.type = XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB;
foveation_update_state.profile = foveation_profile;

result = swapchain_update_state_ext->xrUpdateSwapchainFB(OpenXRAPI::get_singleton()->get_color_swapchain(), (XrSwapchainStateBaseHeaderFB *)&foveation_update_state);
if (XR_FAILED(result)) {
print_line("OpenXR: Unable to update the swapchain [", OpenXRAPI::get_singleton()->get_error_string(result), "]");

// We still want to destroy our profile so keep going...
}

result = xrDestroyFoveationProfileFB(foveation_profile);
if (XR_FAILED(result)) {
print_line("OpenXR: Unable to destroy the foveation profile [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
}
}
96 changes: 96 additions & 0 deletions modules/openxr/extensions/openxr_fb_foveation_extension.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**************************************************************************/
/* openxr_fb_foveation_extension.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/

#ifndef OPENXR_FB_FOVEATION_EXTENSION_H
#define OPENXR_FB_FOVEATION_EXTENSION_H

// This extension implements the FB Foveation extension.
// This is an extension Meta added due to VRS being unavailable on Android.
// Other Android based devices are implementing this as well, see:
// https://github.khronos.org/OpenXR-Inventory/extension_support.html#XR_FB_foveation

// Note: Currently we only support this for OpenGL.
// This extension works on enabling foveated rendering on the swapchain.
// Vulkan does not render 3D content directly to the swapchain image
// hence this extension can't be used.

#include "../openxr_api.h"
#include "../util.h"
#include "openxr_extension_wrapper.h"
#include "openxr_fb_update_swapchain_extension.h"

class OpenXRFBFoveationExtension : public OpenXRExtensionWrapper {
public:
static OpenXRFBFoveationExtension *get_singleton();

OpenXRFBFoveationExtension(const String &p_rendering_driver);
virtual ~OpenXRFBFoveationExtension() override;

virtual HashMap<String, bool *> get_requested_extensions() override;

virtual void on_instance_created(const XrInstance p_instance) override;
virtual void on_instance_destroyed() override;

virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) override;

virtual void on_state_ready() override;

bool is_enabled() const;

XrFoveationLevelFB get_foveation_level() const;
void set_foveation_level(XrFoveationLevelFB p_foveation_level);

XrFoveationDynamicFB get_foveation_dynamic() const;
void set_foveation_dynamic(XrFoveationDynamicFB p_foveation_dynamic);

private:
static OpenXRFBFoveationExtension *singleton;

// Setup
String rendering_driver;
bool fb_foveation_ext = false;
bool fb_foveation_configuration_ext = false;

// Configuration
XrFoveationLevelFB foveation_level = XR_FOVEATION_LEVEL_NONE_FB;
XrFoveationDynamicFB foveation_dynamic = XR_FOVEATION_DYNAMIC_DISABLED_FB;

void update_profile();

// Enable foveation on this swapchain
XrSwapchainCreateInfoFoveationFB swapchain_create_info_foveation_fb;
OpenXRFBUpdateSwapchainExtension *swapchain_update_state_ext = nullptr;

// OpenXR API call wrappers
EXT_PROTO_XRRESULT_FUNC3(xrCreateFoveationProfileFB, (XrSession), session, (const XrFoveationProfileCreateInfoFB *), create_info, (XrFoveationProfileFB *), profile);
EXT_PROTO_XRRESULT_FUNC1(xrDestroyFoveationProfileFB, (XrFoveationProfileFB), profile);
};

#endif // OPENXR_FB_FOVEATION_EXTENSION_H
Loading