Implement XR_META_foveation_eye_tracked

This commit is contained in:
dhoverb
2025-11-07 18:50:39 +00:00
committed by David Hover
parent 68410acc61
commit 53e1ea184a
8 changed files with 144 additions and 19 deletions

View File

@ -30,6 +30,7 @@
#include "openxr_fb_foveation_extension.h"
#include "core/config/project_settings.h"
#include "openxr_eye_gaze_interaction.h"
#include "../openxr_platform_inc.h"
@ -54,6 +55,14 @@ OpenXRFBFoveationExtension::OpenXRFBFoveationExtension(const String &p_rendering
swapchain_create_info_foveation_fb.next = nullptr;
swapchain_create_info_foveation_fb.flags = 0;
meta_foveation_eye_tracked_create_info.type = XR_TYPE_FOVEATION_EYE_TRACKED_PROFILE_CREATE_INFO_META;
meta_foveation_eye_tracked_create_info.next = nullptr;
meta_foveation_eye_tracked_create_info.flags = 0;
meta_foveation_eye_tracked_properties.type = XR_TYPE_SYSTEM_FOVEATION_EYE_TRACKED_PROPERTIES_META;
meta_foveation_eye_tracked_properties.next = nullptr;
meta_foveation_eye_tracked_properties.supportsFoveationEyeTracked = XR_FALSE;
if (rendering_driver == "opengl3") {
swapchain_create_info_foveation_fb.flags = XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB;
} else if (rendering_driver == "vulkan") {
@ -75,6 +84,7 @@ HashMap<String, bool *> OpenXRFBFoveationExtension::get_requested_extensions() {
#ifdef XR_USE_GRAPHICS_API_VULKAN
if (rendering_driver == "vulkan") {
request_extensions[XR_FB_FOVEATION_VULKAN_EXTENSION_NAME] = &fb_foveation_vulkan_ext;
request_extensions[XR_META_FOVEATION_EYE_TRACKED_EXTENSION_NAME] = &meta_foveation_eye_tracked;
}
#endif // XR_USE_GRAPHICS_API_VULKAN
@ -90,11 +100,16 @@ void OpenXRFBFoveationExtension::on_instance_created(const XrInstance p_instance
if (fb_foveation_configuration_ext) {
// nothing to register here...
}
if (meta_foveation_eye_tracked) {
EXT_INIT_XR_FUNC(xrGetFoveationEyeTrackedStateMETA);
}
}
void OpenXRFBFoveationExtension::on_instance_destroyed() {
fb_foveation_ext = false;
fb_foveation_configuration_ext = false;
meta_foveation_eye_tracked = false;
}
bool OpenXRFBFoveationExtension::is_enabled() const {
@ -107,6 +122,16 @@ bool OpenXRFBFoveationExtension::is_enabled() const {
return enabled;
}
void *OpenXRFBFoveationExtension::set_system_properties_and_get_next_pointer(void *p_next_pointer) {
#ifdef XR_USE_GRAPHICS_API_VULKAN
if (rendering_driver == "vulkan") {
meta_foveation_eye_tracked_properties.next = p_next_pointer;
return &meta_foveation_eye_tracked_properties;
}
#endif
return p_next_pointer;
}
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;
@ -142,6 +167,37 @@ void OpenXRFBFoveationExtension::set_foveation_dynamic(XrFoveationDynamicFB p_fo
update_profile();
}
LocalVector<Vector2i> OpenXRFBFoveationExtension::get_fragment_density_offsets() {
LocalVector<Vector2i> ret;
if (!is_enabled() || !meta_foveation_eye_tracked || !meta_foveation_eye_tracked_properties.supportsFoveationEyeTracked || !OpenXREyeGazeInteractionExtension::get_singleton()->is_available()) {
return ret;
}
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
ERR_FAIL_NULL_V(openxr_api, ret);
XrFoveationEyeTrackedStateMETA state = {
XR_TYPE_FOVEATION_EYE_TRACKED_STATE_META, // type
nullptr, // next
{ XrVector2f{}, XrVector2f{} }, // foveationCenter[XR_FOVEATION_CENTER_SIZE_META];
0, // flags
};
XrResult result = xrGetFoveationEyeTrackedStateMETA(openxr_api->get_session(), &state);
if (XR_FAILED(result)) {
print_line("OpenXR: Unable to get foveation offsets [", openxr_api->get_error_string(result), "]");
return ret;
}
ret.reserve(XR_FOVEATION_CENTER_SIZE_META);
Size2 dims = openxr_api->get_recommended_target_size() * 0.5 / openxr_api->get_render_target_size_multiplier();
for (uint32_t i = 0; i < XR_FOVEATION_CENTER_SIZE_META; ++i) {
const XrVector2f &xr_offset = state.foveationCenter[i];
ret.push_back(Vector2i((int)(xr_offset.x * dims.x), (int)(xr_offset.y * dims.y)));
}
return ret;
}
void OpenXRFBFoveationExtension::_update_profile() {
// Must be called from rendering thread!
ERR_NOT_ON_RENDER_THREAD;
@ -162,9 +218,15 @@ void OpenXRFBFoveationExtension::_update_profile() {
return;
}
void *next = nullptr;
if (fov_ext->meta_foveation_eye_tracked && fov_ext->meta_foveation_eye_tracked_properties.supportsFoveationEyeTracked) {
fov_ext->meta_foveation_eye_tracked_create_info.next = next;
next = &fov_ext->meta_foveation_eye_tracked_create_info;
}
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.next = next;
level_profile_create_info.level = fov_ext->foveation_level;
level_profile_create_info.verticalOffset = 0.0f;
level_profile_create_info.dynamic = fov_ext->foveation_dynamic;

View File

@ -57,6 +57,7 @@ public:
virtual void on_instance_created(const XrInstance p_instance) override;
virtual void on_instance_destroyed() override;
virtual void *set_system_properties_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 on_main_swapchains_created() override;
@ -69,6 +70,8 @@ public:
XrFoveationDynamicFB get_foveation_dynamic() const;
void set_foveation_dynamic(XrFoveationDynamicFB p_foveation_dynamic);
LocalVector<Vector2i> get_fragment_density_offsets();
private:
static OpenXRFBFoveationExtension *singleton;
@ -77,6 +80,7 @@ private:
bool fb_foveation_ext = false;
bool fb_foveation_configuration_ext = false;
bool fb_foveation_vulkan_ext = false;
bool meta_foveation_eye_tracked = false;
// Configuration
XrFoveationLevelFB foveation_level = XR_FOVEATION_LEVEL_NONE_FB;
@ -96,7 +100,12 @@ private:
XrSwapchainCreateInfoFoveationFB swapchain_create_info_foveation_fb;
OpenXRFBUpdateSwapchainExtension *swapchain_update_state_ext = nullptr;
// Enable eye tracked foveation
XrSystemFoveationEyeTrackedPropertiesMETA meta_foveation_eye_tracked_properties;
XrFoveationEyeTrackedProfileCreateInfoMETA meta_foveation_eye_tracked_create_info;
// OpenXR API call wrappers
EXT_PROTO_XRRESULT_FUNC3(xrCreateFoveationProfileFB, (XrSession), session, (const XrFoveationProfileCreateInfoFB *), create_info, (XrFoveationProfileFB *), profile);
EXT_PROTO_XRRESULT_FUNC1(xrDestroyFoveationProfileFB, (XrFoveationProfileFB), profile);
EXT_PROTO_XRRESULT_FUNC2(xrGetFoveationEyeTrackedStateMETA, (XrSession), session, (XrFoveationEyeTrackedStateMETA *), foveationState);
};

View File

@ -105,17 +105,7 @@ void OpenXRFBUpdateSwapchainExtension::on_instance_destroyed() {
}
bool OpenXRFBUpdateSwapchainExtension::is_enabled() const {
if (rendering_driver == "vulkan") {
return fb_swapchain_update_state_ext && fb_swapchain_update_state_vulkan_ext;
} else if (rendering_driver == "opengl3") {
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
return fb_swapchain_update_state_ext && fb_swapchain_update_state_opengles_ext;
#else
return fb_swapchain_update_state_ext;
#endif
}
return false;
return fb_swapchain_update_state_ext;
}
bool OpenXRFBUpdateSwapchainExtension::is_android_ext_enabled() const {

View File

@ -203,6 +203,23 @@ void OpenXRVulkanExtension::set_direct_queue_family_and_index(uint32_t p_queue_f
vulkan_queue_index = p_queue_index;
}
LocalVector<VkOffset2D> OpenXRVulkanExtension::get_fragment_density_offsets() {
LocalVector<VkOffset2D> ret;
OpenXRFBFoveationExtension *fb_foveation = OpenXRFBFoveationExtension::get_singleton();
if (fb_foveation == nullptr) {
return ret;
}
LocalVector<Vector2i> offsets = fb_foveation->get_fragment_density_offsets();
ret.reserve(offsets.size());
for (const Vector2i &offset : offsets) {
ret.push_back(VkOffset2D{ offset.x, offset.y });
}
return ret;
}
XrGraphicsBindingVulkanKHR OpenXRVulkanExtension::graphics_binding_vulkan;
void *OpenXRVulkanExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) {

View File

@ -54,6 +54,7 @@ public:
virtual bool get_physical_device(VkPhysicalDevice *r_device) override final;
virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) override final;
virtual void set_direct_queue_family_and_index(uint32_t p_queue_family_index, uint32_t p_queue_index) override final;
virtual LocalVector<VkOffset2D> get_fragment_density_offsets() override final;
virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override;
virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) override;