Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partial support for Pico 4 #68023

Merged
merged 1 commit into from
Nov 24, 2022
Merged

Conversation

rsjtdrjgfuzkfg
Copy link
Contributor

@rsjtdrjgfuzkfg rsjtdrjgfuzkfg commented Oct 29, 2022

I attempted to port Godot 4 to the Pico 4, but so far did not succeed to get the whole engine up and running. This PR adds support for the necessary OpenXR extension and injects necessary metadata to permit the engine to start in VR mode.

With this PR, only extremely simple scenes will render properly (with the mobile renderer). I tested this with a scene with the usual XR nodes (origin, camera, controllers) and a world environment with sky shader and unshaded, untextured geometry, on a Pico 4 with Pico OS 5.1. As far as I see, the remaining issues are likely to reside either on the Vulkan side or in the OpenXR-Vulkan interactions.

I hope this PR helps people with more Vulkan / OpenXR / godot core experience to either complete the port or point me in the right direction so I can get further. I'll post a comment on this PR shortly with information about the issues I identified so far and some information about what I tried already. That said, it might be reasonable to merge it as-is and in the meantime and continue the discussion for full Pico 4 support elsewhere, as the two commits in this PR are self-contained.

Similar to Meta/Oculus Quest, Pico devices support OpenXR through a proprietary loader included in their OpenXR SDK download. To test this code in a crude way, it is sufficient to copy the 64-bit libopenxr_loader.so file to platform/android/java/app/libs/dev/arm64-v8a and rebuild the Android export template.

@rsjtdrjgfuzkfg rsjtdrjgfuzkfg requested a review from a team as a code owner October 29, 2022 15:40
@rsjtdrjgfuzkfg
Copy link
Contributor Author

rsjtdrjgfuzkfg commented Oct 29, 2022

I'd love input form the community to overcome the limitations in this PR, towards full support for the Pico 4. I update this comment with new findings as I make them.

If desired, we can move this to a different issue instead of discussing on the PR. Either way, I hope for an expert to support me or take over (@BastiaanOlij ?). I'm stuck, so I'm looking forward to input on what else to try or how to approach the problem in a new direction. :)

The main blocker is that adding shaded or otherwise textured meshes with mobile renderer caused failed pipeline creation: adding a simple mesh without explicit material causes vkCreateGraphicsPipelines to fail with error -13 (VK_ERROR_UNKNOWN) for shader "SceneForwardMobileShaderRD:5". The mesh thus does not render, and performance drops as there are attempts to rebuild the pipeline for each frame. So the question is why the pipeline cannot get created.

Current best guess: something is enabled in the mobile renderer whenever varyings are needed in the context of spatial shaders, which causes the corresponding shaders to not be permissible in a graphics pipeline.

The rest of this post gives some information on what I tried so far or that I considered relevant to the question. Feel free to ask for clarifications / more details when I missed something!


Vulkan Validation Layer

Vulkan validation layers give quite a few violations, but I believe the issues identified before the pipeline creation either are not relevant or fixable, but the fix did not help:

[ VUID-VkSwapchainCreateInfoKHR-imageExtent-01274 ] | vkCreateSwapchainKHR() called with imageExtent = (4320,2160), which is outside the bounds returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (4320,2160), minImageExtent = (1,1), maxImageExtent = (4096,4096). The Vulkan spec states: imageExtent must be between minImageExtent and maxImageExtent, inclusive, where minImageExtent and maxImageExtent are members of the VkSurfaceCapabilitiesKHR structure returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR for the surface (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageExtent-01274)

This warning seems to be caused by the app starting in non-VR mode (until a script sets the viewport's use_xr), but the Pico does not provide a standard-compliant "normal" rendering surface. The warning can be worked around by not adding the metadata for VR mode, which does avoid this message but causes the then-unused activity to float as black square in VR space. Working around the issue does not, however, fix and rendering issues.

This warning also occurs when starting godot on a scene that does render properly.

[ VUID-VkImageSubresourceRange-levelCount-01720 ] | vkCreateImageView: pCreateInfo->subresourceRange.levelCount is 0. The Vulkan spec states: If levelCount is not VK_REMAINING_MIP_LEVELS, it must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkImageSubresourceRange-levelCount-01720)

Switching to VK_REMAINING_MIP_LEVELS fixed the warning, but did not fix rendering issues.

This warning also occurs when starting godot on a scene that does render properly.

