Path: blob/master/modules/openxr/extensions/openxr_fb_foveation_extension.cpp
21635 views
/**************************************************************************/1/* openxr_fb_foveation_extension.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "openxr_fb_foveation_extension.h"31#include "core/config/project_settings.h"32#include "openxr_eye_gaze_interaction.h"3334#include "../openxr_platform_inc.h"3536OpenXRFBFoveationExtension *OpenXRFBFoveationExtension::singleton = nullptr;3738OpenXRFBFoveationExtension *OpenXRFBFoveationExtension::get_singleton() {39return singleton;40}4142OpenXRFBFoveationExtension::OpenXRFBFoveationExtension(const String &p_rendering_driver) {43singleton = this;44rendering_driver = p_rendering_driver;45swapchain_update_state_ext = OpenXRFBUpdateSwapchainExtension::get_singleton();46int fov_level = GLOBAL_GET("xr/openxr/foveation_level");47if (fov_level >= 0 && fov_level < 4) {48foveation_level = XrFoveationLevelFB(fov_level);49}50bool fov_dyn = GLOBAL_GET("xr/openxr/foveation_dynamic");51foveation_dynamic = fov_dyn ? XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB : XR_FOVEATION_DYNAMIC_DISABLED_FB;5253swapchain_create_info_foveation_fb.type = XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB;54swapchain_create_info_foveation_fb.next = nullptr;55swapchain_create_info_foveation_fb.flags = 0;5657meta_foveation_eye_tracked_create_info.type = XR_TYPE_FOVEATION_EYE_TRACKED_PROFILE_CREATE_INFO_META;58meta_foveation_eye_tracked_create_info.next = nullptr;59meta_foveation_eye_tracked_create_info.flags = 0;6061meta_foveation_eye_tracked_properties.type = XR_TYPE_SYSTEM_FOVEATION_EYE_TRACKED_PROPERTIES_META;62meta_foveation_eye_tracked_properties.next = nullptr;63meta_foveation_eye_tracked_properties.supportsFoveationEyeTracked = XR_FALSE;6465#ifdef VULKAN_ENABLED66meta_vulkan_swapchain_create_info.type = XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META;67meta_vulkan_swapchain_create_info.next = nullptr;68meta_vulkan_swapchain_create_info.additionalCreateFlags = VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_QCOM;69meta_vulkan_swapchain_create_info.additionalUsageFlags = 0;70#endif7172if (rendering_driver == "opengl3") {73swapchain_create_info_foveation_fb.flags = XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB;74} else if (rendering_driver == "vulkan") {75swapchain_create_info_foveation_fb.flags = XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB;76}77}7879OpenXRFBFoveationExtension::~OpenXRFBFoveationExtension() {80singleton = nullptr;81swapchain_update_state_ext = nullptr;82}8384HashMap<String, bool *> OpenXRFBFoveationExtension::get_requested_extensions(XrVersion p_version) {85HashMap<String, bool *> request_extensions;8687request_extensions[XR_FB_FOVEATION_EXTENSION_NAME] = &fb_foveation_ext;88request_extensions[XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME] = &fb_foveation_configuration_ext;8990#ifdef XR_USE_GRAPHICS_API_VULKAN91if (rendering_driver == "vulkan") {92request_extensions[XR_FB_FOVEATION_VULKAN_EXTENSION_NAME] = &fb_foveation_vulkan_ext;93request_extensions[XR_META_FOVEATION_EYE_TRACKED_EXTENSION_NAME] = &meta_foveation_eye_tracked_ext;94request_extensions[XR_META_VULKAN_SWAPCHAIN_CREATE_INFO_EXTENSION_NAME] = &meta_vulkan_swapchain_create_info_ext;95}96#endif // XR_USE_GRAPHICS_API_VULKAN9798return request_extensions;99}100101void OpenXRFBFoveationExtension::on_instance_created(const XrInstance p_instance) {102if (fb_foveation_ext) {103EXT_INIT_XR_FUNC(xrCreateFoveationProfileFB);104EXT_INIT_XR_FUNC(xrDestroyFoveationProfileFB);105}106107if (fb_foveation_configuration_ext) {108// nothing to register here...109}110111if (meta_foveation_eye_tracked_ext) {112EXT_INIT_XR_FUNC(xrGetFoveationEyeTrackedStateMETA);113}114}115116void OpenXRFBFoveationExtension::on_instance_destroyed() {117fb_foveation_ext = false;118fb_foveation_configuration_ext = false;119meta_foveation_eye_tracked_ext = false;120}121122bool OpenXRFBFoveationExtension::is_enabled() const {123bool enabled = swapchain_update_state_ext != nullptr && swapchain_update_state_ext->is_enabled() && fb_foveation_ext && fb_foveation_configuration_ext;124#ifdef XR_USE_GRAPHICS_API_VULKAN125if (rendering_driver == "vulkan") {126enabled = enabled && fb_foveation_vulkan_ext;127}128#endif // XR_USE_GRAPHICS_API_VULKAN129return enabled;130}131132void *OpenXRFBFoveationExtension::set_system_properties_and_get_next_pointer(void *p_next_pointer) {133#ifdef XR_USE_GRAPHICS_API_VULKAN134if (rendering_driver == "vulkan") {135meta_foveation_eye_tracked_properties.next = p_next_pointer;136return &meta_foveation_eye_tracked_properties;137}138#endif139return p_next_pointer;140}141142void *OpenXRFBFoveationExtension::set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) {143void *next = p_next_pointer;144if (is_enabled()) {145swapchain_create_info_foveation_fb.next = next;146next = &swapchain_create_info_foveation_fb;147148#ifdef VULKAN_ENABLED149if (meta_foveation_eye_tracked_ext && meta_vulkan_swapchain_create_info_ext && meta_foveation_eye_tracked_properties.supportsFoveationEyeTracked) {150meta_vulkan_swapchain_create_info.next = next;151next = &meta_vulkan_swapchain_create_info;152}153#endif154}155156return next;157}158159void OpenXRFBFoveationExtension::on_main_swapchains_created() {160update_profile();161}162163XrFoveationLevelFB OpenXRFBFoveationExtension::get_foveation_level() const {164return foveation_level;165}166167void OpenXRFBFoveationExtension::set_foveation_level(XrFoveationLevelFB p_foveation_level) {168foveation_level = p_foveation_level;169170// Update profile will do nothing if we're not yet initialized.171update_profile();172}173174XrFoveationDynamicFB OpenXRFBFoveationExtension::get_foveation_dynamic() const {175return foveation_dynamic;176}177178void OpenXRFBFoveationExtension::set_foveation_dynamic(XrFoveationDynamicFB p_foveation_dynamic) {179foveation_dynamic = p_foveation_dynamic;180181// Update profile will do nothing if we're not yet initialized.182update_profile();183}184185bool OpenXRFBFoveationExtension::is_foveation_eye_tracked_enabled() const {186return is_enabled() && meta_foveation_eye_tracked_ext && meta_vulkan_swapchain_create_info_ext && meta_foveation_eye_tracked_properties.supportsFoveationEyeTracked;187}188189void OpenXRFBFoveationExtension::get_fragment_density_offsets(LocalVector<Vector2i> &r_offsets) {190// Must be called from rendering thread!191ERR_NOT_ON_RENDER_THREAD;192193if (!is_foveation_eye_tracked_enabled() || !OpenXREyeGazeInteractionExtension::get_singleton()->is_available()) {194return;195}196197OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();198ERR_FAIL_NULL(openxr_api);199200_update_profile_rt();201202XrFoveationEyeTrackedStateMETA state = {203XR_TYPE_FOVEATION_EYE_TRACKED_STATE_META, // type204nullptr, // next205{ XrVector2f{}, XrVector2f{} }, // foveationCenter[XR_FOVEATION_CENTER_SIZE_META];2060, // flags207};208XrResult result = xrGetFoveationEyeTrackedStateMETA(openxr_api->get_session(), &state);209if (XR_FAILED(result)) {210print_line("OpenXR: Unable to get foveation offsets [", openxr_api->get_error_string(result), "]");211return;212}213if (!(state.flags & XR_FOVEATION_EYE_TRACKED_STATE_VALID_BIT_META)) {214return;215}216217r_offsets.reserve(XR_FOVEATION_CENTER_SIZE_META);218Size2 dims = openxr_api->get_recommended_target_size() * 0.5;219for (uint32_t i = 0; i < XR_FOVEATION_CENTER_SIZE_META; ++i) {220const XrVector2f &xr_center = state.foveationCenter[i];221r_offsets.push_back(Vector2i((int)(xr_center.x * dims.x), (int)(xr_center.y * dims.y)));222}223}224225void OpenXRFBFoveationExtension::_update_profile_rt() {226// Must be called from rendering thread!227ERR_NOT_ON_RENDER_THREAD;228229if (!is_enabled()) {230return;231}232233OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();234ERR_FAIL_NULL(openxr_api);235236XrSwapchain main_color_swapchain = openxr_api->get_color_swapchain();237if (main_color_swapchain == XR_NULL_HANDLE) {238// Our swapchain hasn't been created yet, we'll call this again once it has.239return;240}241242void *next = nullptr;243if (meta_foveation_eye_tracked_ext && meta_vulkan_swapchain_create_info_ext && meta_foveation_eye_tracked_properties.supportsFoveationEyeTracked) {244meta_foveation_eye_tracked_create_info.next = next;245next = &meta_foveation_eye_tracked_create_info;246}247248XrFoveationLevelProfileCreateInfoFB level_profile_create_info;249level_profile_create_info.type = XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB;250level_profile_create_info.next = next;251level_profile_create_info.level = foveation_level;252level_profile_create_info.verticalOffset = 0.0f;253level_profile_create_info.dynamic = foveation_dynamic;254255XrFoveationProfileCreateInfoFB profile_create_info;256profile_create_info.type = XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB;257profile_create_info.next = &level_profile_create_info;258259XrFoveationProfileFB foveation_profile;260XrResult result = xrCreateFoveationProfileFB(openxr_api->get_session(), &profile_create_info, &foveation_profile);261if (XR_FAILED(result)) {262print_line("OpenXR: Unable to create the foveation profile [", openxr_api->get_error_string(result), "]");263return;264}265266XrSwapchainStateFoveationFB foveation_update_state;267foveation_update_state.type = XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB;268foveation_update_state.next = nullptr;269foveation_update_state.flags = 0;270foveation_update_state.profile = foveation_profile;271272result = swapchain_update_state_ext->xrUpdateSwapchainFB(main_color_swapchain, (XrSwapchainStateBaseHeaderFB *)&foveation_update_state);273if (XR_FAILED(result)) {274print_line("OpenXR: Unable to update the swapchain [", openxr_api->get_error_string(result), "]");275276// We still want to destroy our profile so keep going...277}278279result = xrDestroyFoveationProfileFB(foveation_profile);280if (XR_FAILED(result)) {281print_line("OpenXR: Unable to destroy the foveation profile [", openxr_api->get_error_string(result), "]");282}283}284285286