From dd272f12577069e20a6f4ab9144a1023d1f2a078 Mon Sep 17 00:00:00 2001 From: patrickdown Date: Tue, 5 Dec 2023 14:27:02 -0500 Subject: [PATCH] Fixes for initialization and glasses state management In the process of working on a Linux version some problems were found in initialization and glasses state management. Since they are relevant to other platforms I've pulled these fixes together here. I have excluded changes to `build-on-push.yml` because the Linux version of the plugin still has some issues to work out. Problems and fixes: 1) A race condition was found in initialization that would cause rendering to start before frame textures had been created. This was caused when the READY state flipped between the `update_connection()` call and the `get_events()` call. The solution implemented was to move the graphics initialization into the `start_display()` function call chain. Since this is the function that starts rendering it can ensure that textures are setup first. 2. Although it has never seemed to come up, there are situations where previous state variable might be reset before changes could be detected. The fix for this was stop using a single var for this and track separate vars in each place changes needed to be detected. 3. Finally there are a few minor changes to account for differences in C++ library functions between Windows and Linux. --- SConstruct | 33 +++++- .../addons/tiltfive/tiltfive.gdextension | 9 ++ extension/T5Integration/Glasses.cpp | 108 +++++++++--------- extension/T5Integration/Glasses.h | 30 +++-- extension/T5Integration/Logging.h | 5 + extension/T5Integration/StateFlags.h | 43 +++---- extension/T5Integration/T5Service.cpp | 91 +++++++-------- extension/T5Integration/T5Service.h | 1 + extension/T5Integration/Wand.cpp | 4 +- extension/T5Integration/Wand.h | 7 +- extension/src/GodotT5Glasses.cpp | 14 ++- extension/src/OpenGLGlasses.cpp | 17 ++- extension/src/OpenGLGlasses.h | 6 +- extension/src/TiltFiveXRInterface.cpp | 3 + extension/src/VulkanGlasses.cpp | 26 +++-- extension/src/VulkanGlasses.h | 7 +- 16 files changed, 223 insertions(+), 181 deletions(-) diff --git a/SConstruct b/SConstruct index 91efbd8..fb8e654 100644 --- a/SConstruct +++ b/SConstruct @@ -8,11 +8,9 @@ VariantDir('build/src','extension/src', duplicate=False) VariantDir('build/T5Integration','extension/T5Integration', duplicate=False) env = SConscript('godot-cpp/SConstruct') -env['CXXFLAGS'].remove('/std:c++17') -env.Append(CXXFLAGS=['/std:c++20']) tilt_five_headers_path = 'extension/TiltFiveNDK/include' -tilt_five_library_path = 'extension/TiltFiveNDK/lib/' + { 'windows' : 'win/x86_64', 'linux' : 'linux/x86_64'}[env["platform"]] -tilt_five_library = 'TiltFiveNative.dll.if' +tilt_five_library_path = 'extension/TiltFiveNDK/lib/' + { 'windows' : 'win/x86_64', 'linux' : 'linux/x86_64', 'android' : 'android/arm64-v8a'}[env["platform"]] +tilt_five_library = {'windows' : 'TiltFiveNative.dll.if', 'linux' : 'libTiltFiveNative.so', 'android' : 'libTiltFiveNative.so'}[env["platform"]] # For the reference: # - CCFLAGS are compilation flags shared between C and C++ @@ -31,16 +29,39 @@ env.Append(LIBPATH=[tilt_five_library_path]) env.Append(LIBS=[tilt_five_library]) if env['platform'] == 'windows': + env['t5_shared_lib'] = 'TiltFiveNative.dll' + env['CXXFLAGS'].remove('/std:c++17') + env.Append(CXXFLAGS=['/std:c++20']) env.Append(CXXFLAGS=['/Zc:__cplusplus']) library = env.SharedLibrary( 'build/bin/libgdtiltfive{}{}'.format(env['suffix'], env['SHLIBSUFFIX']), source=sources, ) +elif env['platform'] == 'linux': + env['t5_shared_lib'] = 'libTiltFiveNative.so' + env['CXXFLAGS'].remove('-std=c++17') + env.Append(CXXFLAGS=['-std=c++20']) + env.Append(RPATH=env.Literal('\\$$ORIGIN' )) + library = env.SharedLibrary( + 'build/bin/libgdtiltfive{}{}'.format(env['suffix'], env['SHLIBSUFFIX']), + source=sources, + ) +elif env['platform'] == 'android': + env['t5_shared_lib'] = 'libTiltFiveNative.so' + env['CXXFLAGS'].remove('-std=c++17') + env.Append(CXXFLAGS=['-std=c++20']) + env.Append(CXXFLAGS=['-stdlib=libc++']) + env.Append(CCFLAGS=['-fPIC']) + env.Append(RPATH=env.Literal('\\$$ORIGIN' )) + library = env.SharedLibrary( + 'build/bin/libgdtiltfive{}{}'.format(env['suffix'], env['SHLIBSUFFIX']), + source=sources, + ) f1 = env.Command('example.gd/addons/tiltfive/bin/libgdtiltfive{}{}'.format(env['suffix'], env['SHLIBSUFFIX']), library, Copy('$TARGET', '$SOURCE') ) -f2 = env.Command('example.gd/addons/tiltfive/bin/TiltFiveNative.dll', tilt_five_library_path + '/TiltFiveNative.dll', Copy('$TARGET', '$SOURCE') ) +f2 = env.Command('example.gd/addons/tiltfive/bin/{}'.format(env['t5_shared_lib']), tilt_five_library_path + '/{}'.format(env['t5_shared_lib']), Copy('$TARGET', '$SOURCE') ) f3 = env.Command('example.csharp/addons/tiltfive/bin/libgdtiltfive{}{}'.format(env['suffix'], env['SHLIBSUFFIX']), library, Copy('$TARGET', '$SOURCE') ) -f4 = env.Command('example.csharp/addons/tiltfive/bin/TiltFiveNative.dll', tilt_five_library_path + '/TiltFiveNative.dll', Copy('$TARGET', '$SOURCE') ) +f4 = env.Command('example.csharp/addons/tiltfive/bin/{}'.format(env['t5_shared_lib']), tilt_five_library_path + '/{}'.format(env['t5_shared_lib']), Copy('$TARGET', '$SOURCE') ) env.Alias('example', [f1, f2, f3, f4]) diff --git a/example.gd/addons/tiltfive/tiltfive.gdextension b/example.gd/addons/tiltfive/tiltfive.gdextension index 96362ae..aa4e9e7 100644 --- a/example.gd/addons/tiltfive/tiltfive.gdextension +++ b/example.gd/addons/tiltfive/tiltfive.gdextension @@ -10,6 +10,9 @@ T5Gameboard = "res://addons/tiltfive/assets/board.svg" windows.x86_64.debug = "res://addons/tiltfive/bin/libgdtiltfive.windows.template_debug.x86_64.dll" windows.x86_64.release = "res://addons/tiltfive/bin/libgdtiltfive.windows.template_release.x86_64.dll" +linux.x86_64.debug = "res://addons/tiltfive/bin/libgdtiltfive.linux.template_debug.x86_64.so" +linux.x86_64.release = "res://addons/tiltfive/bin/libgdtiltfive.linux.template_release.x86_64.so" + [dependencies] @@ -19,4 +22,10 @@ windows.x86_64.debug = { windows.x86_64.release = { "res://addons/tiltfive/bin/TiltFiveNative.dll" : "" } +linux.x86_64.debug = { + "res://addons/tiltfive/bin/libTiltFiveNative.so" : "" +} +linux.x86_64.release = { + "res://addons/tiltfive/bin/libTiltFiveNative.so" : "" +} diff --git a/extension/T5Integration/Glasses.cpp b/extension/T5Integration/Glasses.cpp index a56c195..4ad4687 100644 --- a/extension/T5Integration/Glasses.cpp +++ b/extension/T5Integration/Glasses.cpp @@ -2,6 +2,8 @@ #include #include #include +#include + using TaskSystem::task_sleep; using TaskSystem::run_in_foreground; @@ -28,7 +30,9 @@ namespace T5Integration { _scheduler = ObjectRegistry::scheduler(); _math = ObjectRegistry::math(); - _state.reset(GlassesState::UNAVAILABLE, true); + _state.reset(GlassesState::UNAVAILABLE); + _previous_event_state.reset(GlassesState::UNAVAILABLE); + _previous_update_state.reset(GlassesState::UNAVAILABLE); set_swap_chain_size(1); } @@ -178,6 +182,9 @@ namespace T5Integration { while (_glasses_handle && _state.is_current(GlassesState::SUSTAIN_CONNECTION)) { T5_ConnectionState connectionState; + GlassesFlags _previous_monitor_state; + + _previous_monitor_state.sync_from(_state); { std::lock_guard lock(g_t5_exclusivity_group_1); @@ -264,15 +271,16 @@ namespace T5Integration { } } - if (_state.any_changed(GlassesState::READY | GlassesState::GRAPHICS_INIT)) { + if (_state.any_changed(_previous_monitor_state, GlassesState::READY | GlassesState::GRAPHICS_INIT)) { if (_state.is_current(GlassesState::READY | GlassesState::GRAPHICS_INIT)) _state.set(GlassesState::CONNECTED); else _state.clear(GlassesState::CONNECTED); } - if (_state.is_current(GlassesState::READY) && !_state.is_current(GlassesState::TRACKING_WANDS)) { - _state.set(GlassesState::TRACKING_WANDS); - _scheduler->add_task(monitor_wands()); + if (_state.is_current(GlassesState::READY)) { + if(_state.set_and_was_toggled(GlassesState::TRACKING_WANDS)) { + _scheduler->add_task(monitor_wands()); + } } co_await task_sleep( @@ -427,7 +435,6 @@ namespace T5Integration { } void Glasses::disconnect() { - if (_state.is_current(GlassesState::READY)) { T5_Result result; { @@ -442,6 +449,18 @@ namespace T5Integration { on_glasses_released(); } + void Glasses::start_display() { + if(_state.set_and_was_toggled(GlassesState::DISPLAY_STARTED)) { + on_start_display(); + } + } + + void Glasses::stop_display() { + if(_state.clear_and_was_toggled(GlassesState::DISPLAY_STARTED)) { + on_stop_display(); + } + } + bool Glasses::initialize_graphics() { auto service = ObjectRegistry::service(); @@ -573,26 +592,15 @@ namespace T5Integration { bool Glasses::update_connection() { - static GlassesFlags::FlagType prev_changes = 0; - static GlassesFlags::FlagType prev_current = 0; - auto changes = _state.get_changes(); - auto current_state = _state.get_current(); - - // if(changes != prev_changes || current_state != prev_current) { - // log_message("Glasses::update_connection changes ", changes, " Current ", current_state); - // prev_changes = changes; - // prev_current = current_state; - // } - - if((changes & GlassesState::CONNECTED) == GlassesState::CONNECTED) { - if(current_state & GlassesState::CONNECTED) { - on_glasses_reserved(); - } else { + if(_state.became_set(_previous_update_state, GlassesState::CONNECTED)) { + on_glasses_reserved(); + } + if(_state.became_clear(_previous_update_state, GlassesState::CONNECTED)) { + stop_display(); on_glasses_dropped(); - - } } + _previous_update_state.sync_from(_state); return true; } @@ -605,48 +613,34 @@ namespace T5Integration { void Glasses::get_events(int index, std::vector& out_events) { - static GlassesFlags::FlagType prev_changes = 0; - static GlassesFlags::FlagType prev_current = 0; - - auto changes = _state.get_changes(); - auto current_state = _state.get_current(); - - // if(changes != prev_changes || current_state != prev_current) { - // log_message("T5Service::get_events ", changes, " Current ", current_state); - // prev_changes = changes; - // prev_current = current_state; - // } - if((changes & GlassesState::CREATED) == GlassesState::CREATED) { - if(current_state & GlassesState::CREATED) { - out_events.push_back(GlassesEvent(index, GlassesEvent::E_ADDED)); - - } else { - out_events.push_back(GlassesEvent(index, GlassesEvent::E_LOST)); - } + if(_state.became_set(_previous_event_state, GlassesState::CREATED)) { + out_events.push_back(GlassesEvent(index, GlassesEvent::E_ADDED)); + } + if(_state.became_clear(_previous_event_state, GlassesState::CREATED)) { + out_events.push_back(GlassesEvent(index, GlassesEvent::E_LOST)); } - if((changes & GlassesState::UNAVAILABLE) == GlassesState::UNAVAILABLE) { - if(current_state & GlassesState::UNAVAILABLE) { + + if(_state.became_set(_previous_event_state, GlassesState::UNAVAILABLE)) { out_events.push_back(GlassesEvent(index, GlassesEvent::E_UNAVAILABLE)); - } else { + } + if(_state.became_clear(_previous_event_state, GlassesState::UNAVAILABLE)) { out_events.push_back(GlassesEvent(index, GlassesEvent::E_AVAILABLE)); - } } - if((changes & GlassesState::CONNECTED) == GlassesState::CONNECTED) { - if(current_state & GlassesState::CONNECTED) { + + if(_state.became_set(_previous_event_state, GlassesState::CONNECTED)) { out_events.push_back(GlassesEvent(index, GlassesEvent::E_CONNECTED)); - } else { + } + if(_state.became_clear(_previous_event_state, GlassesState::CONNECTED)) { out_events.push_back(GlassesEvent(index, GlassesEvent::E_DISCONNECTED)); - - } } - if((changes & GlassesState::TRACKING) == GlassesState::TRACKING) { - out_events.push_back(GlassesEvent(index, current_state & GlassesState::TRACKING ? GlassesEvent::E_TRACKING : GlassesEvent::E_NOT_TRACKING)); + + if(_state.became_set(_previous_event_state, GlassesState::TRACKING)) { + out_events.push_back(GlassesEvent(index, GlassesEvent::E_TRACKING)); } - if((changes & GlassesState::ERROR) == GlassesState::ERROR) { - // There is currently no way to recover from the error state - out_events.push_back(GlassesEvent(index, current_state & GlassesState::ERROR ? GlassesEvent::E_STOPPED_ON_ERROR : GlassesEvent::E_AVAILABLE)); + if(_state.became_clear(_previous_event_state, GlassesState::TRACKING)) { + out_events.push_back(GlassesEvent(index, GlassesEvent::E_NOT_TRACKING)); } - _state.reset_changes(); - } + _previous_event_state.sync_from(_state); + } } \ No newline at end of file diff --git a/extension/T5Integration/Glasses.h b/extension/T5Integration/Glasses.h index add02ad..837f54f 100644 --- a/extension/T5Integration/Glasses.h +++ b/extension/T5Integration/Glasses.h @@ -17,16 +17,17 @@ using TaskSystem::Scheduler; float const g_default_fov = 48.0f; namespace GlassesState { - const uint16_t READY = 0x00000001; //000000001 - const uint16_t GRAPHICS_INIT = 0x00000002; //000000010 - const uint16_t SUSTAIN_CONNECTION = 0x00000004; //000000100 - - const uint16_t CREATED = 0x00000008; //000001000 - const uint16_t UNAVAILABLE = 0x00000010; //000010000 - const uint16_t TRACKING = 0x00000020; //000100000 - const uint16_t CONNECTED = 0x00000040; //001000000 - const uint16_t TRACKING_WANDS = 0x00000080; //010000000 - const uint16_t ERROR = 0x00000100; //100000000 + const uint16_t READY = 0x00000001; //0000000001 + const uint16_t GRAPHICS_INIT = 0x00000002; //0000000010 + const uint16_t SUSTAIN_CONNECTION = 0x00000004; //0000000100 + + const uint16_t CREATED = 0x00000008; //0000001000 + const uint16_t UNAVAILABLE = 0x00000010; //0000010000 + const uint16_t TRACKING = 0x00000020; //0000100000 + const uint16_t CONNECTED = 0x00000040; //0001000000 + const uint16_t TRACKING_WANDS = 0x00000080; //0010000000 + const uint16_t ERROR = 0x00000100; //0100000000 + const uint16_t DISPLAY_STARTED = 0x00000200; //1000000000 } struct GlassesEvent { @@ -82,10 +83,13 @@ class Glasses bool is_available(); bool is_tracking(); - bool allocate_handle(T5_Context context); + bool allocate_handle(T5_Context context); void destroy_handle(); void connect(const std::string_view application_name); void disconnect(); + void start_display(); + void stop_display(); + float get_ipd(); float get_fov(); @@ -128,6 +132,8 @@ class Glasses void set_swap_chain_texture_pair(int swap_chain_idx, intptr_t left_eye_handle, intptr_t right_eye_handle); void set_swap_chain_texture_array(int swap_chain_idx, intptr_t array_handle); + virtual void on_start_display() {} + virtual void on_stop_display() {} virtual void on_glasses_reserved() {} virtual void on_glasses_released() {} virtual void on_glasses_dropped() {} @@ -172,6 +178,8 @@ class Glasses float _ipd = 0.059f; GlassesFlags _state; + GlassesFlags _previous_event_state; + GlassesFlags _previous_update_state; bool _is_upside_down_texture = false; diff --git a/extension/T5Integration/Logging.h b/extension/T5Integration/Logging.h index 094b40c..86bb7d1 100644 --- a/extension/T5Integration/Logging.h +++ b/extension/T5Integration/Logging.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include namespace T5Integration { @@ -58,6 +59,10 @@ void log_message(T var1, Types... var2) { #define LOG_TOGGLE(INIT, TEST, MSG1, MSG2) { static bool toggle ## __LINE__ = (INIT); T5Integration::log_toggle((TEST), toggle ## __LINE__, MSG1, MSG2); } #endif +#ifndef LOG_MESSAGE +#define LOG_MESSAGE(...) T5Integration::log_message(__func__, ":", __LINE__, " ", __VA_ARGS__) +#endif + #ifndef LOG_ERROR #define LOG_ERROR(message) T5Integration::log_error((message), __func__, __FILE__, __LINE__) #endif diff --git a/extension/T5Integration/StateFlags.h b/extension/T5Integration/StateFlags.h index dfd3dc9..97f864b 100644 --- a/extension/T5Integration/StateFlags.h +++ b/extension/T5Integration/StateFlags.h @@ -16,14 +16,15 @@ class StateFlags return _current.load(); } - FlagType get_changes() const + void set(FlagType state) { - return (_current.load() ^ _previous); + _current.fetch_or(state); } - void set(FlagType state) + bool set_and_was_toggled(FlagType state) { - _current.fetch_or(state); + T old = _current.fetch_or(state); + return (old & state) != state; } void clear(FlagType state) @@ -31,18 +32,20 @@ class StateFlags _current.fetch_and(~state); } - void clear_all(bool clear_changes = true) + bool clear_and_was_toggled(FlagType state) + { + T old = _current.fetch_and(~state); + return (old & state) == state; + } + + void clear_all() { _current.store(0); - if(clear_changes) - _previous = 0; } - void reset(FlagType state, bool clear_changes = false) + void reset(FlagType state) { _current.store(state); - if(clear_changes) - _previous = state; } bool is_current(FlagType state) const @@ -60,25 +63,25 @@ class StateFlags return (_current.load() & state) != state; } - bool any_changed(FlagType state) const + bool any_changed(const StateFlags& from, FlagType query_state) const { - return ((_current.load() ^ _previous) & state) != 0; + return ((_current.load() ^ from._current.load()) & query_state) != 0; } - bool became_set(FlagType state) const { - return (_current.load() & state) == state && (_previous & state) != state; + bool became_set(const StateFlags& from, FlagType query_state) const { + return (_current.load() & query_state) == query_state && + (from._current.load() & query_state) != query_state; } - bool became_clear(FlagType state) const { - return (_current.load() & state) != state && (_previous & state) == state; + bool became_clear(const StateFlags& from, FlagType query_state) const { + return (_current.load() & query_state) != query_state && + (from._current.load() & query_state) == query_state; } - void reset_changes() - { - _previous = _current; + void sync_from(const StateFlags& from) { + _current.store(from._current.load()); } private: std::atomic _current; - FlagType _previous; }; diff --git a/extension/T5Integration/T5Service.cpp b/extension/T5Integration/T5Service.cpp index 7ae438b..9348f86 100644 --- a/extension/T5Integration/T5Service.cpp +++ b/extension/T5Integration/T5Service.cpp @@ -12,61 +12,63 @@ T5Service::T5Service() { _graphics_api = T5_GraphicsApi::kT5_GraphicsApi_None; _scheduler = ObjectRegistry::scheduler(); - _state.clear_all(true); + _state.clear_all(); + _previous_event_state.clear_all(); } T5Service::~T5Service() { - stop_service(); } bool T5Service::start_service(const std::string_view application_id, std::string_view application_version, uint8_t sdk_type) { - if(_state.is_any_current(T5ServiceState::RUNNING | T5ServiceState::STARTING)) + if(_state.is_current(T5ServiceState::RUNNING)) return true; - if(_graphics_api == T5_GraphicsApi::kT5_GraphicsApi_None) { - LOG_ERROR("TiltFive graphics api is not set"); - return false; - } + if(_state.set_and_was_toggled(T5ServiceState::STARTING)) + { + if(_graphics_api == T5_GraphicsApi::kT5_GraphicsApi_None) { + LOG_ERROR("TiltFive graphics api is not set"); + return false; + } - T5_ClientInfo clientInfo; - clientInfo.applicationId = application_id.data(); - clientInfo.applicationVersion = application_version.data(); - clientInfo.sdkType = sdk_type; - - auto result = t5CreateContext(&_context, &clientInfo, nullptr); + T5_ClientInfo clientInfo; + clientInfo.applicationId = application_id.data(); + clientInfo.applicationVersion = application_version.data(); + clientInfo.sdkType = sdk_type; + + auto result = t5CreateContext(&_context, &clientInfo, nullptr); - if(result != T5_SUCCESS) { - LOG_T5_ERROR(result); - return false; - } - - _state.set(T5ServiceState::STARTING); + if(result != T5_SUCCESS) { + LOG_T5_ERROR(result); + return false; + } - _scheduler->start(); - _scheduler->add_task(startup_checks()); + _state.set(T5ServiceState::STARTING); + _scheduler->start(); + _scheduler->add_task(startup_checks()); + } return true; } void T5Service::stop_service() { - if(_state.is_not_current(T5ServiceState::RUNNING)) - return; - - _state.clear(T5ServiceState::RUNNING); - - _scheduler->stop(); - for(int i = 0; i < _glasses_list.size(); i++) { - _glasses_list[i]->disconnect(); - _glasses_list[i]->destroy_handle(); - } - _glasses_list.clear(); + if( _state.clear_and_was_toggled(T5ServiceState::RUNNING) || + _state.clear_and_was_toggled(T5ServiceState::STARTING)) + { + _scheduler->stop(); + for(int i = 0; i < _glasses_list.size(); i++) { + _glasses_list[i]->stop_display(); + _glasses_list[i]->disconnect(); + _glasses_list[i]->destroy_handle(); + } + _glasses_list.clear(); - if(_context) - { - std::lock_guard lock(g_t5_exclusivity_group_1); - t5DestroyContext(&_context); + if(_context) + { + std::lock_guard lock(g_t5_exclusivity_group_1); + t5DestroyContext(&_context); + } + _context = nullptr; } - _context = nullptr; } std::optional T5Service::find_glasses_idx(const std::string_view glasses_id) { @@ -200,7 +202,6 @@ CotaskPtr T5Service::query_glasses_list() { break; parsed_id_list.emplace_back(str_view.substr(0, pos)); str_view.remove_prefix(pos + 1); - } co_await run_in_foreground; @@ -270,23 +271,19 @@ void T5Service::update_tracking() { } void T5Service::get_service_events(std::vector& out_events) { - - auto changes = _state.get_changes(); - auto current_state = _state.get_current(); - - if(_state.became_set(T5ServiceState::T5_UNAVAILABLE)) { + if(_state.became_set(_previous_event_state, T5ServiceState::T5_UNAVAILABLE)) { out_events.push_back(T5ServiceEvent(T5ServiceEvent::E_T5_UNAVAILABLE)); } - if(_state.became_set(T5ServiceState::T5_INCOMPATIBLE_VERSION)) { + if(_state.became_set(_previous_event_state, T5ServiceState::T5_INCOMPATIBLE_VERSION)) { out_events.push_back(T5ServiceEvent(T5ServiceEvent::E_T5_INCOMPATIBLE_VERSION)); } - if(_state.became_set(T5ServiceState::RUNNING)) { + if(_state.became_set(_previous_event_state, T5ServiceState::RUNNING)) { out_events.push_back(T5ServiceEvent(T5ServiceEvent::E_RUNNING)); } - if(_state.became_clear(T5ServiceState::RUNNING)) { + if(_state.became_clear(_previous_event_state, T5ServiceState::RUNNING)) { out_events.push_back(T5ServiceEvent(T5ServiceEvent::E_STOPPED)); } - _state.reset_changes(); + _previous_event_state.sync_from(_state); } void T5Service::get_glasses_events(std::vector& out_events) { diff --git a/extension/T5Integration/T5Service.h b/extension/T5Integration/T5Service.h index 69269b1..db992ce 100644 --- a/extension/T5Integration/T5Service.h +++ b/extension/T5Integration/T5Service.h @@ -111,6 +111,7 @@ class T5Service { std::vector _glasses_list; T5ServiceFlags _state; + T5ServiceFlags _previous_event_state; std::chrono::milliseconds _poll_rate_for_monitoring = 2s; std::chrono::milliseconds _poll_rate_for_retry = 100ms; diff --git a/extension/T5Integration/Wand.cpp b/extension/T5Integration/Wand.cpp index d385528..e84c28e 100644 --- a/extension/T5Integration/Wand.cpp +++ b/extension/T5Integration/Wand.cpp @@ -151,8 +151,8 @@ void WandService::monitor_wands(std::stop_token s_token) { if(event.type != kT5_WandStreamEventType_Desync) { std::lock_guard lock(_list_access); - auto opt_wand_ptr = find_wand(_wand_list, event.wandId); - auto wand = opt_wand_ptr ? opt_wand_ptr.value() : &_wand_list.emplace_back(); + auto wand_ptr = find_wand(_wand_list, event.wandId); + auto wand = wand_ptr ? wand_ptr : &_wand_list.emplace_back(); wand->update_from_stream_event(event); } else { diff --git a/extension/T5Integration/Wand.h b/extension/T5Integration/Wand.h index 8a23762..e872f39 100644 --- a/extension/T5Integration/Wand.h +++ b/extension/T5Integration/Wand.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include @@ -81,15 +82,15 @@ class WandService { T5_Result _last_wand_error; }; -inline std::optional find_wand(const WandList& list, T5_WandHandle handle) { +inline Wand* find_wand(WandList& list, T5_WandHandle handle) { auto it = std::find_if(list.begin(), list.end(), [handle](auto& test_wand) { return test_wand._handle == handle; }); if(it != list.end()) - return it._Ptr; - return std::nullopt; + return std::addressof(*it); + return nullptr; } } // T5Integration \ No newline at end of file diff --git a/extension/src/GodotT5Glasses.cpp b/extension/src/GodotT5Glasses.cpp index d7aab3a..339258b 100644 --- a/extension/src/GodotT5Glasses.cpp +++ b/extension/src/GodotT5Glasses.cpp @@ -97,11 +97,12 @@ void GodotT5Glasses::on_glasses_reserved() { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL(xr_server); - auto tracker_name = std::format("/user/{}/head", get_id()); + char buffer[64]; + ERR_FAIL_COND(snprintf(buffer, 64, "/user/%s/head", get_id().c_str()) > 64); _head.instantiate(); _head->set_tracker_type(XRServer::TRACKER_HEAD); - _head->set_tracker_name(tracker_name.c_str()); + _head->set_tracker_name(buffer); _head->set_tracker_desc("Players head"); xr_server->add_tracker(_head); } @@ -166,11 +167,12 @@ void GodotT5Glasses::add_tracker() { Ref positional_tracker; positional_tracker.instantiate(); - auto tracker_name = std::format("/user/{}/wand_{}", get_id(), new_id); + char buffer[64]; + ERR_FAIL_COND(snprintf(buffer, 64, "/user/%s/wand_%d", get_id().c_str(), new_id) > 64); - positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); - positional_tracker->set_tracker_name(tracker_name.c_str()); - positional_tracker->set_tracker_desc(tracker_name.c_str()); + positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); + positional_tracker->set_tracker_name(buffer); + positional_tracker->set_tracker_desc("Tracks wand"); _wand_trackers.push_back(positional_tracker); } diff --git a/extension/src/OpenGLGlasses.cpp b/extension/src/OpenGLGlasses.cpp index 8c2d588..1dc1727 100644 --- a/extension/src/OpenGLGlasses.cpp +++ b/extension/src/OpenGLGlasses.cpp @@ -20,7 +20,8 @@ OpenGLGlasses::OpenGLGlasses(std::string_view id) void OpenGLGlasses::SwapChainTextures::allocate_textures(int width, int height) { auto render_server = RenderingServer::get_singleton(); - deallocate_textures(); + if(is_allocated) + deallocate_textures(); Ref dummy_image = Image::create(width, height, false, godot::Image::FORMAT_RGBA8); godot::Color bg(0,0,0); @@ -32,10 +33,13 @@ void OpenGLGlasses::SwapChainTextures::allocate_textures(int width, int height) render_tex.instantiate(); render_tex->create_from_images(image_arr); + + is_allocated = true; } void OpenGLGlasses::SwapChainTextures::deallocate_textures() { render_tex.unref(); + is_allocated = false; } void OpenGLGlasses::allocate_textures() { @@ -58,18 +62,11 @@ void OpenGLGlasses::deallocate_textures() { } } -void OpenGLGlasses::on_glasses_reserved() { - GodotT5Glasses::on_glasses_reserved(); +void OpenGLGlasses::on_start_display() { allocate_textures(); } -void OpenGLGlasses::on_glasses_released() { - GodotT5Glasses::on_glasses_released(); - deallocate_textures(); -} - -void OpenGLGlasses::on_glasses_dropped() { - GodotT5Glasses::on_glasses_dropped(); +void OpenGLGlasses::on_stop_display() { deallocate_textures(); } diff --git a/extension/src/OpenGLGlasses.h b/extension/src/OpenGLGlasses.h index 7d90345..586f7a1 100644 --- a/extension/src/OpenGLGlasses.h +++ b/extension/src/OpenGLGlasses.h @@ -16,6 +16,7 @@ namespace GodotT5Integration { void allocate_textures(int width, int height); void deallocate_textures(); + bool is_allocated = false; Ref render_tex; }; @@ -30,9 +31,8 @@ namespace GodotT5Integration { void allocate_textures(); void deallocate_textures(); - virtual void on_glasses_reserved() override; - virtual void on_glasses_released() override; - virtual void on_glasses_dropped() override; + virtual void on_start_display() override; + virtual void on_stop_display() override; private: diff --git a/extension/src/TiltFiveXRInterface.cpp b/extension/src/TiltFiveXRInterface.cpp index 6191922..d9c590d 100644 --- a/extension/src/TiltFiveXRInterface.cpp +++ b/extension/src/TiltFiveXRInterface.cpp @@ -205,6 +205,7 @@ void TiltFiveXRInterface::_start_display(TiltFiveXRInterface::GlassesIndexEntry& WARN_PRINT("Glasses need to be reserved to display viewport"); return; } + glasses->start_display(); entry.viewport_id = viewport->get_instance_id(); entry.gameboard_id = gameboard->get_instance_id(); @@ -220,11 +221,13 @@ void TiltFiveXRInterface::stop_display(const StringName glasses_id) { void TiltFiveXRInterface::_stop_display(GlassesIndexEntry& entry) { + auto glasses = entry.glasses.lock(); auto viewport = Object::cast_to(ObjectDB::get_instance(entry.viewport_id)); if(viewport) { viewport->set_use_xr(false); viewport->set_update_mode(godot::SubViewport::UpdateMode::UPDATE_DISABLED); } + glasses->stop_display(); entry.viewport_id = ObjectID(); entry.gameboard_id = ObjectID(); } diff --git a/extension/src/VulkanGlasses.cpp b/extension/src/VulkanGlasses.cpp index fc869f6..3411bf1 100644 --- a/extension/src/VulkanGlasses.cpp +++ b/extension/src/VulkanGlasses.cpp @@ -23,10 +23,10 @@ VulkanGlasses::VulkanGlasses(std::string_view id) } void VulkanGlasses::SwapChainTextures::allocate_textures(int width, int height) { - deallocate_textures(); + if(is_allocated) + deallocate_textures(); auto render_server = RenderingServer::get_singleton(); - auto service = T5Integration::ObjectRegistry::service(); auto render_device = render_server->get_rendering_device(); Ref texture_format_render; @@ -54,11 +54,15 @@ void VulkanGlasses::SwapChainTextures::allocate_textures(int width, int height) left_tex_handle = render_device->get_driver_resource(RenderingDevice::DRIVER_RESOURCE_VULKAN_IMAGE_VIEW, left_eye_tex, 0); right_tex_handle = render_device->get_driver_resource(RenderingDevice::DRIVER_RESOURCE_VULKAN_IMAGE_VIEW, right_eye_tex, 0); + + is_allocated = true; } void VulkanGlasses::SwapChainTextures::deallocate_textures() { + if(!is_allocated) + return; + auto render_server = RenderingServer::get_singleton(); - auto service = T5Integration::ObjectRegistry::service(); auto render_device = render_server->get_rendering_device(); if(right_eye_tex.is_valid()) @@ -67,6 +71,11 @@ void VulkanGlasses::SwapChainTextures::deallocate_textures() { render_device->free_rid(left_eye_tex); if(render_tex.is_valid()) render_device->free_rid(render_tex); + + left_tex_handle = 0; + right_tex_handle = 0; + + is_allocated = false; } void VulkanGlasses::allocate_textures() { @@ -95,18 +104,11 @@ void VulkanGlasses::deallocate_textures() { } } -void VulkanGlasses::on_glasses_reserved() { - GodotT5Glasses::on_glasses_reserved(); +void VulkanGlasses::on_start_display() { allocate_textures(); } -void VulkanGlasses::on_glasses_released() { - GodotT5Glasses::on_glasses_released(); - deallocate_textures(); -} - -void VulkanGlasses::on_glasses_dropped() { - GodotT5Glasses::on_glasses_dropped(); +void VulkanGlasses::on_stop_display() { deallocate_textures(); } diff --git a/extension/src/VulkanGlasses.h b/extension/src/VulkanGlasses.h index 376aa82..f74f2c2 100644 --- a/extension/src/VulkanGlasses.h +++ b/extension/src/VulkanGlasses.h @@ -12,6 +12,7 @@ namespace GodotT5Integration { void allocate_textures(int width, int height); void deallocate_textures(); + bool is_allocated = false; RID render_tex; RID left_eye_tex; RID right_eye_tex; @@ -31,10 +32,8 @@ namespace GodotT5Integration { void allocate_textures(); void deallocate_textures(); - virtual void on_glasses_reserved() override; - virtual void on_glasses_released() override; - virtual void on_glasses_dropped() override; - + virtual void on_start_display() override; + virtual void on_stop_display() override; private: