Skip to content

Commit f655719

Browse files
0forksImUrX
andauthored
Implement async IPC (#38)
* Implement async IPC * Refactor and tests * Pin vcpkg registry * ci: Fix cache key, add tests * Fix code style * Print connection error only once if not changed * Fix indent * Fix the indent fix * ci: Add CMakeLists to cache key * Print universe error only once if not changed * Fix naming and refactor * Log tracker statuses * Poll at 500hz * Add sleep benchmark * Fix adding trackers * Remove redundant thises * Change pose request thread logs * Fix atomic on linux * Update dependencies * Get only the HMD pose * Copy devices properly * Send HMD battery at 10Hz * Use already defined prop container for battery * Handle $HOME and $XDG_DATA_DIR * This is fPredictedSecondsFromNow, not device index * update github actions (#49) # Conflicts: # .github/workflows/c-cpp.yml * Update vcpkg and packages * Update github actions * Handle battery message in tests * Position in tracker update was optional * Split implementation from headers * Fix typo * Remove unused bool * Remove old log method * Update readme * Let compiler handle endianness for headers * tests: Check CircularBuffer threading * Fix serial log * Set pose valid/connected flags on position update * Add path to bridge logs * Update min cmake version * Optimize build size --------- Co-authored-by: Uriel <[email protected]>
1 parent 760eb1a commit f655719

35 files changed

+1744
-1244
lines changed

.github/workflows/c-cpp.yml

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: SlimeVR OpenVR Driver
22

3-
on: [ push, pull_request ]
3+
on: [ push, pull_request, workflow_dispatch ]
44

55
jobs:
66
build:
@@ -15,11 +15,11 @@ jobs:
1515
- os: windows-latest
1616
triplet: x64-windows-static-md
1717
target: ALL_BUILD
18-
release_dir: Release/driver # dir of driver binaries within env.CMAKE_BUILD_DIR, VS multi-config uses <CONFIG>/ subfolder
18+
release_dir: Release # dir of driver binaries within env.CMAKE_BUILD_DIR, VS multi-config uses <CONFIG>/ subfolder
1919
- os: ubuntu-latest
2020
triplet: x64-linux
2121
target: all
22-
release_dir: driver # makefile single config won't have subfolder
22+
release_dir: "" # makefile single config won't have subfolder
2323
env:
2424
# Indicates the CMake build directory where project files and binaries are being produced.
2525
CMAKE_BUILD_DIR: ${{ github.workspace }}/build
@@ -30,15 +30,12 @@ jobs:
3030
- uses: actions/checkout@v4
3131
with:
3232
submodules: true
33-
33+
3434
- uses: lukka/get-cmake@latest
35-
36-
- name: Clone vcpkg
37-
uses: actions/checkout@v4
38-
with:
39-
repository: microsoft/vcpkg
40-
path: ${{ env.VCPKG_ROOT }}
41-
submodules: true
35+
36+
- name: Get submodule commit hashes
37+
id: submodule_hashes
38+
run: git submodule foreach --recursive git rev-parse HEAD > submodule_hashes.txt
4239

4340
- name: Restore vcpkg and its artifacts
4441
uses: actions/cache@v4
@@ -52,12 +49,11 @@ jobs:
5249
!${{ env.VCPKG_ROOT }}/buildtrees
5350
!${{ env.VCPKG_ROOT }}/packages
5451
!${{ env.VCPKG_ROOT }}/downloads
55-
# The key is composed in a way that it gets properly invalidated: this must happen whenever vcpkg's Git commit id changes, or the list of packages changes. In this case a cache miss must happen and a new entry with a new key with be pushed to GitHub the cache service.
52+
# The key is composed in a way that it gets properly invalidated: this must happen whenever vcpkg/submodule Git commit id changes, or the list of packages changes. In this case a cache miss must happen and a new entry with a new key with be pushed to GitHub the cache service.
5653
# The key includes: hash of the vcpkg.json file, the hash of the vcpkg Git commit id, and the used vcpkg's triplet. The vcpkg's commit id would suffice, but computing an hash out it does not harm.
5754
# Note: given a key, the cache content is immutable. If a cache entry has been created improperly, in order the recreate the right content the key must be changed as well, and it must be brand new (i.e. not existing already).
58-
key: |
59-
${{ hashFiles( 'vcpkg_manifest/vcpkg.json' ) }}-${{ hashFiles( '.git/modules/vcpkg/HEAD' )}}-${{ hashFiles( '${{ env.VCPKG_ROOT }}/.git/HEAD' )}}-${{ matrix.triplet }}-invalidate
60-
55+
key: ${{ matrix.triplet }}-${{ hashFiles( '**/vcpkg.json', '**/CMakeLists.txt' ) }}-${{ hashFiles( 'submodule_hashes.txt' )}}
56+
6157
- if: matrix.os == 'windows-latest'
6258
name: Set up vcpkg for Windows
6359
run: ${{ env.VCPKG_ROOT }}/bootstrap-vcpkg.bat
@@ -67,7 +63,7 @@ jobs:
6763
run: ${{ env.VCPKG_ROOT }}/bootstrap-vcpkg.sh
6864

6965
- name: Configure CMake
70-
run: cmake -S "${{github.workspace}}" -B "${{env.CMAKE_BUILD_DIR}}" -DVCPKG_TARGET_TRIPLET=${{matrix.triplet}}
66+
run: cmake -S "${{github.workspace}}" -B "${{env.CMAKE_BUILD_DIR}}" -DVCPKG_TARGET_TRIPLET=${{matrix.triplet}} -DCMAKE_BUILD_TYPE=Release
7167

7268
- name: Build
7369
run: cmake --build "${{env.CMAKE_BUILD_DIR}}" --config Release --target "${{ matrix.target }}" -j 6 --
@@ -80,16 +76,46 @@ jobs:
8076
# A file, directory or wildcard pattern that describes what to upload
8177
# Using wildcards so that only the driver directory gets included (if you specify it, then it won't be included)
8278
path: |
83-
${{env.CMAKE_BUILD_DIR}}/${{ matrix.release_dir }}/*
79+
${{env.CMAKE_BUILD_DIR}}/${{ matrix.release_dir }}/driver/*
80+
${{env.CMAKE_BUILD_DIR}}/${{ matrix.release_dir }}/tests*
8481
8582
- name: Zip
8683
if: startsWith(github.ref, 'refs/tags/')
87-
working-directory: ${{env.CMAKE_BUILD_DIR}}/${{ matrix.release_dir }}
88-
run: cmake -E tar "cf" "${{env.CMAKE_BUILD_DIR}}/slimevr-openvr-driver-${{ matrix.triplet }}.zip" --format=zip -- ${{env.CMAKE_BUILD_DIR}}/${{ matrix.release_dir }}/slimevr
84+
working-directory: ${{env.CMAKE_BUILD_DIR}}/${{ matrix.release_dir }}/driver
85+
run: cmake -E tar "cf" "${{env.CMAKE_BUILD_DIR}}/slimevr-openvr-driver-${{ matrix.triplet }}.zip" --format=zip -- ${{env.CMAKE_BUILD_DIR}}/${{ matrix.release_dir }}/driver/slimevr
8986

9087
- name: Release
9188
uses: softprops/action-gh-release@v2
9289
if: startsWith(github.ref, 'refs/tags/')
9390
with:
9491
files: "${{env.CMAKE_BUILD_DIR}}/slimevr-openvr-driver-${{ matrix.triplet }}.zip"
95-
92+
93+
test:
94+
name: Run tests
95+
needs: build
96+
runs-on: ${{ matrix.os }}
97+
strategy:
98+
fail-fast: false
99+
matrix:
100+
os: [windows-latest, ubuntu-latest]
101+
include:
102+
- os: windows-latest
103+
triplet: x64-windows-static-md
104+
target: RUN_TESTS
105+
- os: ubuntu-latest
106+
triplet: x64-linux
107+
target: test
108+
steps:
109+
- name: Download build artifact
110+
uses: actions/download-artifact@v4
111+
with:
112+
name: slimevr-openvr-driver-${{ matrix.triplet }}
113+
path: ${{ github.workspace }}
114+
- if: matrix.os == 'windows-latest'
115+
name: Run tests on Windows
116+
working-directory: ${{ github.workspace }}/
117+
run: .\tests.exe
118+
- if: matrix.os != 'windows-latest'
119+
name: Run tests on Unix
120+
working-directory: ${{ github.workspace }}/
121+
run: chmod +x ./tests && ./tests

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
[submodule "libraries/linalg"]
55
path = libraries/linalg
66
url = https://github.com/sgorsten/linalg.git
7+
[submodule "vcpkg"]
8+
path = vcpkg
9+
url = https://github.com/Microsoft/vcpkg.git

CMakeLists.txt

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required(VERSION 3.0.0)
1+
cmake_minimum_required(VERSION 3.5.0)
22

33
#if (NOT DEFINED VCPKG_TARGET_TRIPLET)
44
if(WIN32)
@@ -69,17 +69,56 @@ SET_SOURCE_FILES_PROPERTIES(${PROTO_SRC} ${PROTO_INCL} PROPERTIES GENERATED TRUE
6969

7070
find_package(simdjson CONFIG REQUIRED)
7171

72+
# libuv
73+
find_package(uvw CONFIG REQUIRED)
74+
75+
# Catch2
76+
find_package(Catch2 3 REQUIRED)
77+
7278
# Project
73-
file(GLOB_RECURSE HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp")
79+
set(DEPS_INCLUDES
80+
"${OPENVR_INCLUDE_DIR}"
81+
"${CMAKE_CURRENT_SOURCE_DIR}/libraries/linalg"
82+
"${CMAKE_CURRENT_SOURCE_DIR}/src/"
83+
)
84+
set(DEPS_LIBS
85+
"${OPENVR_LIB}"
86+
protobuf::libprotoc
87+
protobuf::libprotobuf
88+
protobuf::libprotobuf-lite
89+
simdjson::simdjson
90+
uvw::uvw
91+
)
92+
93+
# compile into a static lib
7494
file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
75-
add_library("${PROJECT_NAME}" SHARED "${HEADERS}" "${SOURCES}" ${PROTO_HEADER} ${PROTO_SRC})
76-
target_include_directories("${PROJECT_NAME}" PUBLIC "${OPENVR_INCLUDE_DIR}")
77-
target_include_directories("${PROJECT_NAME}" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/libraries/linalg")
78-
target_include_directories("${PROJECT_NAME}" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src/")
79-
target_link_libraries("${PROJECT_NAME}" PUBLIC "${OPENVR_LIB}" protobuf::libprotoc protobuf::libprotobuf protobuf::libprotobuf-lite simdjson::simdjson)
95+
file(GLOB_RECURSE HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp")
96+
add_library("${PROJECT_NAME}_static" STATIC ${SOURCES} ${PROTO_HEADER} ${PROTO_SRC})
97+
target_link_libraries("${PROJECT_NAME}_static" PUBLIC ${DEPS_LIBS})
98+
set_property(TARGET "${PROJECT_NAME}_static" PROPERTY CXX_STANDARD 17)
99+
include_directories("${PROJECT_NAME}_static" PUBLIC ${DEPS_INCLUDES} ${Protobuf_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
100+
if(UNIX)
101+
target_compile_options("${PROJECT_NAME}_static" PRIVATE "-fPIC")
102+
target_link_libraries("${PROJECT_NAME}_static" PUBLIC atomic)
103+
endif()
104+
105+
# compile driver
106+
file(GLOB_RECURSE DRIVER_MAIN "${CMAKE_CURRENT_SOURCE_DIR}/src/DriverFactory.cpp")
107+
add_library("${PROJECT_NAME}" SHARED ${DRIVER_MAIN} ${HEADERS} ${PROTO_HEADER})
108+
target_link_libraries("${PROJECT_NAME}" PUBLIC "${PROJECT_NAME}_static")
80109
set_property(TARGET "${PROJECT_NAME}" PROPERTY CXX_STANDARD 17)
81-
include_directories(${Protobuf_INCLUDE_DIRS})
82-
include_directories(${CMAKE_CURRENT_BINARY_DIR})
110+
111+
# compile tests
112+
function(build_tests target_name test_dir)
113+
file(GLOB TESTS "${CMAKE_CURRENT_SOURCE_DIR}/${test_dir}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/${test_dir}/*.hpp")
114+
file(GLOB TESTS_COMMON "${CMAKE_CURRENT_SOURCE_DIR}/test/common/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/test/common/*.hpp")
115+
add_executable(${target_name} ${TESTS} ${TESTS_COMMON} ${HEADERS} ${PROTO_HEADER})
116+
target_link_libraries(${target_name} PUBLIC "${PROJECT_NAME}_static" Catch2::Catch2WithMain)
117+
set_property(TARGET ${target_name} PROPERTY CXX_STANDARD 17)
118+
endfunction()
119+
build_tests(tests "test")
120+
build_tests(tests_integration "test/integration")
121+
add_test(NAME tests COMMAND "tests")
83122

84123
# IDE Config
85124
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/src" PREFIX "Header Files" FILES ${HEADERS})

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,16 @@ okay with this and that you are authorized to provide the above licenses.
3838

3939
### Building
4040

41-
To build the project with VSCode you need to install two things: [vcpkg](https://vcpkg.io/en/getting-started.html) and [VS Build Tools](https://visualstudio.microsoft.com/downloads/).
41+
Clone the repo with `git clone --recurse-submodules https://github.com/SlimeVR/SlimeVR-OpenVR-Driver` to clone with all libraries and [vcpkg](https://vcpkg.io/en/getting-started.html) registry.
42+
43+
To build the project with VSCode on Windows you need to install [VS Build Tools](https://visualstudio.microsoft.com/downloads/).
44+
45+
Run the bootstrap script to build vcpkg binary `.\vcpkg\bootstrap-vcpkg.bat` or `./vcpkg/bootstrap-vcpkg.sh`.
4246

4347
After installing vcpkg if you're on Windows, you need to run `vcpkg integrate install` command from the vcpkg folder to integrate it for VSCode.
4448

4549
For other systems and IDEs instructions are not available as of now, contributions are welcome.
50+
51+
### Updating vcpkg packages
52+
53+
To update vcpkg packages set the vcpkg registry submodule to a newer commit and rerun the bootstrap script.

src/DriverFactory.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,22 @@
66
static std::shared_ptr<SlimeVRDriver::IVRDriver> driver;
77

88
void* HmdDriverFactory(const char* interface_name, int* return_code) {
9-
if (std::strcmp(interface_name, vr::IServerTrackedDeviceProvider_Version) == 0) {
10-
if (!driver) {
11-
// Instantiate concrete impl
12-
driver = std::make_shared<SlimeVRDriver::VRDriver>();
13-
}
14-
// We always have at least 1 ref to the shared ptr in "driver" so passing out raw pointer is ok
15-
return driver.get();
16-
}
9+
if (std::strcmp(interface_name, vr::IServerTrackedDeviceProvider_Version) == 0) {
10+
if (!driver) {
11+
// Instantiate concrete impl
12+
driver = std::make_shared<SlimeVRDriver::VRDriver>();
13+
}
14+
// We always have at least 1 ref to the shared ptr in "driver" so passing out raw pointer is ok
15+
return driver.get();
16+
}
1717

18-
if (return_code)
19-
*return_code = vr::VRInitError_Init_InterfaceNotFound;
18+
if (return_code) {
19+
*return_code = vr::VRInitError_Init_InterfaceNotFound;
20+
}
2021

21-
return nullptr;
22+
return nullptr;
2223
}
2324

2425
std::shared_ptr<SlimeVRDriver::IVRDriver> SlimeVRDriver::GetDriver() {
25-
return driver;
26+
return driver;
2627
}

src/IVRDevice.hpp

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,41 @@
66
#include "ProtobufMessages.pb.h"
77

88
namespace SlimeVRDriver {
9-
109
class IVRDevice : public vr::ITrackedDeviceServerDriver {
1110
public:
12-
/// <summary>
13-
/// Returns the serial string for this device
14-
/// </summary>
15-
/// <returns>Device serial</returns>
11+
/**
12+
* Returns the serial string for this device.
13+
*
14+
* @return Device serial.
15+
*/
1616
virtual std::string GetSerial() = 0;
1717

18-
/// <summary>
19-
/// Runs any update logic for this device.
20-
/// Called once per frame
21-
/// </summary>
18+
/**
19+
* Runs any update logic for this device.
20+
* Called once per frame.
21+
*/
2222
virtual void Update() = 0;
2323

24-
/// <summary>
25-
/// Returns the OpenVR device index
26-
/// This should be 0 for HMDs
27-
/// </summary>
28-
/// <returns>OpenVR device index</returns>
24+
/**
25+
* Returns the OpenVR device index.
26+
* This should be 0 for HMDs.
27+
*
28+
* @returns OpenVR device index.
29+
*/
2930
virtual vr::TrackedDeviceIndex_t GetDeviceIndex() = 0;
3031

31-
/// <summary>
32-
/// Returns which type of device this device is
33-
/// </summary>
34-
/// <returns>The type of device</returns>
32+
/**
33+
* Returns which type of device this device is.
34+
*
35+
* @returns The type of device.
36+
*/
3537
virtual DeviceType GetDeviceType() = 0;
3638

37-
/// <summary>
38-
/// Makes a default device pose
39-
/// </summary>
40-
/// <returns>Default initialised pose</returns>
39+
/**
40+
* Makes a default device pose.
41+
*
42+
* @returns Default initialised pose.
43+
*/
4144
static inline vr::DriverPose_t MakeDefaultPose(bool connected = true, bool tracking = true) {
4245
vr::DriverPose_t out_pose = { 0 };
4346

@@ -51,6 +54,31 @@ namespace SlimeVRDriver {
5154
return out_pose;
5255
}
5356

57+
/**
58+
* Returns the device id.
59+
*/
60+
virtual int GetDeviceId() = 0;
61+
62+
/**
63+
* Sets the device id.
64+
*/
65+
virtual void SetDeviceId(int device_id) = 0;
66+
67+
/**
68+
* Updates device position from a received message.
69+
*/
70+
virtual void PositionMessage(messages::Position& position) = 0;
71+
72+
/**
73+
* Updates device status from a received message.
74+
*/
75+
virtual void StatusMessage(messages::TrackerStatus& status) = 0;
76+
77+
/**
78+
* Updates battery indicator from a received message.
79+
*/
80+
virtual void BatteryMessage(messages::Battery& battery) = 0;
81+
5482
// Inherited via ITrackedDeviceServerDriver
5583
virtual vr::EVRInitError Activate(uint32_t unObjectId) = 0;
5684
virtual void Deactivate() = 0;
@@ -59,12 +87,6 @@ namespace SlimeVRDriver {
5987
virtual void DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize) = 0;
6088
virtual vr::DriverPose_t GetPose() = 0;
6189

62-
virtual int getDeviceId() = 0;
63-
virtual void PositionMessage(messages::Position& position) = 0;
64-
virtual void StatusMessage(messages::TrackerStatus& status) = 0;
65-
66-
virtual void BatteryMessage(messages::Battery& battery) = 0;
67-
6890
~IVRDevice() = default;
6991
};
7092
};

0 commit comments

Comments
 (0)