[ VUID-VkImageViewCreateInfo-image-01762 ] | vkCreateImageView() format VK_FORMAT_R8G8B8A8_UNORM differs from VkImage [...] format VK_FORMAT_R8G8B8A8_SRGB. Formats MUST be IDENTICAL unless VK_IMAGE_CREATE_MUTABLE_FORMAT BIT was set on image creation. The Vulkan spec states: If image was not created with the VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT flag, or if the format of the image is a multi-planar format and if subresourceRange.aspectMask is VK_IMAGE_ASPECT_COLOR_BIT, format must be identical to the format used to create image (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01762)

Can be fixed by passing the correct formats, but that messes up colors (as explained in the comment in the source code, we're intentionally violating spec there) and does not fix the actual rendering issues. Maybe it could also be fixed by setting VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, I did not try that.

This warning also occurs when starting godot on a scene that does render properly.

[ VUID-VkImageMemoryBarrier-newLayout-parameter ] | vkCmdPipelineBarrier: value of pImageMemoryBarriers[0].newLayout ([...]) does not fall within the begin..end range of the core VkImageLayout enumeration tokens and is not an extension added token. The Vulkan spec states: newLayout must be a valid VkImageLayout value (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkImageMemoryBarrier-newLayout-parameter)

We pass unitialized memory as newLayout to vkCmdPipelineBarrier, I tried VK_IMAGE_LAYOUT_GENERAL as well as deriving the layout from the usage_flags, both fixed the warning but not the rendering issues.

This warning also occurs when starting godot on a scene that does render properly.

[ VUID-vkQueueSubmit-fence-00063 ] | vkQueueSubmit(): VkFence 0x7eab950000000728[] submitted in SIGNALED state. Fences must be reset before being submitted The Vulkan spec states: If fence is not VK_NULL_HANDLE, fence must be unsignaled (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkQueueSubmit-fence-00063)

This warning appears when switching from the non-VR to the VR swapchain. I initially believed it is likely this is caused by the timing of the switch, but this warning is triggered again later on, possibly for each frame.

This warning also occurs when starting godot on a scene that does render properly. Similar warnings will then continue throughout the run of the application, likely every frame.

[ VUID-VkRenderPassCreateInfo2-pNext-pNext ] | vkCreateRenderPass2KHR: pCreateInfo->pNext chain includes a structure with unexpected VkStructureType VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO; Allowed structures are [VkRenderPassCreationControlEXT, VkRenderPassCreationFeedbackCreateInfoEXT, VkRenderPassFragmentDensityMapCreateInfoEXT]. This error is based on the Valid Usage documentation for version 224 of the Vulkan header. It is possible that you are using a struct from a private extension or an extension that was added to a later version of the Vulkan header, in which case the use of pCreateInfo->pNext is undefined and may not work correctly with validation enabled The Vulkan spec states: Each pNext member of any structure (including this one) in the pNext chain must be either [message is cut here]

This warning appears due to us passing a VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO; a comment suggested it is no longer needed, I did remove it and that fixed the warning without changing anything else (as far as I can see, at least).

This warning also occurs when starting godot on a scene that does render properly.

[ VUID-VkRenderPassCreateInfo2-attachment-02525 ] | vkCreateRenderPass2KHR(): Using format (VK_FORMAT_A2B10G10R10_UNORM_PACK32) with aspect flags (VK_IMAGE_ASPECT_NONE) but color image formats must have the VK_IMAGE_ASPECT_COLOR_BIT set. The Vulkan spec states: If the attachment member of any element of the pInputAttachments member of any element of pSubpasses is not VK_ATTACHMENT_UNUSED, the aspectMask member of that element of pInputAttachments must only include aspects that are present in images of the format specified by the element of pAttachments specified by attachment (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2-attachment-02525)

Adding VK_IMAGE_ASPECT_COLOR_BIT fixed the warning but did not fix rendering.

This warning also occurs when starting godot on a scene that does render properly.

[ VUID-VkSubpassDescription2-attachment-02800 ] | vkCreateRenderPass2KHR(): Input attachment pSubpasses[3].pInputAttachments[0] aspect mask must not be 0. The Vulkan spec states: If the attachment member of any element of pInputAttachments is not VK_ATTACHMENT_UNUSED, then the aspectMask member must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkSubpassDescription2-attachment-02800)

Passing the VK_IMAGE_ASPECT_COLOR_BIT as indicated by a comment fixes the warning, but not rendering.

