Skip to content

Commit 98aced4

Browse files
committed
Merge pull request #99768 from dsnopek/openxr-vulkan-foveated-rendering
OpenXR: Use the `XR_FB_foveation_vulkan` extension to get the density map for VRS
2 parents c5c1cd4 + 79f5a4d commit 98aced4

24 files changed

+178
-18
lines changed

doc/classes/ProjectSettings.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3379,11 +3379,10 @@
33793379
</member>
33803380
<member name="xr/openxr/foveation_dynamic" type="bool" setter="" getter="" default="false">
33813381
If [code]true[/code] and foveation is supported, will automatically adjust foveation level based on framerate up to the level set on [member xr/openxr/foveation_level].
3382-
[b]Note:[/b] Only works on the Compatibility rendering method.
33833382
</member>
33843383
<member name="xr/openxr/foveation_level" type="int" setter="" getter="" default="&quot;0&quot;">
33853384
Applied foveation level if supported: 0 = off, 1 = low, 2 = medium, 3 = high.
3386-
[b]Note:[/b] Only works on the Compatibility rendering method. On platforms other than Android, if [member rendering/anti_aliasing/quality/msaa_3d] is enabled, this feature will be disabled.
3385+
[b]Note:[/b] On platforms other than Android, if [member rendering/anti_aliasing/quality/msaa_3d] is enabled, this feature will be disabled.
33873386
</member>
33883387
<member name="xr/openxr/reference_space" type="int" setter="" getter="" default="&quot;1&quot;">
33893388
Specify the default reference space.

doc/classes/XRInterface.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,5 +275,14 @@
275275
<constant name="XR_ENV_BLEND_MODE_ALPHA_BLEND" value="2" enum="EnvironmentBlendMode">
276276
Alpha blend mode. This is typically used for AR or VR devices with passthrough capabilities. The alpha channel controls how much of the passthrough is visible. Alpha of 0.0 means the passthrough is visible and this pixel works in ADDITIVE mode. Alpha of 1.0 means that the passthrough is not visible and this pixel works in OPAQUE mode.
277277
</constant>
278+
<constant name="XR_VRS_TEXTURE_FORMAT_UNIFIED" value="0" enum="VRSTextureFormat">
279+
The texture format is the same as returned by [method XRVRS.make_vrs_texture].
280+
</constant>
281+
<constant name="XR_VRS_TEXTURE_FORMAT_FRAGMENT_SHADING_RATE" value="1" enum="VRSTextureFormat">
282+
The texture format is the same as expected by the Vulkan [code]VK_KHR_fragment_shading_rate[/code] extension.
283+
</constant>
284+
<constant name="XR_VRS_TEXTURE_FORMAT_FRAGMENT_DENSITY_MAP" value="2" enum="VRSTextureFormat">
285+
The texture format is the same as expected by the Vulkan [code]VK_EXT_fragment_density_map[/code] extension.
286+
</constant>
278287
</constants>
279288
</class>

doc/classes/XRInterfaceExtension.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@
136136
<description>
137137
</description>
138138
</method>
139+
<method name="_get_vrs_texture_format" qualifiers="virtual">
140+
<return type="int" enum="XRInterface.VRSTextureFormat" />
141+
<description>
142+
Returns the format of the texture returned by [method _get_vrs_texture].
143+
</description>
144+
</method>
139145
<method name="_initialize" qualifiers="virtual">
140146
<return type="bool" />
141147
<description>

modules/openxr/extensions/openxr_extension_wrapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,4 +192,5 @@ class OpenXRGraphicsExtensionWrapper : public OpenXRExtensionWrapper {
192192
virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) = 0; // `cleanup_swapchain_graphics_data` cleans up the data held in our implementation dependent data structure and should free up its memory.
193193
virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) = 0; // `create_projection_fov` creates a proper projection matrix based on asymmetric FOV data provided by OpenXR.
194194
virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) = 0; // `get_texture` returns a Godot texture RID for the current active texture in our swapchain.
195+
virtual RID get_density_map(void *p_swapchain_graphics_data, int p_image_index) = 0; // `get_density_map` returns a Godot texture RID for the current active density map in our swapchain (if any).
195196
};

modules/openxr/extensions/openxr_fb_foveation_extension.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include "openxr_fb_foveation_extension.h"
3232
#include "core/config/project_settings.h"
3333

34+
#include "../openxr_platform_inc.h"
35+
3436
OpenXRFBFoveationExtension *OpenXRFBFoveationExtension::singleton = nullptr;
3537

3638
OpenXRFBFoveationExtension *OpenXRFBFoveationExtension::get_singleton() {
@@ -51,6 +53,12 @@ OpenXRFBFoveationExtension::OpenXRFBFoveationExtension(const String &p_rendering
5153
swapchain_create_info_foveation_fb.type = XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB;
5254
swapchain_create_info_foveation_fb.next = nullptr;
5355
swapchain_create_info_foveation_fb.flags = 0;
56+
57+
if (rendering_driver == "opengl3") {
58+
swapchain_create_info_foveation_fb.flags = XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB;
59+
} else if (rendering_driver == "vulkan") {
60+
swapchain_create_info_foveation_fb.flags = XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB;
61+
}
5462
}
5563

5664
OpenXRFBFoveationExtension::~OpenXRFBFoveationExtension() {
@@ -61,12 +69,11 @@ OpenXRFBFoveationExtension::~OpenXRFBFoveationExtension() {
6169
HashMap<String, bool *> OpenXRFBFoveationExtension::get_requested_extensions() {
6270
HashMap<String, bool *> request_extensions;
6371

64-
if (rendering_driver == "vulkan") {
65-
// This is currently only supported on OpenGL, but we may add Vulkan support in the future...
72+
request_extensions[XR_FB_FOVEATION_EXTENSION_NAME] = &fb_foveation_ext;
73+
request_extensions[XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME] = &fb_foveation_configuration_ext;
6674

67-
} else if (rendering_driver == "opengl3") {
68-
request_extensions[XR_FB_FOVEATION_EXTENSION_NAME] = &fb_foveation_ext;
69-
request_extensions[XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME] = &fb_foveation_configuration_ext;
75+
if (rendering_driver == "vulkan") {
76+
request_extensions[XR_FB_FOVEATION_VULKAN_EXTENSION_NAME] = &fb_foveation_vulkan_ext;
7077
}
7178

7279
return request_extensions;
@@ -89,7 +96,11 @@ void OpenXRFBFoveationExtension::on_instance_destroyed() {
8996
}
9097

9198
bool OpenXRFBFoveationExtension::is_enabled() const {
92-
return swapchain_update_state_ext != nullptr && swapchain_update_state_ext->is_enabled() && fb_foveation_ext && fb_foveation_configuration_ext;
99+
bool enabled = swapchain_update_state_ext != nullptr && swapchain_update_state_ext->is_enabled() && fb_foveation_ext && fb_foveation_configuration_ext;
100+
if (rendering_driver == "vulkan") {
101+
enabled = enabled && fb_foveation_vulkan_ext;
102+
}
103+
return enabled;
93104
}
94105

95106
void *OpenXRFBFoveationExtension::set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) {

modules/openxr/extensions/openxr_fb_foveation_extension.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,6 @@
3535
// Other Android based devices are implementing this as well, see:
3636
// https://github.khronos.org/OpenXR-Inventory/extension_support.html#XR_FB_foveation
3737

38-
// Note: Currently we only support this for OpenGL.
39-
// This extension works on enabling foveated rendering on the swapchain.
40-
// Vulkan does not render 3D content directly to the swapchain image
41-
// hence this extension can't be used.
42-
4338
#include "../openxr_api.h"
4439
#include "../util.h"
4540
#include "openxr_extension_wrapper.h"
@@ -81,6 +76,7 @@ class OpenXRFBFoveationExtension : public OpenXRExtensionWrapper {
8176
String rendering_driver;
8277
bool fb_foveation_ext = false;
8378
bool fb_foveation_configuration_ext = false;
79+
bool fb_foveation_vulkan_ext = false;
8480

8581
// Configuration
8682
XrFoveationLevelFB foveation_level = XR_FOVEATION_LEVEL_NONE_FB;

modules/openxr/extensions/platform/openxr_metal_extension.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class OpenXRMetalExtension : public OpenXRGraphicsExtensionWrapper {
5353
virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override;
5454
virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) override;
5555
virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) override;
56+
virtual RID get_density_map(void *p_swapchain_graphics_data, int p_image_index) override { return RID(); }
5657

5758
private:
5859
static XrGraphicsBindingMetalKHR graphics_binding_metal;

modules/openxr/extensions/platform/openxr_opengl_extension.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class OpenXROpenGLExtension : public OpenXRGraphicsExtensionWrapper {
5555
virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override;
5656
virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) override;
5757
virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) override;
58+
virtual RID get_density_map(void *p_swapchain_graphics_data, int p_image_index) override { return RID(); }
5859

5960
private:
6061
static OpenXROpenGLExtension *singleton;

modules/openxr/extensions/platform/openxr_vulkan_extension.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "openxr_vulkan_extension.h"
3232

3333
#include "../../openxr_util.h"
34+
#include "../openxr_fb_foveation_extension.h"
3435

3536
#include "core/string/print_string.h"
3637
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
@@ -240,6 +241,7 @@ void OpenXRVulkanExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_s
240241

241242
bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) {
242243
LocalVector<XrSwapchainImageVulkanKHR> images;
244+
LocalVector<XrSwapchainImageFoveationVulkanFB> density_images;
243245

244246
RenderingServer *rendering_server = RenderingServer::get_singleton();
245247
ERR_FAIL_NULL_V(rendering_server, false);
@@ -261,6 +263,20 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
261263
image.image = VK_NULL_HANDLE;
262264
}
263265

266+
if (OpenXRFBFoveationExtension::get_singleton()->is_enabled()) {
267+
density_images.resize(swapchain_length);
268+
269+
for (uint64_t i = 0; i < swapchain_length; i++) {
270+
density_images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB;
271+
density_images[i].next = nullptr;
272+
density_images[i].image = VK_NULL_HANDLE;
273+
density_images[i].width = 0;
274+
density_images[i].height = 0;
275+
276+
images[i].next = &density_images[i];
277+
}
278+
}
279+
264280
result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images.ptr());
265281
if (XR_FAILED(result)) {
266282
print_line("OpenXR: Failed to get swapchaim images [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
@@ -351,9 +367,12 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
351367
}
352368

353369
Vector<RID> texture_rids;
370+
Vector<RID> density_map_rids;
354371

355372
// create Godot texture objects for each entry in our swapchain
356-
for (const XrSwapchainImageVulkanKHR &swapchain_image : images) {
373+
for (uint32_t i = 0; i < swapchain_length; i++) {
374+
const XrSwapchainImageVulkanKHR &swapchain_image = images[i];
375+
357376
RID image_rid = rendering_device->texture_create_from_extension(
358377
p_array_size == 1 ? RenderingDevice::TEXTURE_TYPE_2D : RenderingDevice::TEXTURE_TYPE_2D_ARRAY,
359378
format,
@@ -366,9 +385,27 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
366385
p_array_size);
367386

368387
texture_rids.push_back(image_rid);
388+
389+
if (OpenXRFBFoveationExtension::get_singleton()->is_enabled() && density_images[i].image != VK_NULL_HANDLE) {
390+
RID density_map_rid = rendering_device->texture_create_from_extension(
391+
p_array_size == 1 ? RenderingDevice::TEXTURE_TYPE_2D : RenderingDevice::TEXTURE_TYPE_2D_ARRAY,
392+
RD::DATA_FORMAT_R8G8_UNORM,
393+
RenderingDevice::TEXTURE_SAMPLES_1,
394+
RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT,
395+
(uint64_t)density_images[i].image,
396+
density_images[i].width,
397+
density_images[i].height,
398+
1,
399+
p_array_size);
400+
401+
density_map_rids.push_back(density_map_rid);
402+
} else {
403+
density_map_rids.push_back(RID());
404+
}
369405
}
370406

371407
data->texture_rids = texture_rids;
408+
data->density_map_rids = density_map_rids;
372409

373410
return true;
374411
}
@@ -395,6 +432,14 @@ RID OpenXRVulkanExtension::get_texture(void *p_swapchain_graphics_data, int p_im
395432
return data->texture_rids[p_image_index];
396433
}
397434

435+
RID OpenXRVulkanExtension::get_density_map(void *p_swapchain_graphics_data, int p_image_index) {
436+
SwapchainGraphicsData *data = (SwapchainGraphicsData *)p_swapchain_graphics_data;
437+
ERR_FAIL_NULL_V(data, RID());
438+
439+
ERR_FAIL_INDEX_V(p_image_index, data->density_map_rids.size(), RID());
440+
return data->density_map_rids[p_image_index];
441+
}
442+
398443
void OpenXRVulkanExtension::cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) {
399444
if (*p_swapchain_graphics_data == nullptr) {
400445
return;
@@ -413,6 +458,13 @@ void OpenXRVulkanExtension::cleanup_swapchain_graphics_data(void **p_swapchain_g
413458
}
414459
data->texture_rids.clear();
415460

461+
for (int i = 0; i < data->density_map_rids.size(); i++) {
462+
if (data->density_map_rids[i].is_valid()) {
463+
rendering_device->free(data->density_map_rids[i]);
464+
}
465+
}
466+
data->density_map_rids.clear();
467+
416468
memdelete(data);
417469
*p_swapchain_graphics_data = nullptr;
418470
}

modules/openxr/extensions/platform/openxr_vulkan_extension.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks
6262
virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override;
6363
virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) override;
6464
virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) override;
65+
virtual RID get_density_map(void *p_swapchain_graphics_data, int p_image_index) override;
6566

6667
private:
6768
static OpenXRVulkanExtension *singleton;
@@ -70,6 +71,7 @@ class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks
7071
struct SwapchainGraphicsData {
7172
bool is_multiview;
7273
Vector<RID> texture_rids;
74+
Vector<RID> density_map_rids;
7375
};
7476

7577
bool check_graphics_api_support(XrVersion p_desired_version);

0 commit comments

Comments
 (0)