File plugin.hpp
File List > openxr_interface > plugin.hpp
Go to the documentation of this file
#pragma once
#ifdef USING_OPENXR
// Vulkan must be included before OpenXR so the platform defines are in scope.
# ifndef XR_USE_GRAPHICS_API_VULKAN
# define XR_USE_GRAPHICS_API_VULKAN
# endif
# ifndef XR_USE_PLATFORM_ANDROID
# define XR_USE_PLATFORM_ANDROID
# endif
# include "illixr/data_format/frame.hpp"
# include "illixr/data_format/latency_data.hpp"
# include "illixr/data_format/poses/combined_pose.hpp"
# include "illixr/data_format/vulkan_context.hpp"
# ifdef ILLIXR_ENABLE_BOBA
# include "illixr/stoplight.hpp"
# endif
# include "illixr/switchboard.hpp"
# include "illixr/threadloop.hpp"
# include "illixr/vk/vulkan_context_provider.hpp"
# include "oxr_relay.hpp"
# include "stereo_renderer.hpp"
# include
# include
# include
# include
# ifdef ILLIXR_DUMP_FRAMES
# include "frame_dumper.hpp"
# endif
# define USING_APP_SPACEWARP
// Guard for extension name macro that may not be present in older OpenXR headers
# ifndef XR_EXT_HAND_INTERACTION_EXTENSION_NAME
# define XR_EXT_HAND_INTERACTION_EXTENSION_NAME "XR_EXT_hand_interaction"
# endif
namespace ILLIXR {
class oxr_interface
: public threadloop
, public vk::vulkan_context_provider {
public:
[[maybe_unused]] oxr_interface(const std::string& name_, phonebook* pb_);
~oxr_interface() override;
void _p_thread_setup() override;
XrSession session() const {
return session_;
}
XrInstance instance() const {
return instance_;
}
protected:
void _p_one_iteration() override;
void start() override;
void stop() override;
private:
// Swapchain management
void create_swapchains();
// OpenXR lifecycle
void init_xr();
void create_session();
void poll_events();
void run_frame();
// void rx_latency(const switchboard::ptr& datum);
// ==================== Member Variables ====================
const std::shared_ptr<switchboard> switchboard_;
struct android_app* app_;
const std::shared_ptr<relative_clock> clock_;
# ifdef ILLIXR_ENABLE_BOBA
const std::shared_ptr<stoplight> stoplight_;
# endif
// Frame reading
switchboard::reader<data_format::dual_frames> frame_reader_;
# ifdef ILLIXR_ENABLE_BOBA
// Host lifecycle message delivered over the reliable network backend.
switchboard::reader<switchboard::event_wrapper<std::string>> boba_client_control_reader_;
# endif
std::shared_ptr<const data_format::dual_frames> current_frames_ = nullptr;
# ifdef ILLIXR_ENABLE_BOBA
bool client_shutdown_requested_{false};
# endif
// OpenXR handles
XrSession session_ = XR_NULL_HANDLE;
XrInstance instance_ = XR_NULL_HANDLE;
XrSystemId system_id_ = XR_NULL_SYSTEM_ID;
XrSpace local_space_ = XR_NULL_HANDLE;
XrSpace view_space_ = XR_NULL_HANDLE;
XrSessionState session_state_ = XR_SESSION_STATE_UNKNOWN;
XrBool32 session_running_ = XR_FALSE;
XrViewConfigurationView view_configs_[2]{};
XrView views_[2]{};
# ifdef ILLIXR_ENABLE_BOBA
// World-panel anchor persists across head motion until presentation mode changes.
bool world_panel_anchor_initialized_{false};
XrPosef world_panel_pose_{};
data_format::stereo_presentation_mode previous_presentation_mode_{data_format::stereo_presentation_mode::stereo_fullscreen};
# endif
// Vulkan device objects
VkInstance vk_instance_ = VK_NULL_HANDLE;
VkPhysicalDevice vk_physical_device_ = VK_NULL_HANDLE;
VkDevice vk_device_ = VK_NULL_HANDLE;
VkQueue vk_queue_ = VK_NULL_HANDLE;
uint32_t vk_queue_family_ = 0;
// Published to the phonebook after create_session() so other plugins
// (e.g. offload_rendering_client) can obtain the Vulkan context without
// a direct dependency on oxr_interface.
std::shared_ptr<data_format::vulkan_device_context> vk_context_;
std::vector<XrApiLayerProperties> layer_properties_;
std::vector<const char*> required_extensions_;
std::vector<XrExtensionProperties> extension_properties_;
// Swapchains
struct swapchain_info {
XrSwapchain swapchain = XR_NULL_HANDLE;
uint32_t width = 0;
uint32_t height = 0;
std::vector<XrSwapchainImageVulkan2KHR> images;
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
};
std::array<swapchain_info, 2> swapchains_{};
// Per-eye depth swapchains (only valid when use_depth_ && depth_extension_supported_)
std::array<swapchain_info, 2> depth_swapchains_{};
# ifndef USING_APP_SPACEWARP
VkFormat depth_format_ = VK_FORMAT_D16_UNORM;
# else
VkFormat depth_format_ = VK_FORMAT_D32_SFLOAT;
// One motion-vector swapchain per eye (432×432, R16G16B16A16_SFLOAT).
// The App Spacewarp runtime consumes these to extrapolate intermediate frames.
std::array<swapchain_info, 2> mv_swapchains_{};
VkFormat mv_swapchain_format_ = VK_FORMAT_R16G16B16A16_SFLOAT;
# endif
// Rendering
std::unique_ptr<stereo_renderer> renderer_;
// Previous frame's dual_frames (held until GPU finishes)
std::shared_ptr<const data_format::dual_frames> prev_frames_ = nullptr;
# ifdef ILLIXR_DUMP_FRAMES
std::unique_ptr<frame_dumper> dumper_[2];
# endif
uint64_t frame_counter_{0};
// ==================== Depth Extension State ====================
bool use_depth_{false};
bool depth_extension_supported_{false};
// App Spacewarp (XR_FB_space_warp)
// True when the runtime reports XR_FB_SPACE_WARP_EXTENSION_NAME.
bool spacewarp_supported_{false};
std::shared_ptr<oxr_relay> oxr_relay_;
// std::atomic next_frame_id_{0};
# ifdef ILLIXR_ENABLE_BOBA
int headset_width_ = NATIVE_STREAM_EYE_WIDTH;
int headset_height_ = NATIVE_STREAM_EYE_HEIGHT;
# else
int headset_width_ = HEADSET_WIDTH;
int headset_height_ = HEADSET_HEIGHT;
double overscan_;
# endif
};
} // namespace ILLIXR
#endif