This warning also occurs when starting godot on a scene that does render properly.


Debugging / Experimentation

Besides looking at validation layers, I also did some debugging on possible causes, both with a debugger and by experimenting, but that did not yield tangible results. From what I tested, any mesh with a shader using varyings (either explicit or implicit) fails to render. That said, rendering does work with the same renderer in non-VR mode.

The forward_plus renderer on the other hand does kind of work in VR. With this PR applied, the scene renders all elements but I get a lot of vulkan validation layer issues, the performance is terrible and the display and tracking of the Pico 4 occasionally glitches. I did not spend a lot of time debugging the forward_plus renderer, though.

In scenes that do render properly, there are still constant validation errors (VUID-vkQueueSubmit-fence-00064, UID-vkQueueSubmit-fence-00063, VUID-VkPresentInfoKHR-pImageIndices-01296), not sure if these are normal or also related to a Pico-specific issue.

Performing the changes in this PR in Godot 3.5 with the add-on mostly works as expected. The demo scene renders properly. The issues thus seem to be Vulkan-related. The only issue in 3.5 is that the controllers are stuck on the simple_controller interaction profile, which seems fixable though I did not instantly see how (the same issue likely also exists in 4.0, but I did not get that far ;) ).


Metadata that might help

Vulkan and OpenXR information / Metadata what the Pico 4 looks like from Godot for reference (from --verbose startup):

OpenXR: Found OpenXR extension XR_KHR_android_create_instance
OpenXR: Found OpenXR extension XR_KHR_android_surface_swapchain
OpenXR: Found OpenXR extension XR_KHR_composition_layer_color_scale_bias
OpenXR: Found OpenXR extension XR_KHR_composition_layer_cube
OpenXR: Found OpenXR extension XR_KHR_composition_layer_cylinder
OpenXR: Found OpenXR extension XR_KHR_composition_layer_equirect
OpenXR: Found OpenXR extension XR_KHR_composition_layer_equirect2
OpenXR: Found OpenXR extension XR_KHR_convert_timespec_time
OpenXR: Found OpenXR extension XR_KHR_loader_init
OpenXR: Found OpenXR extension XR_KHR_loader_init_android
OpenXR: Found OpenXR extension XR_KHR_opengl_es_enable
OpenXR: Found OpenXR extension XR_KHR_vulkan_enable
OpenXR: Found OpenXR extension XR_KHR_vulkan_enable2
OpenXR: Found OpenXR extension XR_KHR_vulkan_swapchain_format_list
OpenXR: Found OpenXR extension XR_EPIC_view_configuration_fov
OpenXR: Found OpenXR extension XR_EXT_eye_gaze_interaction
OpenXR: Found OpenXR extension XR_EXT_hand_tracking
OpenXR: Found OpenXR extension XR_EXT_view_configuration_depth_range
OpenXR: Found OpenXR extension XR_EXT_performance_settings
OpenXR: Found OpenXR extension XR_EXTX_overlay
OpenXR: Found OpenXR extension XR_FB_composition_layer_image_layout
OpenXR: Found OpenXR extension XR_FB_composition_layer_secure_content
OpenXR: Found OpenXR extension XR_FB_composition_layer_alpha_blend
OpenXR: Found OpenXR extension XR_FB_display_refresh_rate
OpenXR: Found OpenXR extension XR_FB_swapchain_update_state
OpenXR: Found OpenXR extension XR_FB_foveation
OpenXR: Found OpenXR extension XR_FB_foveation_configuration
OpenXR: Found OpenXR extension XR_FB_foveation_vulkan
OpenXR: Found OpenXR extension XR_MND_headless
OpenXR: Found OpenXR extension XR_PICO_ipd
OpenXR: Found OpenXR extension XR_PICO_view_ipd
OpenXR: Found OpenXR extension XR_PICO_view_frustum_ext
OpenXR: Found OpenXR extension XR_PICO_view_frustum
OpenXR: Found OpenXR extension XR_PICO_configs_ext
OpenXR: Found OpenXR extension XR_PICO_configuration
OpenXR: Found OpenXR extension XR_PICO_reset_sensor
OpenXR: Found OpenXR extension XR_PICO_boundary
OpenXR: Found OpenXR extension XR_PICO_view_state_ext_enable
OpenXR: Found OpenXR extension XR_PICO_view_state
OpenXR: Found OpenXR extension XR_PICO_frame_end
OpenXR: Found OpenXR extension XR_PICO_frame_end_info_ext
OpenXR: Found OpenXR extension XR_PICO_mrc_pose_ext_enable
OpenXR: Found OpenXR extension XR_PICO_mrc_pose
OpenXR: Found OpenXR extension XR_PICO_android_controller_function_ext_enable
OpenXR: Found OpenXR extension XR_PICO_controller_interaction
OpenXR: Found OpenXR extension XR_PICO_hand_tracking
OpenXR: Found OpenXR extension XR_PICO_eye_tracking
OpenXR: Found OpenXR extension XR_PICO_body_tracking
OpenXR: Found OpenXR extension XR_PICO_MetricsTool_ext
OpenXR: Found OpenXR extension XR_PICO_performance_metrics
OpenXR: Found OpenXR extension XR_EXT_debug_utils
OpenXR: Running on OpenXR runtime:  Pico(XRT) by Pico et al 'de86b93'   3.0.1
OpenXR: Found supported view configuration XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO
OpenXR: Found supported view configuration view
 - width: 2560
 - height: 2560
 - sample count: 1
 - recommended render width: 1440
 - recommended render height: 1584
 - recommended render sample count: 1
