Skip to content

Commit

Permalink
Fixes for initialization and glasses state management
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
patrickdown committed Dec 5, 2023
1 parent 60cea05 commit dd272f1
Show file tree
Hide file tree
Showing 16 changed files with 223 additions and 181 deletions.
33 changes: 27 additions & 6 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -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++
Expand All @@ -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])

Expand Down
9 changes: 9 additions & 0 deletions example.gd/addons/tiltfive/tiltfive.gdextension
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand All @@ -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" : ""
}

108 changes: 51 additions & 57 deletions extension/T5Integration/Glasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include <Glasses.h>
#include <Logging.h>
#include <Wand.h>
#include <cmath>


using TaskSystem::task_sleep;
using TaskSystem::run_in_foreground;
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -427,7 +435,6 @@ namespace T5Integration {
}

void Glasses::disconnect() {

if (_state.is_current(GlassesState::READY)) {
T5_Result result;
{
Expand All @@ -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();
Expand Down Expand Up @@ -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;
}
Expand All @@ -605,48 +613,34 @@ namespace T5Integration {

void Glasses::get_events(int index, std::vector<GlassesEvent>& 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);
}
}
30 changes: 19 additions & 11 deletions extension/T5Integration/Glasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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() {}
Expand Down Expand Up @@ -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;

Expand Down
5 changes: 5 additions & 0 deletions extension/T5Integration/Logging.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include <memory>
#include <sstream>
#include <TiltFiveNative.h>

namespace T5Integration {
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit dd272f1

Please sign in to comment.