Skip to content

OpenXR SDK 1.1.57 compatibility#55

Open
antoineemerit wants to merge 37 commits intoKhronosGroup:mainfrom
antoineemerit:main
Open

OpenXR SDK 1.1.57 compatibility#55
antoineemerit wants to merge 37 commits intoKhronosGroup:mainfrom
antoineemerit:main

Conversation

@antoineemerit
Copy link
Copy Markdown

@antoineemerit antoineemerit commented Aug 29, 2025

Re-enable all skipped extensions/structure/function and fix all compile errors to make the OpenXR-Hpp scripts compatible with the OpenXR-SDK 1.1.51 (see #53).

…3, because API LAYER functions has been moved from external include file to the XR Registry
…positionLayerPassthroughFB); this fix keeps the parent's name and so the derivated structure affected member does not follow the registry name.
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Aug 29, 2025

CLA assistant check
All committers have signed the CLA.

@antoineemerit
Copy link
Copy Markdown
Author

Compile without error using the OpenXR-SDK 1.1.51 (thanks to the previous fix).

@antoineemerit antoineemerit changed the title OpenXR SDK 1.1.50 compatibility OpenXR SDK 1.1.51 compatibility Sep 16, 2025
@glebov-andrey
Copy link
Copy Markdown

Hi,

Thanks for working on fixing these compatibility problems!

I'm trying out this fork with SDK 1.1.57, and I've come across a couple of issues.

  1. The *ToVector() function templates have been removed. Specifically xr::Swapchain::enumerateSwapchainImagesToVector<xr::SwapchainImageVulkanKHR>(). Was this intended?

  2. Some structure layouts are broken under the Microsoft ABI (MSVC or Clang on Windows):