OpenXR: Found supported view configuration view
 - width: 2560
 - height: 2560
 - sample count: 1
 - recommended render width: 1440
 - recommended render height: 1584
 - recommended render sample count: 1
OpenXR: XrGraphicsRequirementsVulkan2KHR:
 - minApiVersionSupported:  1.0.0
 - maxApiVersionSupported:  1023.1023.1023
Vulkan API 1.1.0 - Using Vulkan Device #0: Qualcomm - Adreno (TM) 650
- Vulkan Variable Rate Shading not supported
- Vulkan multiview supported:
  max view count: 6
  max instances: 4294967295
- Vulkan subgroup:
  size: 64
  stages: STAGE_COMPUTE
  supported ops: FEATURE_BASIC, FEATURE_VOTE, FEATURE_ARITHMETIC, FEATURE_BALLOT, FEATURE_SHUFFLE, FEATURE_SHUFFLE_RELATIVE
Using present mode: VK_PRESENT_MODE_FIFO_KHR

OpenXR Interaction profile /interaction_profiles/hp/mixed_reality_controller is not supported on this runtime
OpenXR Interaction profile /interaction_profiles/samsung/odyssey_controller is not supported on this runtime
OpenXR Interaction profile /interaction_profiles/htc/vive_cosmos_controller is not supported on this runtime
OpenXR Interaction profile /interaction_profiles/htc/vive_focus3_controller is not supported on this runtime
OpenXR: Found supported reference space XR_REFERENCE_SPACE_TYPE_VIEW
OpenXR: Found supported reference space XR_REFERENCE_SPACE_TYPE_LOCAL
OpenXR: Found supported reference space XR_REFERENCE_SPACE_TYPE_STAGE
OpenXR: Found supported swapchain format VK_FORMAT_R8G8B8A8_UNORM
OpenXR: Found supported swapchain format VK_FORMAT_A2B10G10R10_UNORM_PACK32
OpenXR: Found supported swapchain format VK_FORMAT_R16G16B16A16_SFLOAT
OpenXR: Found supported swapchain format VK_FORMAT_R8G8B8A8_SRGB
OpenXR: Found supported swapchain format VK_FORMAT_B8G8R8A8_UNORM
OpenXR: Found supported swapchain format VK_FORMAT_B8G8R8A8_SRGB
OpenXR: Found supported swapchain format VK_FORMAT_B8G8R8_UNORM

OpenXR: Interaction profile for /user/hand/left changed to /interaction_profiles/khr/simple_controller
OpenXR: Interaction profile for /user/hand/right changed to /interaction_profiles/khr/simple_controller

@BastiaanOlij
Copy link
Contributor

Hey @rsjtdrjgfuzkfg ,

The current version of Godot will attempt to load the loader externally, have a look at: https://github.com/GodotVR/godot_openxr_loaders
In theory you should be able to replicate what we're doing there for the meta loader, but insert the PICO loader and add all the meta data info in there. The idea here is to have all the different loaders all in a single asset and you choose the one that you want to use in the export settings. There shouldn't need to be any changes in Godot itself to make this work.

