diff --git a/src/encoder/nvidia_encoder.cpp b/src/encoder/nvidia_encoder.cpp index 7c98df74b958cfffaa39b46d54c56c58e30f4059..ad91eb47f617fa167e68da48398204f3984d7d11 100644 --- a/src/encoder/nvidia_encoder.cpp +++ b/src/encoder/nvidia_encoder.cpp @@ -612,7 +612,7 @@ bool NvidiaEncoder::create_context(lava::device_ptr device) this->cuda_device = device_handle; - if(cuCtxCreate(&this->cuda_context, 0, this->cuda_device) != CUDA_SUCCESS) + if (cuCtxCreate(&this->cuda_context, 0, this->cuda_device) != CUDA_SUCCESS) { lava::log()->error("Nvidia Encoder: Can't create cuda context!"); @@ -965,7 +965,7 @@ bool NvidiaEncoder::create_input_buffer(NvidiaEncoderFrame::Ptr frame, lava::dev memset(register_info.reserved1, 0, sizeof(register_info.reserved1)); memset(register_info.reserved2, 0, sizeof(register_info.reserved2)); - if(nvenc_functions.nvEncRegisterResource(this->nvenc_session, ®ister_info) != NV_ENC_SUCCESS) + if (nvenc_functions.nvEncRegisterResource(this->nvenc_session, ®ister_info) != NV_ENC_SUCCESS) { lava::log()->error("Nvidia Encoder: Can't register input image!"); @@ -1164,7 +1164,7 @@ bool NvidiaEncoder::check_encode_support(GUID required_guid) const { uint32_t guid_count = 0; - if(nvenc_functions.nvEncGetEncodeGUIDCount(this->nvenc_session, &guid_count) != NV_ENC_SUCCESS) + if (nvenc_functions.nvEncGetEncodeGUIDCount(this->nvenc_session, &guid_count) != NV_ENC_SUCCESS) { return false; } @@ -1393,7 +1393,7 @@ void unload_library() bool setup_instance_for_nvidia_encoder(lava::frame_config& config) { - if(cuInit(0) != CUDA_SUCCESS) + if (cuInit(0) != CUDA_SUCCESS) { std::cout << "Nvidia Encoder: Can't init cuda!" << std::endl; diff --git a/src/encoder/nvidia_encoder.hpp b/src/encoder/nvidia_encoder.hpp index f5bea0815a624310ff3465ab5234598f2ed0fe78..4a364f1e940ec323903ab2d1ae0a5f53fb860048 100644 --- a/src/encoder/nvidia_encoder.hpp +++ b/src/encoder/nvidia_encoder.hpp @@ -50,24 +50,24 @@ public: public: NvidiaEncoder(); - bool create(lava::device_ptr device, const lava::renderer& renderer, const glm::uvec2& size, EncoderFormat format); - void destroy(); + bool create(lava::device_ptr device, const lava::renderer& renderer, const glm::uvec2& size, EncoderFormat format) override; + void destroy() override; - EncoderResult encode(VkCommandBuffer command_buffer, lava::renderer& renderer, lava::image::ptr image, VkImageLayout image_layout, OnEncodeComplete function); + EncoderResult encode(VkCommandBuffer command_buffer, lava::renderer& renderer, lava::image::ptr image, VkImageLayout image_layout, OnEncodeComplete function) override; - void set_on_encode_error(OnEncodeError function); + void set_on_encode_error(OnEncodeError function) override; - void set_mode(EncoderMode mode); - void set_quality(double quality); - void set_bitrate(double bitrate); - void set_frame_rate(uint32_t frame_rate); + void set_mode(EncoderMode mode) override; + void set_quality(double quality) override; + void set_bitrate(double bitrate) override; + void set_frame_rate(uint32_t frame_rate) override; - EncoderMode get_mode() const; - double get_quality() const; - double get_bitrate() const; - uint32_t get_frame_rate() const; + EncoderMode get_mode() const override; + double get_quality() const override; + double get_bitrate() const override; + uint32_t get_frame_rate() const override; - bool is_supported(EncoderSetting setting) const; + bool is_supported(EncoderSetting setting) const override; private: bool aquire_frame(NvidiaEncoderFrame::Ptr& frame); diff --git a/src/encoder/vulkan_encoder.hpp b/src/encoder/vulkan_encoder.hpp index 0cf7b82dff443666cb00f7f4f9db6e38e7f9c202..cea0f938b75bbcab1369a64da352ca22a50444ab 100644 --- a/src/encoder/vulkan_encoder.hpp +++ b/src/encoder/vulkan_encoder.hpp @@ -77,26 +77,26 @@ public: public: VulkanEncoder(); - bool create(lava::device_ptr device, const lava::renderer& renderer, const glm::uvec2& size, EncoderFormat format); - void destroy(); + bool create(lava::device_ptr device, const lava::renderer& renderer, const glm::uvec2& size, EncoderFormat format) override; + void destroy() override; - EncoderResult encode(VkCommandBuffer command_buffer, lava::renderer& renderer, lava::image::ptr image, VkImageLayout image_layout, OnEncodeComplete function); + EncoderResult encode(VkCommandBuffer command_buffer, lava::renderer& renderer, lava::image::ptr image, VkImageLayout image_layout, OnEncodeComplete function) override; - void set_on_encode_error(OnEncodeError function); + void set_on_encode_error(OnEncodeError function) override; - void set_mode(EncoderMode mode); - void set_quality(double quality); - void set_bitrate(double bitrate); - void set_key_rate(uint32_t key_rate); - void set_frame_rate(uint32_t frame_rate); + void set_mode(EncoderMode mode) override; + void set_quality(double quality) override; + void set_bitrate(double bitrate) override; + void set_key_rate(uint32_t key_rate) override; + void set_frame_rate(uint32_t frame_rate) override; - EncoderMode get_mode() const; - double get_quality() const; - double get_bitrate() const; - uint32_t get_key_rate() const; - uint32_t get_frame_rate() const; + EncoderMode get_mode() const override; + double get_quality() const override; + double get_bitrate() const override; + uint32_t get_key_rate() const override; + uint32_t get_frame_rate() const override; - bool is_supported(EncoderSetting setting) const; + bool is_supported(EncoderSetting setting) const override; private: bool encode_control(lava::renderer& renderer, OnEncodeComplete callback); diff --git a/src/headset/openvr_headset.cpp b/src/headset/openvr_headset.cpp index bf2db060edd6adcc630d97569c51c29f9f732584..712fc85e6cd86ca4075aece7aff91279451fd757 100644 --- a/src/headset/openvr_headset.cpp +++ b/src/headset/openvr_headset.cpp @@ -6,10 +6,23 @@ #include <glm/gtx/matrix_operation.hpp> #include <imgui.h> +struct OpenVRActionButtonBinding +{ + std::string path; + + Controller controller; + Button button; +}; + OpenVRHeadset::OpenVRHeadset() { this->controller_attached.fill(false); - this->controller_buttons.fill(false); + + for (uint32_t index = 0; index < this->controller_buttons.size(); index++) + { + this->controller_button_handles[index].fill(0); + this->controller_buttons[index].fill(false); + } } bool OpenVRHeadset::on_setup_instance(lava::frame_config& config) @@ -297,31 +310,36 @@ bool OpenVRHeadset::create_actions() return false; } - std::vector<std::string> action_paths = - { - "/actions/controller/in/button_a", - "/actions/controller/in/button_b", - "/actions/controller/in/button_x", - "/actions/controller/in/button_y", - "/actions/controller/in/trigger_left", - "/actions/controller/in/trigger_right" - }; + std::array<OpenVRActionButtonBinding, 6> action_bindings; + action_bindings[0].path = "/actions/controller/in/button_x"; + action_bindings[0].controller = CONTROLLER_LEFT; + action_bindings[0].button = BUTTON_X; - std::vector<Button> action_buttons = - { - BUTTON_A, - BUTTON_B, - BUTTON_X, - BUTTON_Y, - BUTTON_TRIGGER_LEFT, - BUTTON_TRIGGER_RIGHT - }; + action_bindings[1].path = "/actions/controller/in/button_y"; + action_bindings[1].controller = CONTROLLER_LEFT; + action_bindings[1].button = BUTTON_Y; + + action_bindings[2].path = "/actions/controller/in/trigger_left"; + action_bindings[2].controller = CONTROLLER_LEFT; + action_bindings[2].button = BUTTON_TRIGGER; + + action_bindings[3].path = "/actions/controller/in/button_a"; + action_bindings[3].controller = CONTROLLER_RIGHT; + action_bindings[3].button = BUTTON_A; - for (uint32_t index = 0; index < action_paths.size(); index++) + action_bindings[4].path = "/actions/controller/in/button_b"; + action_bindings[4].controller = CONTROLLER_RIGHT; + action_bindings[4].button = BUTTON_B; + + action_bindings[5].path = "/actions/controller/in/trigger_right"; + action_bindings[5].controller = CONTROLLER_RIGHT; + action_bindings[5].button = BUTTON_TRIGGER; + + for (const OpenVRActionButtonBinding& binding : action_bindings) { - if (vr::VRInput()->GetActionHandle(action_paths[index].c_str(), &this->controller_button_handles[action_buttons[index]]) != vr::VRInputError_None) + if (vr::VRInput()->GetActionHandle(binding.path.c_str(), &this->controller_button_handles[binding.controller][binding.button]) != vr::VRInputError_None) { - lava::log()->error("OpenVR: Can't get handle for action: " + action_paths[index]); + lava::log()->error("OpenVR: Can't get handle for action: " + binding.path); return false; } @@ -346,7 +364,7 @@ bool OpenVRHeadset::create_actions() } } - if(vr::VRInput()->GetActionSetHandle("/actions/controller", &this->controller_action_set) != vr::VRInputError_None) + if (vr::VRInput()->GetActionSetHandle("/actions/controller", &this->controller_action_set) != vr::VRInputError_None) { lava::log()->error("OpenVR: Can't get handle for action set: /actions/controller"); @@ -372,18 +390,21 @@ bool OpenVRHeadset::update_actions() return false; } - for (uint32_t index = 0; index < this->controller_button_handles.size(); index++) + for (uint32_t controller = 0; controller < this->controller_button_handles.size(); controller++) { - vr::InputDigitalActionData_t button_data; - - if (vr::VRInput()->GetDigitalActionData(this->controller_button_handles[index], &button_data, sizeof(button_data), vr::k_ulInvalidInputValueHandle) != vr::VRInputError_None) + for (uint32_t button = 0; button < this->controller_button_handles[controller].size(); button++) { - lava::log()->error("OpenVR: Can't get button action data!"); + vr::InputDigitalActionData_t button_data; - return false; - } + if (vr::VRInput()->GetDigitalActionData(this->controller_button_handles[controller][button], &button_data, sizeof(button_data), vr::k_ulInvalidInputValueHandle) != vr::VRInputError_None) + { + lava::log()->error("OpenVR: Can't get button action data!"); + + return false; + } - this->controller_buttons[index] = button_data.bState; + this->controller_buttons[controller][button] = button_data.bState; + } } for (uint32_t index = 0; index < 2; index++) @@ -444,22 +465,17 @@ bool OpenVRHeadset::update_head_pose() void OpenVRHeadset::update_stage(lava::delta delta_time) { - for (uint32_t index = 0; index < 2; index++) + for (uint32_t controller = 0; controller < 2; controller++) { - glm::vec2 thumbstick = this->controller_thumbsticks[index]; + glm::vec2 thumbstick = this->controller_thumbsticks[controller]; - glm::mat4 controller_transform = this->controller_transforms[index]; + glm::mat4 controller_transform = this->controller_transforms[controller]; glm::vec3 controller_forward = controller_transform[2]; glm::vec3 controller_sideward = controller_transform[0]; float strength = this->movement_speed * delta_time; - if (index == CONTROLLER_LEFT && this->controller_buttons[BUTTON_TRIGGER_LEFT]) - { - strength *= 2.0f; - } - - else if (index == CONTROLLER_RIGHT && this->controller_buttons[BUTTON_TRIGGER_RIGHT]) + if (this->controller_buttons[controller][BUTTON_TRIGGER]) { strength *= 2.0f; } diff --git a/src/headset/openvr_headset.hpp b/src/headset/openvr_headset.hpp index b54930212ceb27e30cec0bc94fb94e2af7201887..f655790cda0f86dd364861a49af59f4d534766ba 100644 --- a/src/headset/openvr_headset.hpp +++ b/src/headset/openvr_headset.hpp @@ -63,7 +63,7 @@ private: vr::VRActionSetHandle_t controller_action_set; std::array<vr::VRActionHandle_t, 2> controller_transform_handles; std::array<vr::VRActionHandle_t, 2> controller_thumbsticks_handles; - std::array<vr::VRActionHandle_t, BUTTON_MAX_COUNT> controller_button_handles; + std::array<std::array<vr::VRActionHandle_t, BUTTON_MAX_COUNT>, 2> controller_button_handles; std::array<lava::image::ptr, 2> framebuffers; lava::image::ptr framebuffer_array; @@ -86,5 +86,5 @@ private: std::array<bool, 2> controller_attached; std::array<glm::mat4, 2> controller_transforms; std::array<glm::vec2, 2> controller_thumbsticks; - std::array<bool, BUTTON_MAX_COUNT> controller_buttons; + std::array<std::array<bool, BUTTON_MAX_COUNT>, 2> controller_buttons; }; \ No newline at end of file diff --git a/src/headset/openxr_headset.cpp b/src/headset/openxr_headset.cpp index eaabc82630ee577c0cd549426322c44f1a986c9c..6a53e51716f956a233e5e18a0577661a418abfe7 100644 --- a/src/headset/openxr_headset.cpp +++ b/src/headset/openxr_headset.cpp @@ -10,17 +10,30 @@ PFN_xrGetVulkanInstanceExtensionsKHR xrGetVulkanInstanceExtensionsKHR = nullptr; PFN_xrGetVulkanDeviceExtensionsKHR xrGetVulkanDeviceExtensionsKHR = nullptr; PFN_xrGetVulkanGraphicsDeviceKHR xrGetVulkanGraphicsDeviceKHR = nullptr; +struct OpenXRActionButtonBinding +{ + std::string name; + std::string localized_name; + + Controller controller; + Button button; +}; + OpenXRHeadset::OpenXRHeadset() { memset(&this->swapchain_indices, 0, sizeof(this->swapchain_indices)); - this->controller_button_actions.fill(XR_NULL_HANDLE); this->controller_thumbstick_actions.fill(XR_NULL_HANDLE); this->controller_transform_actions.fill(XR_NULL_HANDLE); this->controller_transform_space.fill(XR_NULL_HANDLE); this->controller_attached.fill(false); - this->controller_buttons.fill(false); + + for (uint32_t index = 0; index < this->controller_button_actions.size(); index++) + { + this->controller_button_actions[index].fill(XR_NULL_HANDLE); + this->controller_buttons[index].fill(false); + } } bool OpenXRHeadset::on_setup_instance(lava::frame_config& config) @@ -639,45 +652,56 @@ bool OpenXRHeadset::create_actions() return false; } - std::vector<std::string> action_names = - { - "button_a", - "button_b", - "button_x", - "button_y", - "trigger_left", - "trigger_right", - }; + std::array<OpenXRActionButtonBinding, 6> action_bindings; + action_bindings[0].name = "button_x"; + action_bindings[0].localized_name = "Button X"; + action_bindings[0].controller = CONTROLLER_LEFT; + action_bindings[0].button = BUTTON_X; - std::vector<std::string> action_localized_names = - { - "Button A", - "Button B", - "Button X", - "Button Y", - "Trigger Left", - "Trigger Right", - }; + action_bindings[1].name = "button_y"; + action_bindings[1].localized_name = "Button Y"; + action_bindings[1].controller = CONTROLLER_LEFT; + action_bindings[1].button = BUTTON_Y; + + action_bindings[2].name = "trigger_left"; + action_bindings[2].localized_name = "Trigger LEFT"; + action_bindings[2].controller = CONTROLLER_LEFT; + action_bindings[2].button = BUTTON_TRIGGER; + + action_bindings[3].name = "button_a"; + action_bindings[3].localized_name = "Button A"; + action_bindings[3].controller = CONTROLLER_RIGHT; + action_bindings[3].button = BUTTON_A; - for (uint32_t index = 0; index < action_names.size(); index++) + action_bindings[4].name = "button_b"; + action_bindings[4].localized_name = "Button B"; + action_bindings[4].controller = CONTROLLER_RIGHT; + action_bindings[4].button = BUTTON_B; + + action_bindings[5].name = "trigger_right"; + action_bindings[5].localized_name = "Trigger Right"; + action_bindings[5].controller = CONTROLLER_RIGHT; + action_bindings[5].button = BUTTON_TRIGGER; + + for (const OpenXRActionButtonBinding& binding : action_bindings) { XrActionCreateInfo button_info; button_info.type = XR_TYPE_ACTION_CREATE_INFO; button_info.next = nullptr; - strncpy(button_info.actionName, action_names[index].c_str(), XR_MAX_ACTION_NAME_SIZE); + strncpy(button_info.actionName, binding.name.c_str(), XR_MAX_ACTION_NAME_SIZE); button_info.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; button_info.countSubactionPaths = 0; button_info.subactionPaths = nullptr; - strncpy(button_info.localizedActionName, action_localized_names[index].c_str(), XR_MAX_LOCALIZED_ACTION_NAME_SIZE); + strncpy(button_info.localizedActionName, binding.localized_name.c_str(), XR_MAX_LOCALIZED_ACTION_NAME_SIZE); - if (xrCreateAction(this->action_set, &button_info, &this->controller_button_actions[index]) != XR_SUCCESS) + if (xrCreateAction(this->action_set, &button_info, &this->controller_button_actions[binding.controller][binding.button]) != XR_SUCCESS) { - lava::log()->error("OpenXR: Can't create action: " + action_names[index]); + lava::log()->error("OpenXR: Can't create action: " + binding.name); return false; } } - + for (uint32_t index = 0; index < 2; index++) { std::string thumbstick_name = (index > 0) ? "thumbstick_right" : "thumbstick_left"; @@ -772,12 +796,15 @@ void OpenXRHeadset::destroy_actions() } } - for (XrAction& action : this->controller_button_actions) + for (uint32_t index = 0; index < this->controller_button_actions.size(); index++) { - if (action != XR_NULL_HANDLE) + for (XrAction& action : this->controller_button_actions[index]) { - xrDestroyAction(action); - action = XR_NULL_HANDLE; + if (action != XR_NULL_HANDLE) + { + xrDestroyAction(action); + action = XR_NULL_HANDLE; + } } } @@ -925,26 +952,36 @@ bool OpenXRHeadset::update_actions() return false; } - for (uint32_t index = 0; index < this->controller_button_actions.size(); index++) + for (uint32_t controller = 0; controller < this->controller_button_actions.size(); controller++) { - XrActionStateGetInfo button_info; - button_info.type = XR_TYPE_ACTION_STATE_GET_INFO; - button_info.next = nullptr; - button_info.action = this->controller_button_actions[index]; - button_info.subactionPath = XR_NULL_PATH; + for (uint32_t button = 0; button < this->controller_button_actions[controller].size(); button++) + { + XrAction action = this->controller_button_actions[controller][button]; - XrActionStateBoolean button_state; - memset(&button_state, 0, sizeof(button_state)); - button_state.type = XR_TYPE_ACTION_STATE_BOOLEAN; + if (action == XR_NULL_HANDLE) + { + continue; + } - if(xrGetActionStateBoolean(this->session, &button_info, &button_state) != XR_SUCCESS) - { - lava::log()->error("OpenXR: Can't get controller button state!"); + XrActionStateGetInfo button_info; + button_info.type = XR_TYPE_ACTION_STATE_GET_INFO; + button_info.next = nullptr; + button_info.action = action; + button_info.subactionPath = XR_NULL_PATH; - return false; - } + XrActionStateBoolean button_state; + memset(&button_state, 0, sizeof(button_state)); + button_state.type = XR_TYPE_ACTION_STATE_BOOLEAN; - this->controller_buttons[index] = button_state.isActive && button_state.currentState; + if (xrGetActionStateBoolean(this->session, &button_info, &button_state) != XR_SUCCESS) + { + lava::log()->error("OpenXR: Can't get controller button state!"); + + return false; + } + + this->controller_buttons[controller][button] = button_state.isActive && button_state.currentState; + } } for (uint32_t index = 0; index < 2; index++) @@ -1031,22 +1068,17 @@ bool OpenXRHeadset::update_actions() void OpenXRHeadset::update_stage(lava::delta delta_time) { - for (uint32_t index = 0; index < 2; index++) + for (uint32_t controller = 0; controller < 2; controller++) { - glm::vec2 thumbstick = this->controller_thumbsticks[index]; + glm::vec2 thumbstick = this->controller_thumbsticks[controller]; - glm::mat4 controller_transform = this->controller_transforms[index]; + glm::mat4 controller_transform = this->controller_transforms[controller]; glm::vec3 controller_forward = controller_transform[2]; glm::vec3 controller_sideward = controller_transform[0]; float strength = this->movement_speed * delta_time; - if (index == CONTROLLER_LEFT && this->controller_buttons[BUTTON_TRIGGER_LEFT]) - { - strength *= 2.0f; - } - - else if (index == CONTROLLER_RIGHT && this->controller_buttons[BUTTON_TRIGGER_RIGHT]) + if (this->controller_buttons[controller][BUTTON_TRIGGER]) { strength *= 2.0f; } @@ -1450,11 +1482,11 @@ bool OpenXRHeadset::suggest_vive_controller_binding() { std::vector<std::string> path_strings = { - "/user/hand/right/input/trackpad/click", - "/user/hand/right/input/squeeze/click", "/user/hand/left/input/trackpad/click", "/user/hand/left/input/squeeze/click", "/user/hand/left/input/trigger/click", + "/user/hand/right/input/trackpad/click", + "/user/hand/right/input/squeeze/click", "/user/hand/right/input/trigger/click", "/user/hand/left/input/trackpad", "/user/hand/right/input/trackpad", @@ -1478,16 +1510,16 @@ bool OpenXRHeadset::suggest_vive_controller_binding() std::vector<XrAction> actions = { - this->controller_button_actions[0], - this->controller_button_actions[1], - this->controller_button_actions[2], - this->controller_button_actions[3], - this->controller_button_actions[4], - this->controller_button_actions[5], - this->controller_thumbstick_actions[0], - this->controller_thumbstick_actions[1], - this->controller_transform_actions[0], - this->controller_transform_actions[1] + this->controller_button_actions[CONTROLLER_LEFT][BUTTON_X], + this->controller_button_actions[CONTROLLER_LEFT][BUTTON_Y], + this->controller_button_actions[CONTROLLER_LEFT][BUTTON_TRIGGER], + this->controller_button_actions[CONTROLLER_RIGHT][BUTTON_A], + this->controller_button_actions[CONTROLLER_RIGHT][BUTTON_B], + this->controller_button_actions[CONTROLLER_RIGHT][BUTTON_TRIGGER], + this->controller_thumbstick_actions[CONTROLLER_LEFT], + this->controller_thumbstick_actions[CONTROLLER_RIGHT], + this->controller_transform_actions[CONTROLLER_LEFT], + this->controller_transform_actions[CONTROLLER_RIGHT] }; std::vector<XrActionSuggestedBinding> bindings; @@ -1520,11 +1552,11 @@ bool OpenXRHeadset::suggest_vive_cosmos_controller_binding() { std::vector<std::string> path_strings = { - "/user/hand/right/input/a/click", - "/user/hand/right/input/b/click", "/user/hand/left/input/x/click", "/user/hand/left/input/y/click", "/user/hand/left/input/trigger/click", + "/user/hand/right/input/a/click", + "/user/hand/right/input/b/click", "/user/hand/right/input/trigger/click", "/user/hand/left/input/thumbstick", "/user/hand/right/input/thumbstick", @@ -1548,16 +1580,16 @@ bool OpenXRHeadset::suggest_vive_cosmos_controller_binding() std::vector<XrAction> actions = { - this->controller_button_actions[0], - this->controller_button_actions[1], - this->controller_button_actions[2], - this->controller_button_actions[3], - this->controller_button_actions[4], - this->controller_button_actions[5], - this->controller_thumbstick_actions[0], - this->controller_thumbstick_actions[1], - this->controller_transform_actions[0], - this->controller_transform_actions[1] + this->controller_button_actions[CONTROLLER_LEFT][BUTTON_X], + this->controller_button_actions[CONTROLLER_LEFT][BUTTON_Y], + this->controller_button_actions[CONTROLLER_LEFT][BUTTON_TRIGGER], + this->controller_button_actions[CONTROLLER_RIGHT][BUTTON_A], + this->controller_button_actions[CONTROLLER_RIGHT][BUTTON_B], + this->controller_button_actions[CONTROLLER_RIGHT][BUTTON_TRIGGER], + this->controller_thumbstick_actions[CONTROLLER_LEFT], + this->controller_thumbstick_actions[CONTROLLER_RIGHT], + this->controller_transform_actions[CONTROLLER_LEFT], + this->controller_transform_actions[CONTROLLER_RIGHT] }; std::vector<XrActionSuggestedBinding> bindings; diff --git a/src/headset/openxr_headset.hpp b/src/headset/openxr_headset.hpp index f19394b67442b8e7fa512ee46c24b24e4c6e88bb..11b3c8bc20a136ba8d3f5652caca97192b46c04a 100644 --- a/src/headset/openxr_headset.hpp +++ b/src/headset/openxr_headset.hpp @@ -90,7 +90,7 @@ private: std::array<XrAction, 2> controller_transform_actions; std::array<XrSpace, 2> controller_transform_space; std::array<XrAction, 2> controller_thumbstick_actions; - std::array<XrAction, BUTTON_MAX_COUNT> controller_button_actions; + std::array<std::array<XrAction, BUTTON_MAX_COUNT>, 2> controller_button_actions; std::array<uint32_t, 2> swapchain_indices; std::array<std::vector<VkImage>, 2> swapchain_images; @@ -118,5 +118,5 @@ private: std::array<bool, 2> controller_attached; std::array<glm::mat4, 2> controller_transforms; std::array<glm::vec2, 2> controller_thumbsticks; - std::array<bool, BUTTON_MAX_COUNT> controller_buttons; + std::array<std::array<bool, BUTTON_MAX_COUNT>, 2> controller_buttons; }; \ No newline at end of file diff --git a/src/headset/remote_headset.hpp b/src/headset/remote_headset.hpp index 6afd11c499b83e92abc9e560bd98c9328ac4df49..0ffaacd63ceed832af132c0a2dfaf1eac00eeaed 100644 --- a/src/headset/remote_headset.hpp +++ b/src/headset/remote_headset.hpp @@ -8,14 +8,10 @@ #include <chrono> #include "headset.hpp" - #include "strategy/stereo_strategy.hpp" #include "transport/transport.hpp" - - #include "encoder/encoder.hpp" -#include "utility/extern_fence.hpp" #include "utility/latency.hpp" class RemoteHeadset : public Headset diff --git a/src/scene.cpp b/src/scene.cpp index 4013fd982e2f076b23b1a6a4f4e876bcf7e6b051..49aaef9105423affd97ea9be5969afbacf7f21ad 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -1447,7 +1447,7 @@ bool Scene::load_texture(const std::string& file_name, lava::device_ptr device, { gli::texture texture = gli::load(image_data.ptr, image_data.size); - if(texture.empty()) + if (texture.empty()) { lava::log()->error("Can't load texture: " + file_name + " !"); @@ -1572,7 +1572,7 @@ bool Scene::load_texture(const std::string& file_name, lava::device_ptr device, texture = lava::make_texture(); - if(!texture->create(device, glm::uvec2(width, height), format, {layer}, lava::texture_type::tex_2d)) + if (!texture->create(device, glm::uvec2(width, height), format, {layer}, lava::texture_type::tex_2d)) { lava::log()->error("Can't create texture: " + file_name + " !"); diff --git a/src/transport/transport.hpp b/src/transport/transport.hpp index 2d3f6b3bc7b766f35294a8cd08eeaea9286be201..850208a5984772c7f66eab95d231af1ac715ae9e 100644 --- a/src/transport/transport.hpp +++ b/src/transport/transport.hpp @@ -1,8 +1,25 @@ /* - Hallo + The transport class can be used to manage the connection to a remote headset. + Before an connection to a remote headset can be established, it is nessesary to call the function create(...). + The communication between hedaset and host applications starts with the sending of a setup packet from the headset to the host. + Due to unreliable protocolls such as UDP for example it could be the case that packages get reordered during transmission. + The transport class however has to allways make sure that the callback for the setup is called before any other callbacks during the startup of the connection. + With the help of the function wait_connection() it should be possible to wait for the arrival of the setup packet. + After the setup packet has been received, the host-system should responde with a setup-complete packet which maks the end of the handshake that is used to initialize the connection between the two devices. + After the handshake phase the host-system can send images in form of encoded nal packets and the headset can send transformation information or controller events. + It is strongly advised to use a single worker thread that waits for packets and sends packets. + When a worker thread is used, all callbacks set by the host-system need to be called only by the worker. Example: - Hallo + Transport::Ptr transport = make_transport(...); + + transport->set_on_setup([transport](const glm::u32vec2& resolution) + { + transport->send_setup_complete(...); + }); + + transport->create(42); + transport->wait_connect(); */ #pragma once @@ -13,17 +30,19 @@ #include "types.hpp" -enum TransportType +enum TransportState { - TRANSPORT_TYPE_UDP + TRANSPORT_STATE_UNINITIALIZED, // Initial state of the transport class + TRANSPORT_STATE_WAITING, // State after calling create(...) and before wait_connect(...) returns + TRANSPORT_STATE_CONNECTED, // State after wait_connect(...) returns successfully + TRANSPORT_STATE_ERROR // State after any error during the communication or if an disconnect was detected. By calling destroy(...) the transport should return to the uninitalized state }; -enum TransportState +// When adding or removing a transport method, the function make_transport(...) as well as +// the function set_transport(...) of the CommandParser need to be adapted accordingly. +enum TransportType { - TRANSPORT_STATE_UNINITIALIZED, - TRANSPORT_STATE_WAITING, - TRANSPORT_STATE_CONNECTED, - TRANSPORT_STATE_ERROR + TRANSPORT_TYPE_UDP }; class Transport @@ -31,14 +50,55 @@ class Transport public: typedef std::shared_ptr<Transport> Ptr; + // OnSetup: Used during the initial handshake + // resolution: The resolution that should be used for rendering typedef std::function<void(const glm::u32vec2& resolution)> OnSetup; + + // OnProjectionChange: Used to change the projection matrices. Needs to be send once after the handshake. + // left_eye_projection: The projection matrix that should be used for the left eye + // right_eye_projection: The projection matrix that should be used for the right eye + // left_head_to_eye: The matrix that defines the transformation from head to left eye + // right_head_to_eye: The matrix that defines the transformation from head to right eye typedef std::function<void(const glm::mat4& left_eye_projection, const glm::mat4& right_eye_projection, const glm::mat4& left_head_to_eye, const glm::mat4& right_head_to_eye)> OnProjectionChange; - typedef std::function<void(TransformId transform, const glm::mat4& head_transform)> OnHeadTransform; + + // OnHeadTransform: Used to define the head transformation and is send requently be the headset + // transform_id: Unique identifier for the head transformation. The id is send back to the headset in an image packet, if the head transform to that id was used for the rendering of an image. + // head_transform: The matrix that defines the rotation and location of the users head. + typedef std::function<void(TransformId transform_id, const glm::mat4& head_transform)> OnHeadTransform; + + // OnControllerTransform: Used to transmit the rotation and location of a controller. Should be send requently by the headset + // controller: Identifies the controller to which the information in this packet belongs + // controller_transform: The matrix that defines the latest rotation and location of the specified controller typedef std::function<void(Controller controller, const glm::mat4& controller_transform)> OnControllerTransform; + + // OnControllerEvent: Used to transmit the current state of a controller. Should be send once after the handshake + // controller: Identifies the controller to which the information in this packet belongs + // controller_state: The state of the specified controller typedef std::function<void(Controller controller, ControllerState controller_state)> OnControllerEvent; + + // OnControllerButton: Used to transmit button events. Should be send once after the handshake + // controller: Identifies the controller to which the information in this packet belongs + // button: Identifies the button to which the information in this packet belongs + // button_state: The state of the specified button on the specified controller typedef std::function<void(Controller controller, Button button, ButtonState button_state)> OnControllerButton; + + // OnControllerThumbstick: Used to transmit changes to the thumbsticks. Should be send once after the handshake + // controller: Identifies the controller to which the information in this packet belongs + // thumbstick: Position of the thumbstick on the specified controller typedef std::function<void(Controller controller, const glm::vec2& thumbstick)> OnControllerThumbstick; + + // OnLatency: Used to transmit latency related information. This packet is optional + // frame_number: Identifies the frame to which the information in this packet belongs + // frame_id: Identifies the frame id (e.g. left or right eye) to which the information in this packet belongs + // transform_id: Identifies the head transformation which was used to render the specified image + // timestamp_transform_query: Time between the statup of the application on the headset and the quering of the head transform on the headset + // timestamp_server_response: Time between the statup of the application on the headset and the response from the host-system to the head transformation send by the headset application + // timestamp_frame_decoded: Time between the statup of the application on the headset and the completion of the image decoding on the headset + // timestamp_command_construct: Time between the statup of the application on the headset and the submission of the rendering command + // timestamp_command_executed: Time between the statup of the application on the headset and the completion of the rendering command typedef std::function<void(FrameNumber frame_number, FrameId frame_id, TransformId transform_id, double timestamp_transform_query, double timestamp_server_response, double timestamp_frame_decoded, double timestamp_command_construct, double timestamp_command_executed)> OnLatency; + + // OnTransportError: Called in case of error or disconnect. After that the transport method transitions to the error state typedef std::function<void()> OnTransportError; public: @@ -49,15 +109,44 @@ public: virtual void destroy() = 0; virtual bool wait_connect() = 0; - //NOTE: The following functions should be thread safe + // send_setup_complete: Used to send a setup-complete packet + // This function should be threadsafe and callable by main and worker thread + // remote_strategy: The postprocessing method that should be used on the headset + // max_frame_ids: The number of images that define a frame and that are send in parallel (normaly 2 for left and right eye). The headset application should setup this many decoders + // near_plane: The distance to the near plane that should be used for the projection matrices + // far_plane: The distance to the far plane that should be used for the projection matrices virtual bool send_setup_complete(RemoteStrategy remote_strategy, uint32_t max_frame_ids, float near_plane, float far_plane) = 0; + + // send_stage_transform: Used to send the current transformation for the origin + // This transformation can change for example if the user moves by pressing a controller button + // This function should be threadsafe and callable by main and worker thread + // stage_transform: Current stage transform virtual bool send_stage_transform(const glm::mat4& stage_transform) = 0; + + // send_frame_config_nal: Used to send meta infromation that is required for the decoding of the images + // In case of an h264 codec this packet would contain the sequence and picture parameter sets + // This function should be threadsafe and callable by main and worker thread + // frame_id: The frame id to which the information in this packet belong (e.g. left or right eye) + // content: Encoding related meta information virtual bool send_frame_config_nal(FrameId frame_id, const std::span<uint8_t>& content) = 0; + + // send_frame_nal: Use to send encoded images + // This could be for example an h264 encoded image + // This function should be threadsafe and callable by main and worker thread + // frame_number: The the number of the frame. The frame number of the first rendered frame would be zero + // frame_id: The frame id to which the information in this packet belong (e.g. left or right eye) + // transform_id: The id of the head transformation that was used to render the image in this packet + // content: Encoded image virtual bool send_frame_nal(FrameNumber frame_number, FrameId frame_id, TransformId transform_id, const std::span<uint8_t>& content) = 0; + + // send_frame_metadata: Used to send additional information that could be needed by the post processing setp that was selected in the setup-complete packet + // This function should be threadsafe and callable by main and worker thread + // frame_number: The the number of the frame. The frame number of the first rendered frame would be zero + // content: Information required by the post processing step virtual bool send_frame_metadata(FrameNumber frame_number, const std::span<uint8_t>& content) = 0; - //NOTE: The callbacks are only executed by the worker thread of the transport class. - //NOTE: Set the callbacks before calling create and don't do it again after calling create. + // The callbacks are only executed by the worker thread of the transport class. + // Set the callbacks before calling create and don't do it again after calling create. virtual void set_on_setup(OnSetup function) = 0; virtual void set_on_projection_change(OnProjectionChange function) = 0; virtual void set_on_head_transform(OnHeadTransform function) = 0; @@ -68,16 +157,16 @@ public: virtual void set_on_latency(OnLatency function) = 0; virtual void set_on_transport_error(OnTransportError function) = 0; - //NOTE: The following functions should be thread safe - virtual void set_max_send_queue_size(uint32_t size) = 0; //NOTE: The size is given in Bytes + // The following functions should be thread safe + virtual void set_max_send_queue_size(uint32_t size) = 0; // The size is given in Bytes - //NOTE: The following function should be thread safe + // The following function should be thread safe virtual TransportState get_state() = 0; - virtual double get_bitrate_send() = 0; //NOTE: The bitrate is given in MBits/s - virtual double get_bitrate_received() = 0; //NOTE: The bitrate is given in MBits/s - virtual uint32_t get_max_send_queue_size() = 0; //NOTE: The size is given in Bytes - virtual uint32_t get_send_queue_size() = 0; //NOTE: In Bytes - virtual uint32_t get_receive_queue_size() = 0; //NOTE: In Bytes + virtual double get_bitrate_send() = 0; // The bitrate is given in MBits/s + virtual double get_bitrate_received() = 0; // The bitrate is given in MBits/s + virtual uint32_t get_max_send_queue_size() = 0; // The size is given in Bytes + virtual uint32_t get_send_queue_size() = 0; // In Bytes + virtual uint32_t get_receive_queue_size() = 0; // In Bytes }; Transport::Ptr make_transport(TransportType transport_type); \ No newline at end of file diff --git a/src/types.hpp b/src/types.hpp index f03364b607b5ad729a541662b174629542062039..19a1f51ca43172d2358f9383afe137f34933b9bf 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -1,22 +1,19 @@ #pragma once - #include <span> #include <cstdint> +typedef uint32_t TransformId; typedef uint32_t FrameId; typedef uint32_t FrameNumber; typedef std::span<uint8_t> FrameMetadata; -typedef uint32_t TransformId; - -// Defined the frame ids for the left and right eye in case of an non-remote headset. +// Define the frame ids for the left and right eye in case of an non-remote headset. enum Eye { EYE_LEFT, EYE_RIGHT }; -// Define left and right controller enum Controller { CONTROLLER_LEFT, @@ -30,7 +27,6 @@ enum ControllerState CONTROLLER_STATE_DETACHED }; -// Define buttons enum Button { BUTTON_A,