.\include\openxr\openxr_structs.hpp(28447,15): error: static assertion failed due to requirement 'sizeof(XrCreateSpatialAnchorsCompletionML) == sizeof(xr::CreateSpatialAnchorsCompletionML)': Original type and wrapper have different size!
 28447 | static_assert(sizeof(XrCreateSpatialAnchorsCompletionML) ==
       |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 28448 |                   sizeof(CreateSpatialAnchorsCompletionML),
       |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\include\openxr\openxr_structs.hpp(28447,58): note: expression evaluates to '32 == 40'
 28447 | static_assert(sizeof(XrCreateSpatialAnchorsCompletionML) ==
       |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
 28448 |                   sizeof(CreateSpatialAnchorsCompletionML),
       |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\include\openxr\openxr_structs.hpp(29280,15): error: static assertion failed due to requirement 'sizeof(XrSpatialAnchorsPublishCompletionML) == sizeof(xr::SpatialAnchorsPublishCompletionML)': Original type and wrapper have different size!
 29280 | static_assert(sizeof(XrSpatialAnchorsPublishCompletionML) ==
       |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 29281 |                   sizeof(SpatialAnchorsPublishCompletionML),
       |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\include\openxr\openxr_structs.hpp(29280,59): note: expression evaluates to '32 == 40'
 29280 | static_assert(sizeof(XrSpatialAnchorsPublishCompletionML) ==
       |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
 29281 |                   sizeof(SpatialAnchorsPublishCompletionML),
       |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\include\openxr\openxr_structs.hpp(57365,15): error: static assertion failed due to requirement 'sizeof(XrWorldMeshRequestCompletionML) == sizeof(xr::WorldMeshRequestCompletionML)': Original type and wrapper have different size!
 57365 | static_assert(sizeof(XrWorldMeshRequestCompletionML) == sizeof(WorldMeshRequestCompletionML),
       |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\include\openxr\openxr_structs.hpp(57365,54): note: expression evaluates to '32 == 40'
 57365 | static_assert(sizeof(XrWorldMeshRequestCompletionML) == sizeof(WorldMeshRequestCompletionML),
       |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\include\openxr\openxr_structs.hpp(65406,15): error: static assertion failed due to requirement 'sizeof(XrCreateSpatialPersistenceContextCompletionEXT) == sizeof(xr::CreateSpatialPersistenceContextCompletionEXT)': Original type and wrapper have different size!
 65406 | static_assert(sizeof(XrCreateSpatialPersistenceContextCompletionEXT) ==
       |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 65407 |                   sizeof(CreateSpatialPersistenceContextCompletionEXT),
       |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\include\openxr\openxr_structs.hpp(65406,70): note: expression evaluates to '32 == 40'
 65406 | static_assert(sizeof(XrCreateSpatialPersistenceContextCompletionEXT) ==
       |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
 65407 |                   sizeof(CreateSpatialPersistenceContextCompletionEXT),
       |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\include\openxr\openxr_structs.hpp(66031,15): error: static assertion failed due to requirement 'sizeof(XrPersistSpatialEntityCompletionEXT) == sizeof(xr::PersistSpatialEntityCompletionEXT)': Original type and wrapper have different size!
 66031 | static_assert(sizeof(XrPersistSpatialEntityCompletionEXT) ==
       |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 66032 |                   sizeof(PersistSpatialEntityCompletionEXT),
       |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\include\openxr\openxr_structs.hpp(66031,59): note: expression evaluates to '40 == 48'
 66031 | static_assert(sizeof(XrPersistSpatialEntityCompletionEXT) ==
       |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
 66032 |                   sizeof(PersistSpatialEntityCompletionEXT),
       |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\include\openxr\openxr_structs.hpp(66240,15): error: static assertion failed due to requirement 'sizeof(XrUnpersistSpatialEntityCompletionEXT) == sizeof(xr::UnpersistSpatialEntityCompletionEXT)': Original type and wrapper have different size!
 66240 | static_assert(sizeof(XrUnpersistSpatialEntityCompletionEXT) ==
       |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 66241 |                   sizeof(UnpersistSpatialEntityCompletionEXT),
       |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\include\openxr\openxr_structs.hpp(66240,61): note: expression evaluates to '24 == 32'
 66240 | static_assert(sizeof(XrUnpersistSpatialEntityCompletionEXT) ==
       |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
 66241 |                   sizeof(UnpersistSpatialEntityCompletionEXT),
       |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note: including file:  .\include\openxr\openxr_method_impls.hpp

I'm pretty sure this happens because under the Microsoft ABI a derived class cannot reuse a non-empty base's padding.
This doesn't happen on Linux.
Disabling these extensions works around the issue:

'XR_EXT_spatial_persistence',
'XR_EXT_spatial_persistence_operations',
'XR_ML_spatial_anchors',
'XR_ML_spatial_anchors_storage',
'XR_ML_world_mesh_detection',
  1. A note on backward compatibility: My code also uses the xr::Session::locateViews() "simple" overload, which takes pointers to C types. While the new propperly C++ overloads are obviously better, the change does break compatibility.

@antoineemerit
Copy link
Copy Markdown
Author

antoineemerit commented Mar 27, 2026

@glebov-andrey

about :
"1. The *ToVector() function templates have been removed. Specifically xr::Swapchain::enumerateSwapchainImagesToVectorxr::SwapchainImageVulkanKHR(). Was this intended?"

I totaly missed the templated functions and remove the parameter and code in a previous patch. So I reworked this point and add an auto-detect feature, and for now two functions are templated with the two_call idiom (enumerateSwapchainImagesToVector, enumerateEnvironmentDepthSwapchainImagesToVectorMETA).

Let me know if this fix your first point.

@antoineemerit
Copy link
Copy Markdown
Author

antoineemerit commented Mar 27, 2026

@glebov-andrey

about :
"3. A note on backward compatibility: My code also uses the xr::Session::locateViews() "simple" overload, which takes pointers to C types. While the new propperly C++ overloads are obviously better, the change does break compatibility."

As you saw, my patches replace some C type with C++ type (previously defined but not projected), but it also replace pointer with reference (to avoid null pointer, and write more "natural/modern" code). I also add a list of native C type to project (uint32_t...) and so these pointer are replaced also by reference.

This is to follow "modern C++" concept, and so this cause compatibility issue.

However, you can easily revert to the previous mode by modifing the OpenXR-Hpp/scripts/data.py file as follow :

PROJECTED_NATIVE_C_TYPE = set((
## stop C type projection (pointer -> reference)
#    "int8_t",
#    "int32_t",
#    "int64_t",
#    "uint8_t",
#    "uint32_t",
#    "uint64_t",
#    "float",
#    "XrSpaceUserIdFB",
))

SKIP_PROJECTION = set((
    "XrBaseInStructure",
    "XrBaseOutStructure",

## unproject few OpenXR types
    "XrViewState",
    "XrView",
))

Let me know if this fix your compatibility issue

@antoineemerit
Copy link
Copy Markdown
Author

antoineemerit commented Mar 28, 2026

@glebov-andrey

About :
"3. Some structure layouts are broken under the Microsoft ABI (MSVC or Clang on Windows):"

It seems you're right, the Future base struct include a simple 32 bits Result data member, but the struct size is 16 bytes aligned and so the compiler add 8 bytes padding, which causes, under Winkdows ABI, the derivated classes to have a larger size.

I'm developping under Linux and I don't have a valid Windows environment yet to check and test or modify this point.

I will see later.

Regards

@glebov-andrey
Copy link
Copy Markdown

  1. Looks like it's fixed. Thanks!
  2. Given the restriction on reusing base class padding, it seems like there is no easy way to fix this. But I have come up with a workaround using #pragma pack, which should be fine as long as no one constructs FutureCompletionBaseHeaderEXT directly: https://godbolt.org/z/E976qrGox.
  3. This point was mostly because I don't know what the backward compatibility policy is for this project. Personally, I think the change is quite reasonable.

@antoineemerit
Copy link
Copy Markdown
Author

@glebov-andrey

I defined a specific projection for the XrFutureCompletionBaseHeaderEXT, that take care of the Windows 64bits ABI.

Let me know if this fix works on Windows 64bits.

Regards

@glebov-andrey
Copy link
Copy Markdown

I had to change a few things to get it working:

  1. Move FutureCompletionBaseHeaderEXT out of namespace impl. Alternatively it could be special-cased when deriving - I'm not sure what the best option is.
  2. Change FutureCompletionBaseHeaderEXT's constructor signature to match what is expected by derived structs.
  3. Change FutureCompletionBaseHeaderEXT's base class to OutputStructBase because its next pointer is mutable.
  4. Use wrapperSizeStaticAssert in the non-_WIN64 case so that things don't break on other platforms.
  5. Add #ifdef XR_EXT_future to match generated code. Maybe the whole thing should be moved to after EventDataBuffer for consistency?
  6. Remove XrSpatialAnchorCreateCompletionBD from SKIP_PROJECTION and add XrFutureCompletionBaseHeaderEXT to MANUALLY_PROJECTED (I assume this was a mistake?)
  7. Add alignas(void*) to derived structs. This is required because otherwise some derived structs end up under-aligned and smaller than they should be.

I didn't add get/put functions to FutureCompletionBaseHeaderEXT because they didn't seem to be needed by derived structs, but maybe they should be there for consistency?

I've also checked the offsetof each derived struct's member on MSVC and Clang on Windows - everything looks good.

Here's the diff:

diff --git a/scripts/cpp_generator.py b/scripts/cpp_generator.py
index 8bdec4f..d9a11d9 100644
--- a/scripts/cpp_generator.py
+++ b/scripts/cpp_generator.py
@@ -218,6 +218,12 @@ class StructProjection:
             return "next_"
         return None
 
+    @property
+    def alignas_spec(self):
+        if self.parent_type == "XrFutureCompletionBaseHeaderEXT":
+            return "\n#ifdef _WIN64\nalignas(void*)\n#endif\n"
+        return ""
+
 
 DISPATCH_TEMPLATE_PARAM_NAME = "Dispatch"
 DISPATCH_TEMPLATE_DEFN = f"typename {DISPATCH_TEMPLATE_PARAM_NAME}"
diff --git a/scripts/data.py b/scripts/data.py
index 85d45d9..3ab1561 100644
--- a/scripts/data.py
+++ b/scripts/data.py
@@ -32,6 +32,7 @@ MANUALLY_PROJECTED_SCALARS = set((
 
 MANUALLY_PROJECTED = set((
     "XrEventDataBuffer",
+    "XrFutureCompletionBaseHeaderEXT",
 )).union(MANUALLY_PROJECTED_SCALARS)
 
 PROJECTED_NATIVE_C_TYPE = set((
@@ -48,7 +49,6 @@ PROJECTED_NATIVE_C_TYPE = set((
 SKIP_PROJECTION = set((
     "XrBaseInStructure",
     "XrBaseOutStructure",
-    "XrSpatialAnchorCreateCompletionBD",
 ))
 
 UPPER_TOKENS = set((
diff --git a/scripts/struct.hpp b/scripts/struct.hpp
index 2c6d6b2..fb8c4e4 100644
--- a/scripts/struct.hpp
+++ b/scripts/struct.hpp
@@ -115,7 +115,7 @@
     //! @ingroup structs
 //#     endif
 //# endfilter
-    struct XR_MAY_ALIAS /*{ s.cpp_name }*/ /*{ s.struct_parent_decl }*/
+    struct XR_MAY_ALIAS /*{ s.alignas_spec }*/ /*{ s.cpp_name }*/ /*{ s.struct_parent_decl }*/
     {
 //# if s.typed_struct
     private:
diff --git a/scripts/template_openxr_structs.hpp b/scripts/template_openxr_structs.hpp
index 91a4c77..6cfef86 100644
--- a/scripts/template_openxr_structs.hpp
+++ b/scripts/template_openxr_structs.hpp
@@ -103,30 +103,46 @@ namespace impl {
         void* next;
     };
     /*{ wrapperSizeStaticAssert('::XrBaseOutStructure', 'OutputStructBase') }*/
-
-    #ifdef _WIN64
-        #pragma pack(push, 4)
-    #endif
-    
-    class XR_MAY_ALIAS FutureCompletionBaseHeaderEXT : public InputStructBase {
-    protected:
-        FutureCompletionBaseHeaderEXT(StructureType type_, void *next_) : InputStructBase(type_, next_) {}
-    
-    public:
-        XrResult futureResult;
-    };
-    
-    #ifdef _WIN64
-        #pragma pack(pop)
-    #endif
-
-    #ifdef _WIN64
-        static_assert(sizeof(FutureCompletionBaseHeaderEXT) == 20);
-    #else
-        static_assert(sizeof(FutureCompletionBaseHeaderEXT) == 24);
-    #endif
 }  // namespace impl
 
+#ifdef XR_EXT_future
+#ifdef _WIN64
+    #pragma pack(push, 4)
+#endif
+/*!
+ * C++ projection of XrFutureCompletionBaseHeaderEXT
+ *
+ * Provided by the `XR_EXT_future` extension.
+ *
+ * @see
+ * <https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrFutureCompletionBaseHeaderEXT>
+ * @xrentity{XrFutureCompletionBaseHeaderEXT}
+ * @ingroup abstracttypedstructs
+ */
+class XR_MAY_ALIAS FutureCompletionBaseHeaderEXT : public impl::OutputStructBase {
+private:
+    using Parent = impl::OutputStructBase;
+
+protected:
+    //! Protected constructor: this type is abstract.
+    FutureCompletionBaseHeaderEXT(StructureType type_, const Result& futureResult_,
+                                  void* next_ = nullptr)
+        : Parent(type_, next_), futureResult{futureResult_} {}
+
+public:
+    Result futureResult;
+};
+#ifdef _WIN64
+    #pragma pack(pop)
+#endif
+
+#ifdef _WIN64
+    static_assert(sizeof(FutureCompletionBaseHeaderEXT) == 20);
+#else
+    /*{ wrapperSizeStaticAssert('::XrFutureCompletionBaseHeaderEXT', 'FutureCompletionBaseHeaderEXT') }*/
+#endif
+#endif // XR_EXT_future
+
 //# filter block_doxygen_comment
 //! @brief Wrapper for XrEventDataBuffer
 //!

@antoineemerit antoineemerit changed the title OpenXR SDK 1.1.51 compatibility OpenXR SDK 1.1.57 compatibility Mar 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants