Skip to content

Commit 53e1ea1

Browse files
committed
Implement XR_META_foveation_eye_tracked
1 parent 68410ac commit 53e1ea1

File tree

8 files changed

+144
-19
lines changed

8 files changed

+144
-19
lines changed

drivers/vulkan/rendering_device_driver_vulkan.cpp

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ Error RenderingDeviceDriverVulkan::_initialize_device_extensions() {
523523
_register_requested_device_extension(VK_KHR_MULTIVIEW_EXTENSION_NAME, false);
524524
_register_requested_device_extension(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, false);
525525
_register_requested_device_extension(VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME, false);
526+
_register_requested_device_extension(VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME, false);
526527
_register_requested_device_extension(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, false);
527528
_register_requested_device_extension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
528529
_register_requested_device_extension(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, false);
@@ -760,6 +761,7 @@ Error RenderingDeviceDriverVulkan::_check_device_capabilities() {
760761
VkPhysicalDeviceVulkanMemoryModelFeaturesKHR vulkan_memory_model_features = {};
761762
VkPhysicalDeviceFragmentShadingRateFeaturesKHR fsr_features = {};
762763
VkPhysicalDeviceFragmentDensityMapFeaturesEXT fdm_features = {};
764+
VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM fdmo_features_qcom = {};
763765
VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = {};
764766
VkPhysicalDeviceMultiviewFeatures multiview_features = {};
765767
VkPhysicalDevicePipelineCreationCacheControlFeatures pipeline_cache_control_features = {};
@@ -799,6 +801,12 @@ Error RenderingDeviceDriverVulkan::_check_device_capabilities() {
799801
next_features = &fdm_features;
800802
}
801803

804+
if (enabled_device_extension_names.has(VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME)) {
805+
fdmo_features_qcom.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM;
806+
fdmo_features_qcom.pNext = next_features;
807+
next_features = &fdmo_features_qcom;
808+
}
809+
802810
if (enabled_device_extension_names.has(VK_KHR_16BIT_STORAGE_EXTENSION_NAME)) {
803811
storage_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR;
804812
storage_feature.pNext = next_features;
@@ -863,6 +871,10 @@ Error RenderingDeviceDriverVulkan::_check_device_capabilities() {
863871
fdm_capabilities.non_subsampled_images_supported = fdm_features.fragmentDensityMapNonSubsampledImages;
864872
}
865873

874+
if (enabled_device_extension_names.has(VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME)) {
875+
fdm_capabilities.offset_supported = fdmo_features_qcom.fragmentDensityMapOffset;
876+
}
877+
866878
// Multiple VRS techniques can't co-exist during the existence of one device, so we must
867879
// choose one at creation time and only report one of them as available.
868880
_choose_vrs_capabilities();
@@ -898,6 +910,7 @@ Error RenderingDeviceDriverVulkan::_check_device_capabilities() {
898910
void *next_properties = nullptr;
899911
VkPhysicalDeviceFragmentShadingRatePropertiesKHR fsr_properties = {};
900912
VkPhysicalDeviceFragmentDensityMapPropertiesEXT fdm_properties = {};
913+
VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM fdmo_properties = {};
901914
VkPhysicalDeviceMultiviewProperties multiview_properties = {};
902915
VkPhysicalDeviceSubgroupProperties subgroup_properties = {};
903916
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control_properties = {};
@@ -935,6 +948,12 @@ Error RenderingDeviceDriverVulkan::_check_device_capabilities() {
935948
next_properties = &fdm_properties;
936949
}
937950

951+
if (fdm_capabilities.offset_supported) {
952+
fdmo_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM;
953+
fdmo_properties.pNext = next_properties;
954+
next_properties = &fdmo_properties;
955+
}
956+
938957
physical_device_properties_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
939958
physical_device_properties_2.pNext = next_properties;
940959
functions.GetPhysicalDeviceProperties2(physical_device, &physical_device_properties_2);
@@ -1002,6 +1021,17 @@ Error RenderingDeviceDriverVulkan::_check_device_capabilities() {
10021021
print_verbose("- Vulkan Fragment Density Map not supported");
10031022
}
10041023

1024+
if (fdm_capabilities.offset_supported) {
1025+
print_verbose("- Vulkan Fragment Density Map Offset supported");
1026+
1027+
fdm_capabilities.offset_granularity.x = fdmo_properties.fragmentDensityOffsetGranularity.width;
1028+
fdm_capabilities.offset_granularity.y = fdmo_properties.fragmentDensityOffsetGranularity.height;
1029+
1030+
print_verbose(vformat(" Offset granularity: (%d, %d)", fdm_capabilities.offset_granularity.x, fdm_capabilities.offset_granularity.y));
1031+
} else {
1032+
print_verbose("- Vulkan Fragment Density Map Offset not supported");
1033+
}
1034+
10051035
if (multiview_capabilities.is_supported) {
10061036
multiview_capabilities.max_view_count = multiview_properties.maxMultiviewViewCount;
10071037
multiview_capabilities.max_instance_count = multiview_properties.maxMultiviewInstanceIndex;
@@ -3708,11 +3738,6 @@ RDD::FramebufferID RenderingDeviceDriverVulkan::framebuffer_create(RenderPassID
37083738
for (uint32_t i = 0; i < p_attachments.size(); i++) {
37093739
const TextureInfo *texture = (const TextureInfo *)p_attachments[i].id;
37103740
vk_img_views[i] = texture->vk_view;
3711-
3712-
if (render_pass->uses_fragment_density_map_offsets && (texture->vk_create_info.usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT)) {
3713-
// If the render pass uses the FDM and the usage fits, we store the amount of layers to use it later on the render pass's end.
3714-
fragment_density_map_offsets_layers = texture->vk_create_info.arrayLayers;
3715-
}
37163741
}
37173742

37183743
VkFramebufferCreateInfo framebuffer_create_info = {};
@@ -4921,6 +4946,7 @@ RDD::RenderPassID RenderingDeviceDriverVulkan::render_pass_create(VectorView<Att
49214946

49224947
RenderPassInfo *render_pass = VersatileResource::allocate<RenderPassInfo>(resources_allocator);
49234948
render_pass->vk_render_pass = vk_render_pass;
4949+
render_pass->uses_fragment_density_map = uses_fragment_density_map;
49244950
return RenderPassID(render_pass);
49254951
}
49264952

@@ -4982,7 +5008,25 @@ void RenderingDeviceDriverVulkan::command_end_render_pass(CommandBufferID p_cmd_
49825008
DEV_ASSERT(command_buffer->active_framebuffer != nullptr && "A framebuffer must be active.");
49835009
DEV_ASSERT(command_buffer->active_render_pass != nullptr && "A render pass must be active.");
49845010

4985-
vkCmdEndRenderPass(command_buffer->vk_command_buffer);
5011+
if (device_functions.EndRenderPass2KHR != nullptr && fdm_capabilities.offset_supported && command_buffer->active_render_pass->uses_fragment_density_map) {
5012+
LocalVector<VkOffset2D> fragment_density_offsets;
5013+
if (VulkanHooks::get_singleton() != nullptr) {
5014+
fragment_density_offsets = VulkanHooks::get_singleton()->get_fragment_density_offsets();
5015+
}
5016+
5017+
VkSubpassFragmentDensityMapOffsetEndInfoQCOM offset_info = {};
5018+
offset_info.sType = VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM;
5019+
offset_info.pFragmentDensityOffsets = fragment_density_offsets.is_empty() ? nullptr : fragment_density_offsets.ptr();
5020+
offset_info.fragmentDensityOffsetCount = fragment_density_offsets.size();
5021+
5022+
VkSubpassEndInfo subpass_end_info = {};
5023+
subpass_end_info.sType = VK_STRUCTURE_TYPE_SUBPASS_END_INFO;
5024+
subpass_end_info.pNext = &offset_info;
5025+
5026+
device_functions.EndRenderPass2KHR(command_buffer->vk_command_buffer, &subpass_end_info);
5027+
} else {
5028+
vkCmdEndRenderPass(command_buffer->vk_command_buffer);
5029+
}
49865030

49875031
command_buffer->active_render_pass = nullptr;
49885032
command_buffer->active_framebuffer = nullptr;

drivers/vulkan/rendering_device_driver_vulkan.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver {
575575

576576
struct RenderPassInfo {
577577
VkRenderPass vk_render_pass = VK_NULL_HANDLE;
578-
bool uses_fragment_density_map_offsets = false;
578+
bool uses_fragment_density_map = false;
579579
};
580580

581581
public:

drivers/vulkan/vulkan_hooks.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#pragma once
3232

33+
#include "core/templates/local_vector.h"
3334
#include "drivers/vulkan/godot_vulkan.h"
3435

3536
class VulkanHooks {
@@ -43,5 +44,6 @@ class VulkanHooks {
4344
virtual bool get_physical_device(VkPhysicalDevice *r_device) = 0;
4445
virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) = 0;
4546
virtual void set_direct_queue_family_and_index(uint32_t p_queue_family_index, uint32_t p_queue_index) = 0;
47+
virtual LocalVector<VkOffset2D> get_fragment_density_offsets() = 0;
4648
static VulkanHooks *get_singleton() { return singleton; }
4749
};

modules/openxr/extensions/openxr_fb_foveation_extension.cpp

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#include "openxr_fb_foveation_extension.h"
3232
#include "core/config/project_settings.h"
33+
#include "openxr_eye_gaze_interaction.h"
3334

3435
#include "../openxr_platform_inc.h"
3536

@@ -54,6 +55,14 @@ OpenXRFBFoveationExtension::OpenXRFBFoveationExtension(const String &p_rendering
5455
swapchain_create_info_foveation_fb.next = nullptr;
5556
swapchain_create_info_foveation_fb.flags = 0;
5657

58+
meta_foveation_eye_tracked_create_info.type = XR_TYPE_FOVEATION_EYE_TRACKED_PROFILE_CREATE_INFO_META;
59+
meta_foveation_eye_tracked_create_info.next = nullptr;
60+
meta_foveation_eye_tracked_create_info.flags = 0;
61+
62+
meta_foveation_eye_tracked_properties.type = XR_TYPE_SYSTEM_FOVEATION_EYE_TRACKED_PROPERTIES_META;
63+
meta_foveation_eye_tracked_properties.next = nullptr;
64+
meta_foveation_eye_tracked_properties.supportsFoveationEyeTracked = XR_FALSE;
65+
5766
if (rendering_driver == "opengl3") {
5867
swapchain_create_info_foveation_fb.flags = XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB;
5968
} else if (rendering_driver == "vulkan") {
@@ -75,6 +84,7 @@ HashMap<String, bool *> OpenXRFBFoveationExtension::get_requested_extensions() {
7584
#ifdef XR_USE_GRAPHICS_API_VULKAN
7685
if (rendering_driver == "vulkan") {
7786
request_extensions[XR_FB_FOVEATION_VULKAN_EXTENSION_NAME] = &fb_foveation_vulkan_ext;
87+
request_extensions[XR_META_FOVEATION_EYE_TRACKED_EXTENSION_NAME] = &meta_foveation_eye_tracked;
7888
}
7989
#endif // XR_USE_GRAPHICS_API_VULKAN
8090

@@ -90,11 +100,16 @@ void OpenXRFBFoveationExtension::on_instance_created(const XrInstance p_instance
90100
if (fb_foveation_configuration_ext) {
91101
// nothing to register here...
92102
}
103+
104+
if (meta_foveation_eye_tracked) {
105+
EXT_INIT_XR_FUNC(xrGetFoveationEyeTrackedStateMETA);
106+
}
93107
}
94108

95109
void OpenXRFBFoveationExtension::on_instance_destroyed() {
96110
fb_foveation_ext = false;
97111
fb_foveation_configuration_ext = false;
112+
meta_foveation_eye_tracked = false;
98113
}
99114

100115
bool OpenXRFBFoveationExtension::is_enabled() const {
@@ -107,6 +122,16 @@ bool OpenXRFBFoveationExtension::is_enabled() const {
107122
return enabled;
108123
}
109124

125+
void *OpenXRFBFoveationExtension::set_system_properties_and_get_next_pointer(void *p_next_pointer) {
126+
#ifdef XR_USE_GRAPHICS_API_VULKAN
127+
if (rendering_driver == "vulkan") {
128+
meta_foveation_eye_tracked_properties.next = p_next_pointer;
129+
return &meta_foveation_eye_tracked_properties;
130+
}
131+
#endif
132+
return p_next_pointer;
133+
}
134+
110135
void *OpenXRFBFoveationExtension::set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) {
111136
if (is_enabled()) {
112137
swapchain_create_info_foveation_fb.next = p_next_pointer;
@@ -142,6 +167,37 @@ void OpenXRFBFoveationExtension::set_foveation_dynamic(XrFoveationDynamicFB p_fo
142167
update_profile();
143168
}
144169

170+
LocalVector<Vector2i> OpenXRFBFoveationExtension::get_fragment_density_offsets() {
171+
LocalVector<Vector2i> ret;
172+
if (!is_enabled() || !meta_foveation_eye_tracked || !meta_foveation_eye_tracked_properties.supportsFoveationEyeTracked || !OpenXREyeGazeInteractionExtension::get_singleton()->is_available()) {
173+
return ret;
174+
}
175+
176+
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
177+
ERR_FAIL_NULL_V(openxr_api, ret);
178+
179+
XrFoveationEyeTrackedStateMETA state = {
180+
XR_TYPE_FOVEATION_EYE_TRACKED_STATE_META, // type
181+
nullptr, // next
182+
{ XrVector2f{}, XrVector2f{} }, // foveationCenter[XR_FOVEATION_CENTER_SIZE_META];
183+
0, // flags
184+
};
185+
XrResult result = xrGetFoveationEyeTrackedStateMETA(openxr_api->get_session(), &state);
186+
if (XR_FAILED(result)) {
187+
print_line("OpenXR: Unable to get foveation offsets [", openxr_api->get_error_string(result), "]");
188+
return ret;
189+
}
190+
191+
ret.reserve(XR_FOVEATION_CENTER_SIZE_META);
192+
Size2 dims = openxr_api->get_recommended_target_size() * 0.5 / openxr_api->get_render_target_size_multiplier();
193+
for (uint32_t i = 0; i < XR_FOVEATION_CENTER_SIZE_META; ++i) {
194+
const XrVector2f &xr_offset = state.foveationCenter[i];
195+
ret.push_back(Vector2i((int)(xr_offset.x * dims.x), (int)(xr_offset.y * dims.y)));
196+
}
197+
198+
return ret;
199+
}
200+
145201
void OpenXRFBFoveationExtension::_update_profile() {
146202
// Must be called from rendering thread!
147203
ERR_NOT_ON_RENDER_THREAD;
@@ -162,9 +218,15 @@ void OpenXRFBFoveationExtension::_update_profile() {
162218
return;
163219
}
164220

221+
void *next = nullptr;
222+
if (fov_ext->meta_foveation_eye_tracked && fov_ext->meta_foveation_eye_tracked_properties.supportsFoveationEyeTracked) {
223+
fov_ext->meta_foveation_eye_tracked_create_info.next = next;
224+
next = &fov_ext->meta_foveation_eye_tracked_create_info;
225+
}
226+
165227
XrFoveationLevelProfileCreateInfoFB level_profile_create_info;
166228
level_profile_create_info.type = XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB;
167-
level_profile_create_info.next = nullptr;
229+
level_profile_create_info.next = next;
168230
level_profile_create_info.level = fov_ext->foveation_level;
169231
level_profile_create_info.verticalOffset = 0.0f;
170232
level_profile_create_info.dynamic = fov_ext->foveation_dynamic;

modules/openxr/extensions/openxr_fb_foveation_extension.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class OpenXRFBFoveationExtension : public OpenXRExtensionWrapper {
5757
virtual void on_instance_created(const XrInstance p_instance) override;
5858
virtual void on_instance_destroyed() override;
5959

60+
virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) override;
6061
virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) override;
6162

6263
virtual void on_main_swapchains_created() override;
@@ -69,6 +70,8 @@ class OpenXRFBFoveationExtension : public OpenXRExtensionWrapper {
6970
XrFoveationDynamicFB get_foveation_dynamic() const;
7071
void set_foveation_dynamic(XrFoveationDynamicFB p_foveation_dynamic);
7172

73+
LocalVector<Vector2i> get_fragment_density_offsets();
74+
7275
private:
7376
static OpenXRFBFoveationExtension *singleton;
7477

@@ -77,6 +80,7 @@ class OpenXRFBFoveationExtension : public OpenXRExtensionWrapper {
7780
bool fb_foveation_ext = false;
7881
bool fb_foveation_configuration_ext = false;
7982
bool fb_foveation_vulkan_ext = false;
83+
bool meta_foveation_eye_tracked = false;
8084

8185
// Configuration
8286
XrFoveationLevelFB foveation_level = XR_FOVEATION_LEVEL_NONE_FB;
@@ -96,7 +100,12 @@ class OpenXRFBFoveationExtension : public OpenXRExtensionWrapper {
96100
XrSwapchainCreateInfoFoveationFB swapchain_create_info_foveation_fb;
97101
OpenXRFBUpdateSwapchainExtension *swapchain_update_state_ext = nullptr;
98102

103+
// Enable eye tracked foveation
104+
XrSystemFoveationEyeTrackedPropertiesMETA meta_foveation_eye_tracked_properties;
105+
XrFoveationEyeTrackedProfileCreateInfoMETA meta_foveation_eye_tracked_create_info;
106+
99107
// OpenXR API call wrappers
100108
EXT_PROTO_XRRESULT_FUNC3(xrCreateFoveationProfileFB, (XrSession), session, (const XrFoveationProfileCreateInfoFB *), create_info, (XrFoveationProfileFB *), profile);
101109
EXT_PROTO_XRRESULT_FUNC1(xrDestroyFoveationProfileFB, (XrFoveationProfileFB), profile);
110+
EXT_PROTO_XRRESULT_FUNC2(xrGetFoveationEyeTrackedStateMETA, (XrSession), session, (XrFoveationEyeTrackedStateMETA *), foveationState);
102111
};

modules/openxr/extensions/openxr_fb_update_swapchain_extension.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,7 @@ void OpenXRFBUpdateSwapchainExtension::on_instance_destroyed() {
105105
}
106106

107107
bool OpenXRFBUpdateSwapchainExtension::is_enabled() const {
108-
if (rendering_driver == "vulkan") {
109-
return fb_swapchain_update_state_ext && fb_swapchain_update_state_vulkan_ext;
110-
} else if (rendering_driver == "opengl3") {
111-
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
112-
return fb_swapchain_update_state_ext && fb_swapchain_update_state_opengles_ext;
113-
#else
114-
return fb_swapchain_update_state_ext;
115-
#endif
116-
}
117-
118-
return false;
108+
return fb_swapchain_update_state_ext;
119109
}
120110

121111
bool OpenXRFBUpdateSwapchainExtension::is_android_ext_enabled() const {

modules/openxr/extensions/platform/openxr_vulkan_extension.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,23 @@ void OpenXRVulkanExtension::set_direct_queue_family_and_index(uint32_t p_queue_f
203203
vulkan_queue_index = p_queue_index;
204204
}
205205

206+
LocalVector<VkOffset2D> OpenXRVulkanExtension::get_fragment_density_offsets() {
207+
LocalVector<VkOffset2D> ret;
208+
OpenXRFBFoveationExtension *fb_foveation = OpenXRFBFoveationExtension::get_singleton();
209+
if (fb_foveation == nullptr) {
210+
return ret;
211+
}
212+
213+
LocalVector<Vector2i> offsets = fb_foveation->get_fragment_density_offsets();
214+
215+
ret.reserve(offsets.size());
216+
for (const Vector2i &offset : offsets) {
217+
ret.push_back(VkOffset2D{ offset.x, offset.y });
218+
}
219+
220+
return ret;
221+
}
222+
206223
XrGraphicsBindingVulkanKHR OpenXRVulkanExtension::graphics_binding_vulkan;
207224

208225
void *OpenXRVulkanExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) {

modules/openxr/extensions/platform/openxr_vulkan_extension.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks
5454
virtual bool get_physical_device(VkPhysicalDevice *r_device) override final;
5555
virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) override final;
5656
virtual void set_direct_queue_family_and_index(uint32_t p_queue_family_index, uint32_t p_queue_index) override final;
57+
virtual LocalVector<VkOffset2D> get_fragment_density_offsets() override final;
5758

5859
virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override;
5960
virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) override;

0 commit comments

Comments
 (0)