From c7607ea4afd1614f1d7517cccedea7a785c7748e Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Tue, 5 Nov 2024 09:37:53 +1100 Subject: [PATCH] OpenXR: Add Metal support --- modules/openxr/extensions/SCsub | 2 + .../platform/openxr_metal_extension.h | 72 ++++ .../platform/openxr_metal_extension.mm | 318 ++++++++++++++++++ .../platform/openxr_opengl_extension.cpp | 4 +- .../platform/openxr_vulkan_extension.cpp | 12 +- modules/openxr/openxr_api.cpp | 29 +- modules/openxr/openxr_platform_inc.h | 5 + 7 files changed, 423 insertions(+), 19 deletions(-) create mode 100644 modules/openxr/extensions/platform/openxr_metal_extension.h create mode 100644 modules/openxr/extensions/platform/openxr_metal_extension.mm diff --git a/modules/openxr/extensions/SCsub b/modules/openxr/extensions/SCsub index 95b75ccd6528..15eab5d707ae 100644 --- a/modules/openxr/extensions/SCsub +++ b/modules/openxr/extensions/SCsub @@ -13,6 +13,8 @@ if env["platform"] == "android": env_openxr.add_source_files(module_obj, "platform/openxr_android_extension.cpp") if env["vulkan"]: env_openxr.add_source_files(module_obj, "platform/openxr_vulkan_extension.cpp") +if env["metal"]: + env_openxr.add_source_files(module_obj, "platform/openxr_metal_extension.mm") if env["opengl3"] and env["platform"] != "macos": env_openxr.add_source_files(module_obj, "platform/openxr_opengl_extension.cpp") diff --git a/modules/openxr/extensions/platform/openxr_metal_extension.h b/modules/openxr/extensions/platform/openxr_metal_extension.h new file mode 100644 index 000000000000..11bfbcaf7d93 --- /dev/null +++ b/modules/openxr/extensions/platform/openxr_metal_extension.h @@ -0,0 +1,72 @@ +/**************************************************************************/ +/* openxr_metal_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_METAL_EXTENSION_H +#define OPENXR_METAL_EXTENSION_H + +#include "../../openxr_api.h" +#include "../../util.h" +#include "../openxr_extension_wrapper.h" + +#include "core/templates/vector.h" + +// Always include this as late as possible. +#include "../../openxr_platform_inc.h" + +class OpenXRMetalExtension : public OpenXRGraphicsExtensionWrapper { +public: + virtual HashMap get_requested_extensions() override; + + virtual void on_instance_created(const XrInstance p_instance) override; + virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override; + + virtual void get_usable_swapchain_formats(Vector &p_usable_swap_chains) override; + virtual void get_usable_depth_formats(Vector &p_usable_swap_chains) override; + virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override; + virtual bool 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) override; + virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override; + virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) override; + virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) override; + +private: + static XrGraphicsBindingMetalKHR graphics_binding_metal; + + struct SwapchainGraphicsData { + bool is_multiview; + Vector texture_rids; + }; + + bool check_graphics_api_support(); + + EXT_PROTO_XRRESULT_FUNC3(xrGetMetalGraphicsRequirementsKHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsMetalKHR *), p_graphics_requirements) + EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSwapchainImages, (XrSwapchain), p_swapchain, (uint32_t), p_image_capacity_input, (uint32_t *), p_image_count_output, (XrSwapchainImageBaseHeader *), p_images) +}; + +#endif // OPENXR_METAL_EXTENSION_H diff --git a/modules/openxr/extensions/platform/openxr_metal_extension.mm b/modules/openxr/extensions/platform/openxr_metal_extension.mm new file mode 100644 index 000000000000..d4cb2dd45c2d --- /dev/null +++ b/modules/openxr/extensions/platform/openxr_metal_extension.mm @@ -0,0 +1,318 @@ +/**************************************************************************/ +/* openxr_metal_extension.mm */ +/**************************************************************************/ +/* 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_metal_extension.h" + +#include "../../openxr_util.h" +#include "drivers/metal/rendering_device_driver_metal.h" +#include "servers/rendering/rendering_server_globals.h" + +HashMap OpenXRMetalExtension::get_requested_extensions() { + HashMap request_extensions; + + request_extensions[XR_KHR_METAL_ENABLE_EXTENSION_NAME] = nullptr; + + return request_extensions; +} + +void OpenXRMetalExtension::on_instance_created(const XrInstance p_instance) { + // Obtain pointers to functions we're accessing here. + ERR_FAIL_NULL(OpenXRAPI::get_singleton()); + + EXT_INIT_XR_FUNC(xrGetMetalGraphicsRequirementsKHR); + EXT_INIT_XR_FUNC(xrEnumerateSwapchainImages); +} + +bool OpenXRMetalExtension::check_graphics_api_support() { + ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false); + + // TODO We may need to do a callback like we do in Vulkan where we run this first + // and provide the obtained metalDevice to our Metal driver to use. + // But according to Stuart Macs only have 1 device so it should always be the + // same one and we should be able to get away with not doing this just yet. + // If we do go forward with this, this means that just like with Vulkan, + // we have to start with OpenXR before Metal can be setup, and we thus + // can't support applications that want to add XR as an optional/temporary + // feature that users enable when needed. + + XrSystemId system_id = OpenXRAPI::get_singleton()->get_system_id(); + XrInstance instance = OpenXRAPI::get_singleton()->get_instance(); + + XrGraphicsRequirementsMetalKHR metal_requirements; + metal_requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_METAL_KHR; + metal_requirements.next = nullptr; + metal_requirements.metalDevice = nullptr; + + XrResult result = xrGetMetalGraphicsRequirementsKHR(instance, system_id, &metal_requirements); + if (!OpenXRAPI::get_singleton()->xr_result(result, "Failed to get Metal graphics requirements!")) { + return false; + } + + // See what metal device we are using... + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL_V(rendering_server, false); + RenderingDevice *rendering_device = rendering_server->get_rendering_device(); + ERR_FAIL_NULL_V(rendering_device, false); + + void *our_metal_device = (void *)rendering_device->get_driver_resource(RD::DRIVER_RESOURCE_LOGICAL_DEVICE); + + // Make sure we're using the same one. + ERR_FAIL_COND_V(metal_requirements.metalDevice != our_metal_device, false); + + return true; +} + +XrGraphicsBindingMetalKHR OpenXRMetalExtension::graphics_binding_metal; + +void *OpenXRMetalExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) { + if (!check_graphics_api_support()) { + return p_next_pointer; + } + + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL_V(rendering_server, p_next_pointer); + RenderingDevice *rendering_device = rendering_server->get_rendering_device(); + ERR_FAIL_NULL_V(rendering_device, p_next_pointer); + + graphics_binding_metal.type = XR_TYPE_GRAPHICS_BINDING_METAL_KHR; + graphics_binding_metal.next = p_next_pointer; + graphics_binding_metal.commandQueue = (void *)rendering_device->get_driver_resource(RD::DRIVER_RESOURCE_COMMAND_QUEUE); + + return &graphics_binding_metal; +} + +void OpenXRMetalExtension::get_usable_swapchain_formats(Vector &p_usable_swap_chains) { + p_usable_swap_chains.push_back(MTLPixelFormatRGBA8Unorm_sRGB); + p_usable_swap_chains.push_back(MTLPixelFormatBGRA8Unorm_sRGB); + p_usable_swap_chains.push_back(MTLPixelFormatRGBA8Uint); +} + +void OpenXRMetalExtension::get_usable_depth_formats(Vector &p_usable_swap_chains) { + p_usable_swap_chains.push_back(MTLPixelFormatDepth24Unorm_Stencil8); + p_usable_swap_chains.push_back(MTLPixelFormatDepth32Float_Stencil8); + p_usable_swap_chains.push_back(MTLPixelFormatDepth32Float); +} + +#define ENUM_TO_STRING_CASE(m_e) \ + case m_e: { \ + return String(#m_e); \ + } break; + +String OpenXRMetalExtension::get_swapchain_format_name(int64_t p_swapchain_format) const { + // This really should be in vulkan_context... + MTLPixelFormat format = MTLPixelFormat(p_swapchain_format); + switch (format) { + ENUM_TO_STRING_CASE(MTLPixelFormatRGBA8Unorm) + ENUM_TO_STRING_CASE(MTLPixelFormatRGBA8Unorm_sRGB) + ENUM_TO_STRING_CASE(MTLPixelFormatBGRA8Unorm) + ENUM_TO_STRING_CASE(MTLPixelFormatBGRA8Unorm_sRGB) + ENUM_TO_STRING_CASE(MTLPixelFormatRGBA8Uint) + ENUM_TO_STRING_CASE(MTLPixelFormatDepth24Unorm_Stencil8) + ENUM_TO_STRING_CASE(MTLPixelFormatDepth32Float_Stencil8) + ENUM_TO_STRING_CASE(MTLPixelFormatDepth32Float) + default: { + return String("Swapchain format ") + String::num_int64(int64_t(p_swapchain_format)); + } break; + } +} + +bool OpenXRMetalExtension::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) { + LocalVector images; + + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL_V(rendering_server, false); + RenderingDevice *rendering_device = rendering_server->get_rendering_device(); + ERR_FAIL_NULL_V(rendering_device, false); + + uint32_t swapchain_length; + XrResult result = xrEnumerateSwapchainImages(p_swapchain, 0, &swapchain_length, nullptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get swapchaim image count [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); + return false; + } + + images.resize(swapchain_length); + + for (XrSwapchainImageMetalKHR &image : images) { + image.type = XR_TYPE_SWAPCHAIN_IMAGE_METAL_KHR; + image.next = nullptr; + image.texture = nullptr; + } + + result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images.ptr()); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get swapchaim images [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); + return false; + } + + SwapchainGraphicsData *data = memnew(SwapchainGraphicsData); + if (data == nullptr) { + print_line("OpenXR: Failed to allocate memory for swapchain data"); + return false; + } + *r_swapchain_graphics_data = data; + data->is_multiview = (p_array_size > 1); + + RenderingDevice::DataFormat format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB; + RenderingDevice::TextureSamples samples = RenderingDevice::TEXTURE_SAMPLES_1; + uint64_t usage_flags = RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT; + + switch (p_swapchain_format) { + case MTLPixelFormatRGBA8Unorm_sRGB: + // Even though this is an sRGB framebuffer format we're using UNORM here. + // The reason here is because Godot does a linear to sRGB conversion while + // with the sRGB format, this conversion would be doubled by the hardware. + // This also means we're reading the values as is for our preview on screen. + // The OpenXR runtime however is still treating this as an sRGB format and + // will thus do an sRGB -> Linear conversion as expected. + //format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB; + format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UNORM; + usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + break; + case MTLPixelFormatBGRA8Unorm_sRGB: + format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UNORM; + usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + break; + case MTLPixelFormatRGBA8Uint: + format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UINT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + break; + case MTLPixelFormatDepth32Float: + format = RenderingDevice::DATA_FORMAT_D32_SFLOAT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + break; + case MTLPixelFormatDepth24Unorm_Stencil8: + format = RenderingDevice::DATA_FORMAT_D24_UNORM_S8_UINT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + break; + case MTLPixelFormatDepth32Float_Stencil8: + format = RenderingDevice::DATA_FORMAT_D32_SFLOAT_S8_UINT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + break; + default: + // Continue with our default value. + print_line("Unsupported swapchain format ", p_swapchain_format); + break; + } + + switch (p_sample_count) { + case 1: + samples = RenderingDevice::TEXTURE_SAMPLES_1; + break; + case 2: + samples = RenderingDevice::TEXTURE_SAMPLES_2; + break; + case 4: + samples = RenderingDevice::TEXTURE_SAMPLES_4; + break; + case 8: + samples = RenderingDevice::TEXTURE_SAMPLES_8; + break; + case 16: + samples = RenderingDevice::TEXTURE_SAMPLES_16; + break; + case 32: + samples = RenderingDevice::TEXTURE_SAMPLES_32; + break; + case 64: + samples = RenderingDevice::TEXTURE_SAMPLES_64; + break; + default: + // Continue with our default value. + print_line("Unsupported sample count ", p_sample_count); + break; + } + + Vector texture_rids; + + // Create Godot texture objects for each entry in our swapchain. + for (uint64_t i = 0; i < swapchain_length; i++) { + // Note, the formats we sent to render_device are ignored on metal. + RID image_rid = rendering_device->texture_create_from_extension( + p_array_size == 1 ? RenderingDevice::TEXTURE_TYPE_2D : RenderingDevice::TEXTURE_TYPE_2D_ARRAY, + format, + samples, + usage_flags, + (uint64_t)images[i].texture, + p_width, + p_height, + 1, + p_array_size); + + texture_rids.push_back(image_rid); + } + + data->texture_rids = texture_rids; + + return true; +} + +void OpenXRMetalExtension::cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) { + if (*p_swapchain_graphics_data == nullptr) { + return; + } + + SwapchainGraphicsData *data = (SwapchainGraphicsData *)*p_swapchain_graphics_data; + + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL(rendering_server); + RenderingDevice *rendering_device = rendering_server->get_rendering_device(); + ERR_FAIL_NULL(rendering_device); + + for (const RID &texture_rid : data->texture_rids) { + rendering_device->free(texture_rid); + } + data->texture_rids.clear(); + + memdelete(data); + *p_swapchain_graphics_data = nullptr; +} + +bool OpenXRMetalExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) { + // Even though this is a Metal renderer we're using OpenGL coordinate systems. + OpenXRUtil::XrMatrix4x4f matrix; + OpenXRUtil::XrMatrix4x4f_CreateProjectionFov(&matrix, OpenXRUtil::GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far); + + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + r_camera_matrix.columns[j][i] = matrix.m[j * 4 + i]; + } + } + + return true; +} + +RID OpenXRMetalExtension::get_texture(void *p_swapchain_graphics_data, int p_image_index) { + SwapchainGraphicsData *data = (SwapchainGraphicsData *)p_swapchain_graphics_data; + ERR_FAIL_NULL_V(data, RID()); + + ERR_FAIL_INDEX_V(p_image_index, data->texture_rids.size(), RID()); + return data->texture_rids[p_image_index]; +} diff --git a/modules/openxr/extensions/platform/openxr_opengl_extension.cpp b/modules/openxr/extensions/platform/openxr_opengl_extension.cpp index 4fcb3f7b75ba..057e527f5fe6 100644 --- a/modules/openxr/extensions/platform/openxr_opengl_extension.cpp +++ b/modules/openxr/extensions/platform/openxr_opengl_extension.cpp @@ -315,8 +315,8 @@ void OpenXROpenGLExtension::cleanup_swapchain_graphics_data(void **p_swapchain_g SwapchainGraphicsData *data = (SwapchainGraphicsData *)*p_swapchain_graphics_data; - for (int i = 0; i < data->texture_rids.size(); i++) { - texture_storage->texture_free(data->texture_rids[i]); + for (const RID &texture_rid : data->texture_rids) { + texture_storage->texture_free(texture_rid); } data->texture_rids.clear(); diff --git a/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp b/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp index da613f8435ff..e433626481f8 100644 --- a/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp +++ b/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp @@ -291,12 +291,12 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in // This also means we're reading the values as is for our preview on screen. // The OpenXR runtime however is still treating this as an sRGB format and // will thus do an sRGB -> Linear conversion as expected. - // format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB; + //format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB; format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UNORM; usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; break; case VK_FORMAT_B8G8R8A8_SRGB: - // format = RenderingDevice::DATA_FORMAT_B8G8R8A8_SRGB; + //format = RenderingDevice::DATA_FORMAT_B8G8R8A8_SRGB; format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UNORM; usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; break; @@ -380,7 +380,7 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in } bool OpenXRVulkanExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) { - // Even though this is a Vulkan renderer we're using OpenGL coordinate systems + // Even though this is a Vulkan renderer we're using OpenGL coordinate systems. OpenXRUtil::XrMatrix4x4f matrix; OpenXRUtil::XrMatrix4x4f_CreateProjectionFov(&matrix, OpenXRUtil::GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far); @@ -413,9 +413,9 @@ void OpenXRVulkanExtension::cleanup_swapchain_graphics_data(void **p_swapchain_g RenderingDevice *rendering_device = rendering_server->get_rendering_device(); ERR_FAIL_NULL(rendering_device); - for (int i = 0; i < data->texture_rids.size(); i++) { - // This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain - rendering_device->free(data->texture_rids[i]); + for (const RID &texture_rid : data->texture_rids) { + // This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain. + rendering_device->free(texture_rid); } data->texture_rids.clear(); diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 17755417578a..de931da4cb55 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -49,6 +49,10 @@ #include "extensions/platform/openxr_vulkan_extension.h" #endif +#ifdef METAL_ENABLED +#include "extensions/platform/openxr_metal_extension.h" +#endif + #if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED) #include "extensions/platform/openxr_opengl_extension.h" #endif @@ -1174,12 +1178,9 @@ bool OpenXRAPI::obtain_swapchain_formats() { } } - if (color_swapchain_format == 0) { - color_swapchain_format = usable_swapchain_formats[0]; // just use the first one and hope for the best... - print_line("Couldn't find usable color swap chain format, using", get_swapchain_format_name(color_swapchain_format), "instead."); - } else { - print_verbose(String("Using color swap chain format:") + get_swapchain_format_name(color_swapchain_format)); - } + ERR_FAIL_COND_V_MSG(color_swapchain_format == 0, false, "OpenXR: No usable color swap chain format available!"); + + print_verbose(String("Using color swap chain format:") + get_swapchain_format_name(color_swapchain_format)); } { @@ -1196,11 +1197,9 @@ bool OpenXRAPI::obtain_swapchain_formats() { } } - if (depth_swapchain_format == 0) { - WARN_PRINT_ONCE("Couldn't find usable depth swap chain format, depth buffer will not be submitted if requested."); - } else { - print_verbose(String("Using depth swap chain format:") + get_swapchain_format_name(depth_swapchain_format)); - } + ERR_FAIL_COND_V_MSG(depth_swapchain_format == 0, false, "OpenXR: No usable depth swap chain format available!"); + + print_verbose(String("Using depth swap chain format:") + get_swapchain_format_name(depth_swapchain_format)); } return true; @@ -1657,6 +1656,14 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) { #else // shouldn't be possible... ERR_FAIL_V(false); +#endif + } else if (p_rendering_driver == "metal") { +#ifdef METAL_ENABLED + graphics_extension = memnew(OpenXRMetalExtension); + register_extension_wrapper(graphics_extension); +#else + // shouldn't be possible... + ERR_FAIL_V(false); #endif } else if (p_rendering_driver == "opengl3") { #if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED) diff --git a/modules/openxr/openxr_platform_inc.h b/modules/openxr/openxr_platform_inc.h index 09bc0c89a282..d2268efc3cb6 100644 --- a/modules/openxr/openxr_platform_inc.h +++ b/modules/openxr/openxr_platform_inc.h @@ -39,6 +39,11 @@ #include "drivers/vulkan/rendering_context_driver_vulkan.h" #endif // VULKAN_ENABLED +#ifdef METAL_ENABLED +#define XR_USE_GRAPHICS_API_METAL +#include "drivers/metal/rendering_context_driver_metal.h" +#endif // METAL_ENABLED + #if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED) #ifdef ANDROID_ENABLED #define XR_USE_GRAPHICS_API_OPENGL_ES