@kisg @konczg , I was surprised that we no longer have XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME and XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME in the android extension, those extensions should still be enabled even for Quest right?

I am worried about all the errors you're getting in the log, Godot certainly will be slowed down a lot if its spamming the log on each frame. Sounds like the PICO has very incapable Vulkan drivers. That said, @clayjohn and I have been hunting situations where GPUs that only support Vulkan 1.0 and non of the required extensions aren't being properly detected and therefor having Godot wrongfully try to do things that cant be done. I would have expected PICO to have pretty up to date Vulkan support though..

@rsjtdrjgfuzkfg
Copy link
Contributor Author

@BastiaanOlij thanks for your response!

Yes, the loader can be distributed as android plugin, placing it in libs as explained in the first post is just to speed up testing and not a permanent solution. It is not necessary to make changes beyond this PR in core godot, I tried to keep everything similar to how Meta/Oculus is handled at the moment (metadata in core, loader from an asset). If it helps I can also provide you with a PR against GodotVR/godot_openxr_loaders for everything but the .so file?

I'd not be comfortable to include the .so file myself for legal concerns around the loader's license not permitting redistribution outside of concrete applications. That said, we might get a clear official permission from Pico to redistribute the loader as part of the XR asset and its repository if we ask them nicely? I can ask, but somebody publicly associated with godot might have better chances.

I am worried about all the errors you're getting in the log, Godot certainly will be slowed down a lot if its spamming the log on each frame.
All quoted errors only occur with validation layers turned on. But even with them, performance is surprisingly not as bad as it sounds.

To have something to compare against: did you run the current main branch on a Quest with validation layers? How much / which messages do you get there? I don't have a Quest to test.

Quite a few of the messages seems to me to be obvious bugs in godot (like passing uninitialised memory, that can't be right, can it?). I plan to provide a PR for those once I get things to render, but as I'm not very experienced with Vulkan yet I want to take things one step at a time.

@BastiaanOlij
Copy link
Contributor

BastiaanOlij commented Nov 1, 2022

@rsjtdrjgfuzkfg

You're joking that PICO does not allow redistribution of their loader? Whats wrong with these companies? Do they not want their devices to be used or something? That doesn't just effect us, that will make it harder for Unity and Unreal to distribute builds that support the PICO as well.

It's a ****ing loader, there is no IP embedded in it, geez.... /end rant

A few things in this PR do need to move into the loader and I'm waiting on @kisg and/or @konczg to react on the Android changes, we always had that bit in the Godot 3 plugin so I'm not sure why they haven't been reproduced here. It's possible with all their changes it already happens but through another mechanism.

I don't remember seeing validation errors on my side but I have to admit most of my testing has been on desktop, once I'm through my current workload I will do some testing on my end as well.

As for what stands out:

vkCreateSwapchainKHR() called with imageExtent = (4320,2160), which is outside the bounds returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (4320,2160), minImageExtent = (1,1), maxImageExtent = (4096,4096)

Ok, I think this is because we're still initializing Godot as a normal application, we initially allocate a buffer at the size of the display, which likely is a 4320x2160 panel, but it seems larger then their GPU allows (weird, very very weird).
Then once XR mode is enabled we're switching over to stereoscopic rendering at the resolution PICO suggest per eye, which likely fits within the 4096x4096 limit.
I do wonder that if their Vulkan driver doesn't support the full panel size, how are they outputting the final results?

I guess we could check for min and max and clamp it, @clayjohn what do you think?

vkCreateImageView: pCreateInfo->subresourceRange.levelCount is 0. The Vulkan spec states

Not sure where that is coming from, I'm guessing when we create the subviews to access the individual layers of the stereo image. But that is code that is used all over the place in Godot so not sure why it suddenly doesn't like the setup.
Sounds like levelCount might need to be 1?

vkCreateImageView() format VK_FORMAT_R8G8B8A8_UNORM differs from VkImage [...] format VK_FORMAT_R8G8B8A8_SRGB

That's really weird that we run into this now but good to know. For the most part Godot runs _UNORM only and does it's own SRGB handling but this gives us problems with OpenXR. We thus do use _SRGB buffers in OpenXR and I actually want to investigate doing the same for Godot itself and letting the hardware handle conversions.
So far I haven't seen any GPUs complain about needing the bit but it should be as easy as adding this to the OpenXR module where we're creating the swapchain.

vkCmdPipelineBarrier: value of pImageMemoryBarriers[0].newLayout ([...]) does not fall within the begin..end range of the core VkImageLayout enumeration tokens and is not an extension added token

This one is worrisome but also easy to fix if it is just uninitialized memory. I've noticed that the compilers used for Android don't clear memory the same way desktop compilers do, I've run into this before with other commands.

edit having a search through the code, every place vkCmdPipelineBarrier is providing image barriers, the image barriers are fully configured and newLayout is definately set.
But there are a few places where the newLayout is coming from the image, so we may have the wrong layout set in our OpenXR module somewhere.

vkQueueSubmit(): VkFence 0x7eab950000000728[] submitted in SIGNALED state

I have a feeling this may just be a flow on effect of the failed vkCmdPipelineBarrier...

vkCreateRenderPass2KHR: pCreateInfo->pNext chain includes a structure with unexpected VkStructureType VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO; Allowed structures are [VkRenderPassCreationControlEXT, VkRenderPassCreationFeedbackCreateInfoEXT

This one is weird because from the log the multiview extension is available. That said, things did change with the introduction of vkCreateRenderPass2KHR so indeed it may not be needed anymore.
We should probably only be sending this structure through if vkCreateRenderPass2KHR is not supported and vkCreateRenderPass is used.
That said, I need to see how we can make that work in the fallback.

vkCreateRenderPass2KHR(): Using format (VK_FORMAT_A2B10G10R10_UNORM_PACK32) with aspect flags (VK_IMAGE_ASPECT_NONE) but color image formats must have the VK_IMAGE_ASPECT_COLOR_BIT set.

That does make sense, indeed suggest to add that bit.

vkCreateRenderPass2KHR(): Input attachment pSubpasses[3].pInputAttachments[0] aspect mask must not be 0

Indeed should be fixed by adding the bit.

All in all I think the error caused by uninitialized memory is the one that is most important.

@BastiaanOlij
Copy link
Contributor

@rsjtdrjgfuzkfg

Can you give #68102 a try? This I think will deal with the most pressing validation errors.

@kisg
Copy link
Contributor

kisg commented Nov 1, 2022

Hi, we have national holidays today and tomorrow, that is why we have been silent. :) We will back on the 2nd November.

@rsjtdrjgfuzkfg
Copy link
Contributor Author

rsjtdrjgfuzkfg commented Nov 1, 2022

@BastiaanOlij thanks for the review and #68102! I posted test results regarding the validation errors and a note regarding the device capabilities there. Similar to my more crude workarounds, the failed pipeline issue persists but most warnings were fixed. There is only one remaining warning that could point to the main issue (VUID-vkQueueSubmit-fence-00063) and one for each frame while rendering works (VUID-VkPresentInfoKHR-pImageIndices-01296).

You're joking that PICO does not allow redistribution of their loader?

Not intentionally, but IANAL, so maybe I just misunderstand their terms. The official unity / unreal plugins seem to only be available from their website, under the same license.

Regarding this PR: I'll split things up as requested in the review.

@BastiaanOlij
Copy link
Contributor

Regarding this PR: I'll split things up as requested in the review.

Make sure to wait until @kisg and @konczg are back from their annual leave, they're the architects to the AAR loader approach and will have more insight to offer.

@rsjtdrjgfuzkfg
Copy link
Contributor Author

rsjtdrjgfuzkfg commented Nov 1, 2022

@BastiaanOlij well, it was too late for the PR against the loader repo :D
But I'll wait updating this PR to not trash discussions.

From my POV the second commit on this PR is now obsolete, and replaced by GodotVR/godot_openxr_vendors#13

Edit: I also posted a comment with remaining validation layer issues in #68102, maybe seeing things in the exact order and context helps to identify remaining issues.

@konczg
Copy link
Contributor

konczg commented Nov 2, 2022

@BastiaanOlij

@kisg @konczg , I was surprised that we no longer have XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME and XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME in the android extension, those extensions should still be enabled even for Quest right?

I have checked and neither XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME nor XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME were included as a required extension, even before the introduction of the dynamic loading of OpenXR loaders. I think the reason it still worked with Quest is that the Meta OpenXR loader might not require such additional information upon initialization. But I agree that they should be added to OpenXRAndroidExtension.

@konczg
Copy link
Contributor

konczg commented Nov 2, 2022

We have reviewed the addition of the Pico Loader to godot_openxr_loaders with @korompg, and it seems fine

@BastiaanOlij
Copy link
Contributor

I have checked and neither XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME nor XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME were included as a required extension

Yeah I think I'm mixing this up with the code we had that performed the android init even before the openxr instance is created.
Reading up on the OpenXR spec, I think these should indeed be added to the android extension.

jobject activity_object = env->NewGlobalRef(static_cast<OS_Android *>(OS::get_singleton())->get_godot_java()->get_activity());

instance_create_info_next = memalloc(sizeof(XrInstanceCreateInfoAndroidKHR));
*reinterpret_cast<XrInstanceCreateInfoAndroidKHR *>(instance_create_info_next) = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that Godot has build in memory functions/macros that should be used.

That said, look at the other extensions where we add structures, the pattern we're following is to make this a member variable of the class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched to a static instance in the cpp to match the pattern you suggested (the vulkan extension uses a static class member, which has pretty much the same properties), but can't say I love it as it ties a static instance to all instances of the class. That said, it should be reasonably safe and work, as there is at most one instance. I guess some uglyness can't be avoided, just like the leaked global reference to the activity – which I copied, so now there are two of those ;)

Note that it would not be possible to place the instance into the class without major changes, as the struct is defined within openxr_platform.h, whose content varies depending on the #defines that were set up before the first include in each compile unit. As long as different extensions use different parts of openxr_platform.h, use of that header from other headers should be avoided.

I'd propose to also change the vulkan extension to match whatever pattern we decide on for the android extension, as the vulkan extension includes the header in the header already and thus might cause issues down the road. Alternatively we could also move all relevant #defines out of the extensions to make including openxr_platform.h safe from headers, though that likely comes with its own problems.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The extensions are instanced as singletons so the variable itself can be a member variable of the class, it doesn't need to be static. Same for your JAVA instance variable.

The extension instances are also cleaned up when the OpenXR singleton is destroyed though I suspect there might be some timing issues there so that should allow us to do any cleanup needed.

Including the needed platform headers in order to properly include OpenXR has been a pain in my behind because it screws up other parts of the system. Especially on windows once windows.h is included it causes a lot of pain.

But it seems we can't internalize this enough, I wish there was a solid way to ensure only the .cpp files of the extensions were required to include the needed parts of OpenXR.

Defo welcome for suggestions but lets not let your PR hang on that improvement.

Copy link
Contributor Author

@rsjtdrjgfuzkfg rsjtdrjgfuzkfg Nov 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it doesn't need to be static.

My comment on a static member was regarding the vulkan extension I looked at for reference, that one uses a static member for its next chain entry.

Same for your JAVA instance variable.

I can add cleanup for the jobject, but would prefer to treat both instances the same (so the cleanup should also apply to the instance passed via xrInitializeLoaderKHR in OpenXRAndroidExtension::on_before_instance_created). My assumption was, however, that the missing cleanup was intentional, as the standard does not clearly state whether OpenXR assumes ownership or creates its own reference.

Defo welcome for suggestions

Imho a void pointer in the class and memalloc memfree are a bit nicer, but I can live without that. But I think you did not want me to use those two, and have other godot memory macros to use? Either way, I'm also fine merging as-is.

I wish there was a solid way to ensure only the .cpp files of the extensions were required to include the needed parts of OpenXR

We could go the pimpl (header does not contain any implementation details) or pure abstract / interface route (header does not contain the class at all, but only a factory method). The latter is probably nicer. But both are not in the scope of this PR imho.

This commit adds support for the OpenXR extension
XR_KHR_android_create_instance, which seems to be required on Pico
devices.
@rsjtdrjgfuzkfg
Copy link
Contributor Author

A short update: behind the scenes @BastiaanOlij and myself were discussing with engineers from Pico, which permitted us to identify the rendering issue as bug or incompatibility within the current vulkan driver on the headset. Engineering builds of Pico OS supposedly already work with this PR. In addition, they provided us with the correct mapping for the Pico's controllers and cleared up our licensing concerns, so we're on a good track towards full Pico 4 support. \o/

Copy link
Contributor

@BastiaanOlij BastiaanOlij left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After talking with @rsjtdrjgfuzkfg , we can likely merge this PR though it mostly contains generic improvements to the Android support in OpenXR.

For PICO specific there are:

@akien-mga akien-mga merged commit c39c251 into godotengine:master Nov 24, 2022
@akien-mga
Copy link
Member

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants