File plugin.hpp
File List > controller > plugin.hpp
Go to the documentation of this file
#pragma once
#define GL_GLEXT_PROTOTYPES
#define XR_USE_PLATFORM_XLIB
#define XR_USE_GRAPHICS_API_OPENGL
#define GLFW_EXPOSE_NATIVE_X11
#define GLFW_EXPOSE_NATIVE_GLX
#include "illixr/data_format/openxr_view_frame.hpp"
#include "illixr/data_format/quest_controller.hpp"
#include "illixr/data_format/stereo_frame.hpp"
#include "illixr/plugin.hpp"
#include "illixr/relative_clock.hpp"
#include "illixr/stoplight.hpp"
#include "illixr/switchboard.hpp"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace ILLIXR {
class openxr_quest_controller final : public plugin {
public:
openxr_quest_controller(const std::string& name, phonebook* pb);
~openxr_quest_controller() override;
void start() override;
void stop() override;
private:
using controller_input = data_format::quest_controller_input;
using hand_controller = data_format::quest_hand_controller;
using controller_pose = data_format::quest_controller_pose;
using controller_button = data_format::quest_controller_button;
using controller_axis2d = data_format::quest_controller_axis2d;
using controller_profile = data_format::quest_controller_profile;
using view_frame = data_format::openxr_view_frame;
using eye_view = data_format::openxr_eye_view;
using stereo_frame = data_format::stereo_frame;
struct mapped_file {
int fd{-1};
const std::uint8_t* data{nullptr};
std::size_t size{0};
std::string path;
mapped_file() = default;
mapped_file(const mapped_file&) = delete;
mapped_file& operator=(const mapped_file&) = delete;
~mapped_file();
void reset();
};
struct swapchain_view {
XrSwapchain handle{XR_NULL_HANDLE};
std::uint32_t width{0};
std::uint32_t height{0};
std::vector<XrSwapchainImageOpenGLKHR> images;
};
// Hidden desktop OpenGL context used to create the OpenXR GLX binding.
void initialize_graphics();
void destroy_graphics();
bool resolve_glx_binding();
// OpenXR lifecycle and per-frame event/render loop.
void run();
bool initialize_openxr();
void destroy_openxr();
bool pump_events();
bool process_frame();
bool enumerate_view_configuration();
bool query_views(XrTime sample_time, view_frame* views);
// Swapchain, shared-ring upload, and compositor submission.
bool create_swapchains();
void destroy_swapchains();
bool initialize_stereo_renderer();
void destroy_stereo_renderer();
bool update_stereo_frame();
bool ensure_mapped(const std::string& path, mapped_file* mapping);
bool ensure_source_textures(std::uint32_t width, std::uint32_t height);
bool render_projection_layer(XrCompositionLayerProjection* layer,
std::array<XrCompositionLayerProjectionView, 2>* projection_views);
bool render_eye(std::size_t eye_index, GLuint swapchain_image);
// Controller action creation and cross-runtime binding suggestions.
bool create_actions();
bool suggest_bindings();
bool create_action(XrActionType type, const char* name, const char* localized_name, XrAction* action);
bool create_action_space(XrAction action, XrPath hand_path, XrSpace* space, const char* label);
bool add_binding(std::vector<XrActionSuggestedBinding>* bindings, XrAction action, const char* path_string);
bool suggest_profile_bindings(const char* profile_string, const std::vector<XrActionSuggestedBinding>& bindings);
// Per-frame action-state queries. Inactive sources remain explicit neutral values.
bool query_hand(std::size_t hand_index, XrTime sample_time, hand_controller* hand);
bool query_pose(XrAction action, XrSpace action_space, XrPath hand_path, XrTime sample_time, controller_pose* pose);
bool query_boolean(XrAction action, XrPath hand_path, controller_button* button);
bool query_float(XrAction action, XrPath hand_path, float pressed_threshold, controller_button* button);
bool query_axis2d(XrAction action, XrPath hand_path, controller_axis2d* axis);
bool refresh_interaction_profiles();
// Optional transition-only input diagnostics; no per-frame pose spam.
void log_input_changes(const controller_input& input);
void log_hand_changes(const char* hand_name, bool left, const hand_controller& current, const hand_controller& previous,
bool first_sample);
void log_button_change(const char* hand_name, const char* button_name, const controller_button& current,
const controller_button& previous, bool first_sample);
// OpenXR error/path presentation helpers.
bool check_xr(XrResult result, const char* operation) const;
std::string xr_result_string(XrResult result) const;
std::string path_string(XrPath path) const;
// Stable mappings between OpenXR identifiers and switchboard-facing enums/log labels.
static controller_profile profile_from_path(const std::string& path);
static const char* profile_label(controller_profile profile);
static const char* session_state_label(XrSessionState state);
static void merge_button(controller_button* destination, const controller_button& source);
// ILLIXR services and typed topics.
const std::shared_ptr<switchboard> switchboard_;
const std::shared_ptr<const relative_clock> clock_;
const std::shared_ptr<const stoplight> stoplight_;
switchboard::writer<controller_input> controller_writer_;
switchboard::writer<view_frame> view_writer_;
switchboard::reader<stereo_frame> stereo_reader_;
// Worker control.
bool log_input_{true};
std::atomic<bool> stop_requested_{false};
std::thread worker_;
// Hidden GLFW/X11/GLX objects supplied in XrGraphicsBindingOpenGLXlibKHR.
bool glfw_initialized_{false};
GLFWwindow* window_{nullptr};
Display* x_display_{nullptr};
GLXFBConfig glx_fb_config_{nullptr};
GLXDrawable glx_drawable_{0};
GLXContext glx_context_{nullptr};
std::uint32_t visual_id_{0};
// Core OpenXR instance, HMD system, session, and LOCAL reference space.
XrInstance instance_{XR_NULL_HANDLE};
XrSystemId system_id_{XR_NULL_SYSTEM_ID};
XrSession session_{XR_NULL_HANDLE};
XrSpace local_space_{XR_NULL_HANDLE};
// Shared left/right action set. Individual action state is selected by subaction path.
XrActionSet action_set_{XR_NULL_HANDLE};
XrAction grip_pose_action_{XR_NULL_HANDLE};
XrAction aim_pose_action_{XR_NULL_HANDLE};
XrAction trigger_click_action_{XR_NULL_HANDLE};
XrAction trigger_value_action_{XR_NULL_HANDLE};
XrAction primary_click_action_{XR_NULL_HANDLE};
XrAction secondary_click_action_{XR_NULL_HANDLE};
XrAction thumbstick_click_action_{XR_NULL_HANDLE};
XrAction thumbstick_axis_action_{XR_NULL_HANDLE};
XrAction squeeze_value_action_{XR_NULL_HANDLE};
// Per-hand paths, pose spaces, and currently bound interaction profiles.
std::array<XrPath, 2> hand_paths_{XR_NULL_PATH, XR_NULL_PATH};
std::array<XrSpace, 2> grip_spaces_{XR_NULL_HANDLE, XR_NULL_HANDLE};
std::array<XrSpace, 2> aim_spaces_{XR_NULL_HANDLE, XR_NULL_HANDLE};
std::array<controller_profile, 2> interaction_profiles_{controller_profile::none, controller_profile::none};
// Runtime session/view state updated by pump_events() and query_views().
XrViewConfigurationType view_configuration_type_{XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO};
XrEnvironmentBlendMode blend_mode_{XR_ENVIRONMENT_BLEND_MODE_OPAQUE};
XrSessionState session_state_{XR_SESSION_STATE_UNKNOWN};
bool session_running_{false};
bool exit_requested_{false};
bool interaction_profiles_dirty_{true};
std::array<XrViewConfigurationView, 2> view_configuration_views_{};
std::array<XrView, 2> located_views_{};
bool located_views_valid_{false};
// Runtime-owned eye swapchains.
std::array<swapchain_view, 2> swapchain_views_{};
std::int64_t swapchain_format_{0};
// Producer rings for pixels and optional overlays.
mapped_file pixel_mapping_;
mapped_file overlay_mapping_;
mapped_file modal_mapping_;
// Double-buffered source/modal textures and the last complete frame snapshot.
std::array<std::array<GLuint, 2>, 2> source_textures_{};
std::array<GLuint, 2> modal_textures_{};
int active_texture_set_{-1};
std::uint32_t source_width_{0};
std::uint32_t source_height_{0};
std::uint64_t active_stereo_frame_id_{0};
bool active_stereo_frame_valid_{false};
data_format::stereo_image_origin active_origin_{data_format::stereo_image_origin::upper_left};
data_format::stereo_presentation_mode active_presentation_mode_{data_format::stereo_presentation_mode::stereo_fullscreen};
std::array<data_format::stereo_render_view, 2> active_render_views_{};
std::array<std::vector<float>, 2> active_overlay_commands_{};
data_format::stereo_modal_overlay active_modal_{};
std::array<float, 16> world_panel_model_{};
bool world_panel_initialized_{false};
// OpenGL resources used to draw Boba content into acquired OpenXR images.
GLuint framebuffer_{0};
GLuint panel_program_{0};
GLuint panel_vao_{0};
GLint panel_source_location_{-1};
GLint panel_mvp_location_{-1};
GLint panel_flip_y_location_{-1};
GLuint overlay_program_{0};
GLuint overlay_vao_{0};
GLuint overlay_vbo_{0};
GLint overlay_source_size_location_{-1};
GLuint modal_program_{0};
GLuint modal_vao_{0};
GLuint modal_vbo_{0};
GLint modal_source_size_location_{-1};
GLint modal_texture_location_{-1};
// Sequence number shared by controller/view events and previous state used for logging.
std::uint64_t sequence_{0};
controller_input previous_input_{};
bool have_previous_input_{false};
};
} // namespace ILLIXR