Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement async IPC #38

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
03ef571
Implement async IPC
0forks Mar 21, 2023
a37f410
Refactor and tests
0forks Mar 26, 2023
c9d499d
Pin vcpkg registry
0forks Mar 26, 2023
b03f540
ci: Fix cache key, add tests
0forks Mar 26, 2023
8cc160b
Fix code style
0forks Mar 27, 2023
479c570
Print connection error only once if not changed
0forks Mar 27, 2023
ab0b1e2
Fix indent
0forks Mar 28, 2023
801e0ff
Fix the indent fix
0forks Mar 28, 2023
9d02b4b
ci: Add CMakeLists to cache key
0forks Apr 2, 2023
610a902
Print universe error only once if not changed
0forks Mar 28, 2023
7212890
Fix naming and refactor
0forks Mar 28, 2023
2a54f0d
Log tracker statuses
0forks Mar 28, 2023
582e199
Poll at 500hz
0forks Mar 28, 2023
73c2f19
Add sleep benchmark
0forks Apr 2, 2023
50e0f95
Fix adding trackers
0forks Apr 2, 2023
c27ee5b
Remove redundant thises
0forks Apr 2, 2023
93c7f22
Change pose request thread logs
0forks Apr 2, 2023
d3036c3
Fix atomic on linux
0forks Apr 8, 2023
54a1160
Merge remote-tracking branch 'upstream/main' into pr-asyncipc
0forks Aug 26, 2023
572c8e6
Update dependencies
0forks Nov 1, 2023
0b43b19
Get only the HMD pose
0forks Nov 1, 2023
d4349fb
Copy devices properly
0forks Nov 1, 2023
fdd6e9a
Send HMD battery at 10Hz
0forks Nov 1, 2023
599abe2
Use already defined prop container for battery
0forks Nov 1, 2023
996bef3
Handle $HOME and $XDG_DATA_DIR
0forks Aug 30, 2024
1b4cc65
Merge remote-tracking branch 'upstream/main' into pr-asyncipc
0forks Aug 30, 2024
303c9db
This is fPredictedSecondsFromNow, not device index
0forks Feb 20, 2025
511e6b4
update github actions (#49)
ImUrX Dec 8, 2024
dfaa24f
Merge remote-tracking branch 'upstream/main'
0forks Feb 20, 2025
766a262
Update vcpkg and packages
0forks Feb 20, 2025
8354526
Update github actions
0forks Feb 20, 2025
fcb3d69
Handle battery message in tests
0forks Feb 21, 2025
208d86e
Position in tracker update was optional
0forks Feb 21, 2025
4858b12
Split implementation from headers
0forks Feb 21, 2025
8bc8b98
Fix typo
0forks Feb 25, 2025
25a9797
Remove unused bool
0forks Feb 25, 2025
3dee28b
Remove old log method
0forks Feb 25, 2025
b78768b
Update readme
0forks Feb 25, 2025
2a69fb0
Let compiler handle endianness for headers
0forks Feb 25, 2025
e193b75
tests: Check CircularBuffer threading
0forks Mar 5, 2025
d8918e8
Fix serial log
0forks Mar 9, 2025
279b469
Set pose valid/connected flags on position update
0forks Mar 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 45 additions & 19 deletions .github/workflows/c-cpp.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: SlimeVR OpenVR Driver

on: [ push, pull_request ]
on: [ push, pull_request, workflow_dispatch ]

jobs:
build:
Expand All @@ -15,11 +15,11 @@ jobs:
- os: windows-latest
triplet: x64-windows-static-md
target: ALL_BUILD
release_dir: Release/driver # dir of driver binaries within env.CMAKE_BUILD_DIR, VS multi-config uses <CONFIG>/ subfolder
release_dir: Release # dir of driver binaries within env.CMAKE_BUILD_DIR, VS multi-config uses <CONFIG>/ subfolder
- os: ubuntu-latest
triplet: x64-linux
target: all
release_dir: driver # makefile single config won't have subfolder
release_dir: "" # makefile single config won't have subfolder
env:
# Indicates the CMake build directory where project files and binaries are being produced.
CMAKE_BUILD_DIR: ${{ github.workspace }}/build
Expand All @@ -30,15 +30,12 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: true

- uses: lukka/get-cmake@latest

- name: Clone vcpkg
uses: actions/checkout@v4
with:
repository: microsoft/vcpkg
path: ${{ env.VCPKG_ROOT }}
submodules: true

- name: Get submodule commit hashes
id: submodule_hashes
run: git submodule foreach --recursive git rev-parse HEAD > submodule_hashes.txt

- name: Restore vcpkg and its artifacts
uses: actions/cache@v4
Expand All @@ -52,12 +49,11 @@ jobs:
!${{ env.VCPKG_ROOT }}/buildtrees
!${{ env.VCPKG_ROOT }}/packages
!${{ env.VCPKG_ROOT }}/downloads
# 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.
# 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.
# 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.
# 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).
key: |
${{ hashFiles( 'vcpkg_manifest/vcpkg.json' ) }}-${{ hashFiles( '.git/modules/vcpkg/HEAD' )}}-${{ hashFiles( '${{ env.VCPKG_ROOT }}/.git/HEAD' )}}-${{ matrix.triplet }}-invalidate

key: ${{ matrix.triplet }}-${{ hashFiles( '**/vcpkg.json', '**/CMakeLists.txt' ) }}-${{ hashFiles( 'submodule_hashes.txt' )}}

- if: matrix.os == 'windows-latest'
name: Set up vcpkg for Windows
run: ${{ env.VCPKG_ROOT }}/bootstrap-vcpkg.bat
Expand All @@ -80,16 +76,46 @@ jobs:
# A file, directory or wildcard pattern that describes what to upload
# Using wildcards so that only the driver directory gets included (if you specify it, then it won't be included)
path: |
${{env.CMAKE_BUILD_DIR}}/${{ matrix.release_dir }}/*
${{env.CMAKE_BUILD_DIR}}/${{ matrix.release_dir }}/driver/*
${{env.CMAKE_BUILD_DIR}}/${{ matrix.release_dir }}/tests*

- name: Zip
if: startsWith(github.ref, 'refs/tags/')
working-directory: ${{env.CMAKE_BUILD_DIR}}/${{ matrix.release_dir }}
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
working-directory: ${{env.CMAKE_BUILD_DIR}}/${{ matrix.release_dir }}/driver
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

- name: Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: "${{env.CMAKE_BUILD_DIR}}/slimevr-openvr-driver-${{ matrix.triplet }}.zip"


test:
name: Run tests
needs: build
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest]
include:
- os: windows-latest
triplet: x64-windows-static-md
target: RUN_TESTS
- os: ubuntu-latest
triplet: x64-linux
target: test
steps:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: slimevr-openvr-driver-${{ matrix.triplet }}
path: ${{ github.workspace }}
- if: matrix.os == 'windows-latest'
name: Run tests on Windows
working-directory: ${{ github.workspace }}/
run: .\tests.exe
- if: matrix.os != 'windows-latest'
name: Run tests on Unix
working-directory: ${{ github.workspace }}/
run: chmod +x ./tests && ./tests
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "libraries/linalg"]
path = libraries/linalg
url = https://github.com/sgorsten/linalg.git
[submodule "vcpkg"]
path = vcpkg
url = https://github.com/Microsoft/vcpkg.git
55 changes: 47 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,56 @@ SET_SOURCE_FILES_PROPERTIES(${PROTO_SRC} ${PROTO_INCL} PROPERTIES GENERATED TRUE

find_package(simdjson CONFIG REQUIRED)

# libuv
find_package(uvw CONFIG REQUIRED)

# Catch2
find_package(Catch2 3 REQUIRED)

# Project
file(GLOB_RECURSE HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp")
set(DEPS_INCLUDES
"${OPENVR_INCLUDE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/libraries/linalg"
"${CMAKE_CURRENT_SOURCE_DIR}/src/"
)
set(DEPS_LIBS
"${OPENVR_LIB}"
protobuf::libprotoc
protobuf::libprotobuf
protobuf::libprotobuf-lite
simdjson::simdjson
uvw::uvw
)

# compile into a static lib
file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library("${PROJECT_NAME}" SHARED "${HEADERS}" "${SOURCES}" ${PROTO_HEADER} ${PROTO_SRC})
target_include_directories("${PROJECT_NAME}" PUBLIC "${OPENVR_INCLUDE_DIR}")
target_include_directories("${PROJECT_NAME}" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/libraries/linalg")
target_include_directories("${PROJECT_NAME}" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src/")
target_link_libraries("${PROJECT_NAME}" PUBLIC "${OPENVR_LIB}" protobuf::libprotoc protobuf::libprotobuf protobuf::libprotobuf-lite simdjson::simdjson)
file(GLOB_RECURSE HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp")
add_library("${PROJECT_NAME}_static" STATIC ${SOURCES} ${PROTO_HEADER} ${PROTO_SRC})
target_link_libraries("${PROJECT_NAME}_static" PUBLIC ${DEPS_LIBS})
set_property(TARGET "${PROJECT_NAME}_static" PROPERTY CXX_STANDARD 17)
include_directories("${PROJECT_NAME}_static" PUBLIC ${DEPS_INCLUDES} ${Protobuf_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
if(UNIX)
target_compile_options("${PROJECT_NAME}_static" PRIVATE "-fPIC")
target_link_libraries("${PROJECT_NAME}_static" PUBLIC atomic)
endif()

# compile driver
file(GLOB_RECURSE DRIVER_MAIN "${CMAKE_CURRENT_SOURCE_DIR}/src/DriverFactory.cpp")
add_library("${PROJECT_NAME}" SHARED ${DRIVER_MAIN} ${HEADERS} ${PROTO_HEADER})
target_link_libraries("${PROJECT_NAME}" PUBLIC "${PROJECT_NAME}_static")
set_property(TARGET "${PROJECT_NAME}" PROPERTY CXX_STANDARD 17)
include_directories(${Protobuf_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})

# compile tests
function(build_tests target_name test_dir)
file(GLOB TESTS "${CMAKE_CURRENT_SOURCE_DIR}/${test_dir}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/${test_dir}/*.hpp")
file(GLOB TESTS_COMMON "${CMAKE_CURRENT_SOURCE_DIR}/test/common/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/test/common/*.hpp")
add_executable(${target_name} ${TESTS} ${TESTS_COMMON} ${HEADERS} ${PROTO_HEADER})
target_link_libraries(${target_name} PUBLIC "${PROJECT_NAME}_static" Catch2::Catch2WithMain)
set_property(TARGET ${target_name} PROPERTY CXX_STANDARD 17)
endfunction()
build_tests(tests "test")
build_tests(tests_integration "test/integration")
add_test(NAME tests COMMAND "tests")

# IDE Config
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/src" PREFIX "Header Files" FILES ${HEADERS})
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,16 @@ okay with this and that you are authorized to provide the above licenses.

### Building

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/).
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.

To build the project with VSCode on Windows you need to install [VS Build Tools](https://visualstudio.microsoft.com/downloads/).

Run the bootstrap script to build vcpkg binary `.\vcpkg\bootstrap-vcpkg.bat` or `./vcpkg/bootstrap-vcpkg.sh`.

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.

For other systems and IDEs instructions are not available as of now, contributions are welcome.

### Updating vcpkg packages

To update vcpkg packages set the vcpkg registry submodule to a newer commit.
25 changes: 13 additions & 12 deletions src/DriverFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@
static std::shared_ptr<SlimeVRDriver::IVRDriver> driver;

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

if (return_code)
*return_code = vr::VRInitError_Init_InterfaceNotFound;
if (return_code) {
*return_code = vr::VRInitError_Init_InterfaceNotFound;
}

return nullptr;
return nullptr;
}

std::shared_ptr<SlimeVRDriver::IVRDriver> SlimeVRDriver::GetDriver() {
return driver;
return driver;
}
78 changes: 50 additions & 28 deletions src/IVRDevice.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,41 @@
#include "ProtobufMessages.pb.h"

namespace SlimeVRDriver {

class IVRDevice : public vr::ITrackedDeviceServerDriver {
public:
/// <summary>
/// Returns the serial string for this device
/// </summary>
/// <returns>Device serial</returns>
/**
* Returns the serial string for this device.
*
* @return Device serial.
*/
virtual std::string GetSerial() = 0;

/// <summary>
/// Runs any update logic for this device.
/// Called once per frame
/// </summary>
/**
* Runs any update logic for this device.
* Called once per frame.
*/
virtual void Update() = 0;

/// <summary>
/// Returns the OpenVR device index
/// This should be 0 for HMDs
/// </summary>
/// <returns>OpenVR device index</returns>
/**
* Returns the OpenVR device index.
* This should be 0 for HMDs.
*
* @returns OpenVR device index.
*/
virtual vr::TrackedDeviceIndex_t GetDeviceIndex() = 0;

/// <summary>
/// Returns which type of device this device is
/// </summary>
/// <returns>The type of device</returns>
/**
* Returns which type of device this device is.
*
* @returns The type of device.
*/
virtual DeviceType GetDeviceType() = 0;

/// <summary>
/// Makes a default device pose
/// </summary>
/// <returns>Default initialised pose</returns>
/**
* Makes a default device pose.
*
* @returns Default initialised pose.
*/
static inline vr::DriverPose_t MakeDefaultPose(bool connected = true, bool tracking = true) {
vr::DriverPose_t out_pose = { 0 };

Expand All @@ -51,6 +54,31 @@ namespace SlimeVRDriver {
return out_pose;
}

/**
* Returns the device id.
*/
virtual int GetDeviceId() = 0;

/**
* Sets the device id.
*/
virtual void SetDeviceId(int device_id) = 0;

/**
* Updates device position from a received message.
*/
virtual void PositionMessage(messages::Position& position) = 0;

/**
* Updates device status from a received message.
*/
virtual void StatusMessage(messages::TrackerStatus& status) = 0;

/**
* Updates battery indicator from a received message.
*/
virtual void BatteryMessage(messages::Battery& battery) = 0;

// Inherited via ITrackedDeviceServerDriver
virtual vr::EVRInitError Activate(uint32_t unObjectId) = 0;
virtual void Deactivate() = 0;
Expand All @@ -59,12 +87,6 @@ namespace SlimeVRDriver {
virtual void DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize) = 0;
virtual vr::DriverPose_t GetPose() = 0;

virtual int getDeviceId() = 0;
virtual void PositionMessage(messages::Position& position) = 0;
virtual void StatusMessage(messages::TrackerStatus& status) = 0;

virtual void BatteryMessage(messages::Battery& battery) = 0;

~IVRDevice() = default;
};
};
Loading