mirror of
https://github.com/hyblocker/OpenVR-SpaceCalibrator.git
synced 2026-10-06 14:00:19 +02:00
feat: begin work for linux compile
This commit is contained in:
18 files changed
+724
-90
No files matched your search
@@ -21,6 +21,8 @@ endfunction()
|
||||
# windows prefers win8.1 sdk instead of win 10 sdk for some god forsaken reason
|
||||
if(WIN32)
|
||||
set(CMAKE_SYSTEM_VERSION 10.0 CACHE STRING "Forcing Win10 SDK" FORCE)
|
||||
else()
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
project("SpaceCalibrator")
|
||||
|
||||
+20
-1
@@ -3,7 +3,7 @@
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32)
|
||||
#define OS_WINDOWS 1
|
||||
#define OS_LINUX 0
|
||||
#elif (defined(__gnu_linux__) || defined(__linux__))
|
||||
@@ -13,6 +13,22 @@
|
||||
#error "Unsupported OS"
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#define COMPILER_MSVC 0
|
||||
#define COMPILER_GCC 0
|
||||
#define COMPILER_CLANG 1
|
||||
#elif defined(_MSC_VER)
|
||||
#define COMPILER_MSVC 1
|
||||
#define COMPILER_GCC 0
|
||||
#define COMPILER_CLANG 0
|
||||
#elif defined(__GNUC__)
|
||||
#define COMPILER_MSVC 0
|
||||
#define COMPILER_GCC 1
|
||||
#define COMPILER_CLANG 0
|
||||
#else
|
||||
#error "Unknown compiler"
|
||||
#endif
|
||||
|
||||
// warning guards for various compilers
|
||||
#if defined(__clang__)
|
||||
#define BEGIN_EXTERNAL_HEADERS \
|
||||
@@ -55,4 +71,7 @@ namespace platform {
|
||||
void showMessageDialog(const std::string& title, const std::string& message);
|
||||
|
||||
void setThreadName(const std::string& threadName);
|
||||
|
||||
// utf8 stuff for imgui -> overlay -> os interop
|
||||
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
#include "platform.h"
|
||||
|
||||
#if OS_LINUX
|
||||
#include "log.h"
|
||||
#include "constants.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
namespace platform {
|
||||
constexpr int INVALID_FD = -1;
|
||||
|
||||
std::filesystem::path getUserConfigDir() {
|
||||
// based on XDG base dir spec for XDG_DATA_HOME
|
||||
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
|
||||
const char* szXdgConfigHome = getenv("XDG_DATA_HOME");
|
||||
|
||||
if (szXdgConfigHome != nullptr && szXdgConfigHome[0] != '\0') {
|
||||
return std::filesystem::path(szXdgConfigHome);
|
||||
}
|
||||
|
||||
szXdgConfigHome = getenv("HOME");
|
||||
if (szXdgConfigHome != nullptr && szXdgConfigHome[0] != '\0') {
|
||||
return std::filesystem::path(szXdgConfigHome) / ".local" / "share";
|
||||
}
|
||||
|
||||
struct passwd* user_db_entry = getpwuid(getuid());
|
||||
if (user_db_entry) {
|
||||
szXdgConfigHome = user_db_entry->pw_dir;
|
||||
}
|
||||
if (szXdgConfigHome != nullptr && szXdgConfigHome[0] != '\0') {
|
||||
return std::filesystem::path(szXdgConfigHome) / ".local" / "share";
|
||||
}
|
||||
|
||||
return std::filesystem::path();
|
||||
}
|
||||
|
||||
std::filesystem::path getRuntimeDir() {
|
||||
// based on XDG base dir spec for XDG_RUNTIME_DIR
|
||||
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
|
||||
const char* szXdgRuntimeDir = getenv("XDG_RUNTIME_DIR");
|
||||
if (szXdgRuntimeDir != nullptr && szXdgRuntimeDir[0] != '\0') {
|
||||
return std::filesystem::path(szXdgRuntimeDir);
|
||||
}
|
||||
|
||||
LOG_WARN("XDG_RUNTIME_DIR is not set, falling back to /tmp/spacecalibrator-runtime-{}", getuid());
|
||||
|
||||
std::filesystem::path fallback = std::filesystem::path("/tmp") / ("spacecalibrator-runtime-" + std::to_string(getuid()));
|
||||
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(fallback, ec);
|
||||
if (ec) {
|
||||
LOG_ERROR("Failed to create runtime dir fallback {}: {}", fallback.string(), ec.message());
|
||||
return std::filesystem::path();
|
||||
}
|
||||
|
||||
if (chmod(fallback.c_str(), 0700) != 0) {
|
||||
LOG_ERROR("Failed to set permissions on runtime dir fallback {}: {}", fallback.string(), strerror(errno));
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
std::filesystem::path getExeDir() {
|
||||
std::error_code ec;
|
||||
std::filesystem::path exePath = std::filesystem::canonical("/proc/self/exe", ec);
|
||||
if (ec) {
|
||||
return std::filesystem::path();
|
||||
}
|
||||
return exePath;
|
||||
}
|
||||
|
||||
std::string getEnvVariable(const std::string& szEnvVarName) {
|
||||
const char* szEnvVar = std::getenv(szEnvVarName.c_str());
|
||||
return szEnvVar ? std::string(szEnvVar) : "";
|
||||
}
|
||||
|
||||
constexpr const char* s_STEAM_MUTEX_KEY = "/MUTEX__SpaceCalibrator_Steam.lock";
|
||||
int s_hSteamMutex = INVALID_FD; // flock on linux
|
||||
bool s_isGitHubVersionInstalled = false;
|
||||
|
||||
bool isAnotherInstanceRunning(bool& bIsRunningViaSteam) {
|
||||
bIsRunningViaSteam = false;
|
||||
std::string szSteamAppIdEnv = getEnvVariable("SteamAppId");
|
||||
if (spacecal::c_SPACE_CALIBRATOR_STEAM_APP_ID == szSteamAppIdEnv ||
|
||||
spacecal::c_STEAMVR_STEAM_APP_ID == szSteamAppIdEnv) {
|
||||
// We got launched via the Steam client UI.
|
||||
bIsRunningViaSteam = true;
|
||||
|
||||
std::filesystem::path szRuntimeDir = getRuntimeDir();
|
||||
std::string szLockPath = (szRuntimeDir / "spacecalibrator_steam.lock").string();
|
||||
|
||||
s_hSteamMutex = open(szLockPath.c_str(), O_CREAT | O_RDWR, 0666);
|
||||
if (s_hSteamMutex == INVALID_FD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (flock(s_hSteamMutex, LOCK_EX | LOCK_NB) == INVALID_FD) {
|
||||
if (errno == EWOULDBLOCK) {
|
||||
close(s_hSteamMutex);
|
||||
s_hSteamMutex = INVALID_FD;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
void shutdownCurrentInstance() {
|
||||
if (s_hSteamMutex != INVALID_FD) {
|
||||
flock(s_hSteamMutex, LOCK_UN);
|
||||
close(s_hSteamMutex);
|
||||
s_hSteamMutex = INVALID_FD;
|
||||
}
|
||||
}
|
||||
|
||||
void showMessageDialog(const std::string& title, const std::string& message) {
|
||||
LOG_INFO("displaying dialog [{}]: {}", title, message);
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == 0) {
|
||||
// child process
|
||||
|
||||
// redirect stderr to /dev/null to keep the console clean if tools are missing
|
||||
int nullFd = open("/dev/null", O_WRONLY);
|
||||
dup2(nullFd, STDERR_FILENO);
|
||||
close(nullFd);
|
||||
|
||||
// try invoking cli tools which provide a gui
|
||||
// order of choice -> KDE -> GNOME -> notification
|
||||
char* kdialogArgs[] = {
|
||||
(char*)"kdialog",
|
||||
(char*)"--title", (char*)title.c_str(),
|
||||
(char*)"--error", (char*)message.c_str(),
|
||||
nullptr
|
||||
};
|
||||
execvp(kdialogArgs[0], kdialogArgs);
|
||||
|
||||
char* zenityArgs[] = {
|
||||
(char*)"zenity",
|
||||
(char*)"--error",
|
||||
(char*)"--title", (char*)title.c_str(),
|
||||
(char*)"--text", (char*)message.c_str(),
|
||||
(char*)"--width=300",
|
||||
nullptr
|
||||
};
|
||||
execvp(zenityArgs[0], zenityArgs);
|
||||
|
||||
char* notifySendArgs[] = {
|
||||
(char*)"notify-send",
|
||||
(char*)title.c_str(),
|
||||
(char*)message.c_str(),
|
||||
nullptr
|
||||
};
|
||||
execvp(notifySendArgs[0], notifySendArgs);
|
||||
|
||||
// terminate if we failed to switch to any of the above tools
|
||||
_exit(1);
|
||||
}
|
||||
else if (pid > 0) {
|
||||
// parent process - wait for the user to dismiss the dialog
|
||||
int status = 0;
|
||||
waitpid(pid, &status, 0);
|
||||
} else {
|
||||
// fork failed
|
||||
LOG_CRITICAL("Failed to fork process for message dialog.");
|
||||
}
|
||||
}
|
||||
|
||||
void setThreadName(const std::string& threadName) {
|
||||
// thread name has max 16 chars
|
||||
// https://man7.org/linux/man-pages/man3/pthread_setname_np.3.html
|
||||
std::string truncatedName = threadName.substr(0, 15);
|
||||
pthread_setname_np(pthread_self(), truncatedName.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <inttypes.h>
|
||||
|
||||
#if !defined(_OPENVR_API)
|
||||
|
||||
+37
-14
@@ -13,10 +13,12 @@ set(TARGET_NAME 01spacecalibrator)
|
||||
# This is the name that the binary will be called (driver_01spacecalibrator)
|
||||
set(DRIVER_NAME "driver_${TARGET_NAME}")
|
||||
|
||||
foreach(config_type RELEASE RELWITHDEBINFO MINSIZEREL)
|
||||
set(CMAKE_CXX_FLAGS_${config_type} "${CMAKE_CXX_FLAGS_${config_type}} /Ob2 /Zc:inline")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_${config_type} "${CMAKE_SHARED_LINKER_FLAGS_${config_type}} /LTCG /OPT:REF /OPT:ICF")
|
||||
endforeach()
|
||||
if (WIN32)
|
||||
foreach(config_type RELEASE RELWITHDEBINFO MINSIZEREL)
|
||||
set(CMAKE_CXX_FLAGS_${config_type} "${CMAKE_CXX_FLAGS_${config_type}} /Ob2 /Zc:inline")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_${config_type} "${CMAKE_SHARED_LINKER_FLAGS_${config_type}} /LTCG /OPT:REF /OPT:ICF")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
function(GroupSourcesByFolder target)
|
||||
set(SOURCE_GROUP_DELIMITER "/")
|
||||
@@ -59,7 +61,14 @@ message(STATUS "Compilation set for ${PLATFORM}bits architectures.")
|
||||
# OpenVR compatibility checking
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
add_definitions(-DLINUX -DPOSIX)
|
||||
set(ARCH_TARGET linux64)
|
||||
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
|
||||
set(ARCH_TARGET linux_arm64)
|
||||
add_definitions(-DLINUXARM64)
|
||||
else()
|
||||
set(ARCH_TARGET linux64)
|
||||
add_definitions(-DLINUX64)
|
||||
endif()
|
||||
|
||||
if (${PLATFORM} MATCHES 32)
|
||||
message(WARNING "OpenVR x86 binaries not provided on GNU/Linux.")
|
||||
@@ -103,6 +112,7 @@ foreach(SOURCE IN ITEMS ${SOURCES_API})
|
||||
endforeach()
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_BINARY_DIR}/${DRIVER_NAME}/bin/${ARCH_TARGET}>)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY $<1:${CMAKE_BINARY_DIR}/${DRIVER_NAME}/bin/${ARCH_TARGET}>)
|
||||
|
||||
add_library(SpaceCalibratorDriver SHARED ${SOURCES_API} ${SOURCES_HEADERS})
|
||||
GroupSourcesByFolder(SpaceCalibratorDriver)
|
||||
@@ -114,7 +124,6 @@ target_include_directories(SpaceCalibratorDriver
|
||||
PRIVATE ${OPENVR_LIB_DIR}
|
||||
PUBLIC ${CMAKE_SOURCE_DIR}/vendor
|
||||
PUBLIC ${CMAKE_SOURCE_DIR}/vendor/openvr/headers
|
||||
PUBLIC ${CMAKE_SOURCE_DIR}/vendor/minhook/include
|
||||
PUBLIC ${CMAKE_SOURCE_DIR}/vendor/quill/include
|
||||
PUBLIC ${CMAKE_SOURCE_DIR}/vendor/fmt/include
|
||||
PUBLIC ${CMAKE_SOURCE_DIR}/vendor/glaze/include
|
||||
@@ -123,26 +132,40 @@ target_include_directories(SpaceCalibratorDriver
|
||||
target_link_libraries(SpaceCalibratorDriver
|
||||
PRIVATE SpaceCalibratorCommon
|
||||
PRIVATE ${OPENVR_LIBRARIES}
|
||||
PRIVATE minhook
|
||||
PRIVATE fmt
|
||||
PRIVATE quill
|
||||
PRIVATE kernel32 user32 gdi32 winspool comdlg32 advapi32 shell32 ole32 oleaut32 uuid odbc32 odbccp32
|
||||
)
|
||||
|
||||
target_compile_definitions(SpaceCalibratorDriver
|
||||
PRIVATE $<$<CONFIG:Debug>:_DEBUG>
|
||||
PRIVATE $<$<CONFIG:Release>:NDEBUG>
|
||||
PRIVATE _WINDOWS
|
||||
PRIVATE _USRDLL
|
||||
PRIVATE NOMINMAX
|
||||
PRIVATE UNICODE
|
||||
PRIVATE EIGEN_HAS_STD_RESULT_OF=0
|
||||
PRIVATE _CRT_SECURE_NO_WARNINGS
|
||||
PRIVATE IS_DRIVER
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
target_include_directories(SpaceCalibratorDriver
|
||||
PUBLIC ${CMAKE_SOURCE_DIR}/vendor/minhook/include)
|
||||
|
||||
target_link_libraries(SpaceCalibratorDriver
|
||||
PRIVATE minhook
|
||||
PRIVATE kernel32 user32 gdi32 winspool comdlg32 advapi32 shell32 ole32 oleaut32 uuid odbc32 odbccp32
|
||||
)
|
||||
|
||||
target_compile_definitions(SpaceCalibratorDriver
|
||||
PRIVATE _WINDOWS
|
||||
PRIVATE _USRDLL
|
||||
PRIVATE NOMINMAX
|
||||
PRIVATE UNICODE
|
||||
PRIVATE _CRT_SECURE_NO_WARNINGS
|
||||
)
|
||||
endif()
|
||||
|
||||
set_target_properties(SpaceCalibratorDriver PROPERTIES OUTPUT_NAME ${DRIVER_NAME})
|
||||
|
||||
set_target_properties(SpaceCalibratorOverlay PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS")
|
||||
if (WIN32)
|
||||
set_target_properties(SpaceCalibratorOverlay PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS")
|
||||
endif()
|
||||
|
||||
# Copy driver assets to output folder
|
||||
add_custom_command(
|
||||
|
||||
+66
-4
@@ -1,10 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <MinHook.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "log.h"
|
||||
#include "platform.h"
|
||||
#if OS_WINDOWS
|
||||
#include <MinHook.h>
|
||||
#elif OS_LINUX
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define ALIGN_TO_PAGE(addr, pageSize) \
|
||||
((void*)((uintptr_t)(addr) & ~(uintptr_t)((pageSize) - 1)))
|
||||
#endif
|
||||
|
||||
namespace hooking {
|
||||
class IHook
|
||||
@@ -38,6 +47,7 @@ namespace hooking {
|
||||
// To access the vtable, we simply dereference the object.
|
||||
void** vtable = *((void***)object);
|
||||
|
||||
#if OS_WINDOWS
|
||||
// The vtable itself is an array of pointers to member functions,
|
||||
// in the order they were declared in.
|
||||
targetFunc = vtable[vtableOffset];
|
||||
@@ -45,34 +55,86 @@ namespace hooking {
|
||||
auto err = MH_CreateHook(targetFunc, detourFunction, (LPVOID*)&originalFunc);
|
||||
if (err != MH_OK)
|
||||
{
|
||||
LOG_HOOKING_ERROR("Failed to create hook for {}, error: {}", name.c_str(), MH_StatusToString(err));
|
||||
LOG_HOOKING_ERROR("Failed to create hook for {}, error: {}", name, MH_StatusToString(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
err = MH_EnableHook(targetFunc);
|
||||
if (err != MH_OK)
|
||||
{
|
||||
LOG_HOOKING_ERROR("Failed to enable hook for {}, error: {}", name.c_str(), MH_StatusToString(err));
|
||||
LOG_HOOKING_ERROR("Failed to enable hook for {}, error: {}", name, MH_StatusToString(err));
|
||||
MH_RemoveHook(targetFunc);
|
||||
return false;
|
||||
}
|
||||
#elif OS_LINUX
|
||||
targetFunc = (void**)&vtable[vtableOffset];
|
||||
originalFunc = (FuncType)vtable[vtableOffset];
|
||||
|
||||
LOG_HOOKING_INFO("Enabled hook for {}", name.c_str());
|
||||
long pageSize = sysconf(_SC_PAGESIZE);
|
||||
void* pageStart = ALIGN_TO_PAGE(targetFunc, pageSize);
|
||||
void* pageEnd = ALIGN_TO_PAGE((uintptr_t)targetFunc + sizeof(void*) - 1, pageSize);
|
||||
size_t length = (uintptr_t)pageEnd - (uintptr_t)pageStart + pageSize;
|
||||
|
||||
if (mprotect(pageStart, length, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
|
||||
LOG_HOOKING_ERROR("Failed to make vtable writable for {}: {}", name, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
*targetFunc = detourFunction;
|
||||
|
||||
#if COMPILER_GCC || COMPILER_CLANG
|
||||
// https://blog.pathogenstudios.com/rolling-your-own-breakpoints-without-0xcc/
|
||||
// https://github.com/ridpath/gamehacking-cheatsheet#apple-silicon-rosetta-2-game-reversing
|
||||
// flush cache -> required for aarch64
|
||||
// emits no-op on amd64 (done automatically by hardware on amd64 so no need)
|
||||
__builtin___clear_cache(
|
||||
reinterpret_cast<char*>(targetFunc),
|
||||
reinterpret_cast<char*>(targetFunc) + sizeof(void*)
|
||||
);
|
||||
#endif // COMPILER_GCC || COMPILER_CLANG
|
||||
|
||||
if (mprotect(pageStart, length, PROT_READ | PROT_EXEC) != 0) {
|
||||
LOG_HOOKING_ERROR("Failed to restore vtable protection for {}: {}", name, strerror(errno));
|
||||
}
|
||||
#endif // OS_LINUX
|
||||
|
||||
LOG_HOOKING_INFO("Enabled hook for {}", name);
|
||||
enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Destroy()
|
||||
{
|
||||
#if OS_WINDOWS
|
||||
if (enabled)
|
||||
{
|
||||
MH_RemoveHook(targetFunc);
|
||||
enabled = false;
|
||||
}
|
||||
#elif OS_LINUX
|
||||
if (enabled && targetFunc)
|
||||
{
|
||||
long pageSize = sysconf(_SC_PAGESIZE);
|
||||
void* pageStart = ALIGN_TO_PAGE(targetFunc, pageSize);
|
||||
void* pageEnd = ALIGN_TO_PAGE((uintptr_t)targetFunc + sizeof(void*) - 1, pageSize);
|
||||
size_t length = (uintptr_t)pageEnd - (uintptr_t)pageStart + pageSize;
|
||||
|
||||
if (mprotect(pageStart, length, PROT_READ | PROT_WRITE | PROT_EXEC) == 0) {
|
||||
*targetFunc = (void*)originalFunc;
|
||||
mprotect(pageStart, length, PROT_READ | PROT_EXEC);
|
||||
}
|
||||
enabled = false;
|
||||
}
|
||||
#endif // OS_LINUX
|
||||
}
|
||||
|
||||
private:
|
||||
bool enabled = false;
|
||||
#if OS_WINDOWS
|
||||
void* targetFunc = nullptr;
|
||||
#elif OS_LINUX
|
||||
void** targetFunc = nullptr;
|
||||
#undef ALIGN_TO_PAGE
|
||||
#endif
|
||||
};
|
||||
}
|
||||
@@ -64,6 +64,7 @@ namespace hooking {
|
||||
void InjectHooks(spacecal::ServerTrackedDeviceProvider* driver, vr::IVRDriverContext* pDriverContext) {
|
||||
g_mainDriver = driver;
|
||||
|
||||
#if OS_WINDOWS
|
||||
MH_STATUS err = MH_Initialize();
|
||||
if (err == MH_OK) {
|
||||
GetGenericInterfaceHook.CreateHookInObjectVTable(pDriverContext, 0, reinterpret_cast<void*>(&DetourGetGenericInterface));
|
||||
@@ -74,11 +75,21 @@ namespace hooking {
|
||||
} else {
|
||||
LOG_HOOKING_ERROR("MH_Initialize error: {}", MH_StatusToString(err));
|
||||
}
|
||||
#elif OS_LINUX
|
||||
if (GetGenericInterfaceHook.CreateHookInObjectVTable(pDriverContext, 0, reinterpret_cast<void*>(&DetourGetGenericInterface))) {
|
||||
IHook::Register(&GetGenericInterfaceHook);
|
||||
LOG_HOOKING_INFO("Space Calibrator hooked into OpenVR PoseUpdate successfully");
|
||||
} else {
|
||||
LOG_HOOKING_ERROR("Failed to hook into OpenVR PoseUpdate.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DisableHooks() {
|
||||
IHook::DestroyAll();
|
||||
#if OS_WINDOWS
|
||||
MH_Uninitialize();
|
||||
#endif
|
||||
LOG_HOOKING_INFO("Removed all hooks successfully");
|
||||
}
|
||||
}
|
||||
@@ -120,7 +120,7 @@ namespace ipc {
|
||||
.szSharedMemoryName = protocol::k_szIpcIdentifier,
|
||||
.dwSharedBufferSizeBytes = protocol::k_unSharedMemoryElementSize,
|
||||
.aFunctions = m_funcs,
|
||||
.dwFunctionCount = _countof(m_funcs),
|
||||
.dwFunctionCount = IPC_COUNT_OF(m_funcs),
|
||||
.aOperations = nullptr,
|
||||
.dwOperationCount = 0,
|
||||
.userData = this,
|
||||
|
||||
+4
-2
@@ -1,10 +1,12 @@
|
||||
#include <stdio.h>
|
||||
#include <cstring>
|
||||
#include "tracked_device_provider.h"
|
||||
#include "platform.h"
|
||||
|
||||
#if defined( _WIN32 )
|
||||
#if OS_WINDOWS
|
||||
#define SPACECALIBRATORDRIVER_EXPORT extern "C" __declspec( dllexport )
|
||||
#define SPACECALIBRATORDRIVER_IMPORT extern "C" __declspec( dllimport )
|
||||
#elif defined( __GNUC__ ) || defined( COMPILER_GCC ) || defined( __APPLE__ )
|
||||
#elif COMPILER_GCC || OS_LINUX
|
||||
#define SPACECALIBRATORDRIVER_EXPORT extern "C" __attribute__( ( visibility( "default" ) ) )
|
||||
#define SPACECALIBRATORDRIVER_IMPORT extern "C"
|
||||
#else
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "interface_hook_injector.h"
|
||||
#include "vrmath.h"
|
||||
#include "virtual_desktop.h"
|
||||
#include <math.h>
|
||||
#include <Eigen/Dense>
|
||||
#include <openvr_driver.h>
|
||||
|
||||
|
||||
+92
-20
@@ -3,10 +3,12 @@ cmake_minimum_required (VERSION 3.8)
|
||||
project(SpaceCalibratorOverlay CXX)
|
||||
message("SpaceCalibrator - Overlay")
|
||||
|
||||
foreach(config_type RELEASE RELWITHDEBINFO MINSIZEREL)
|
||||
set(CMAKE_CXX_FLAGS_${config_type} "${CMAKE_CXX_FLAGS_${config_type}} /Ob2 /Zc:inline")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_${config_type} "${CMAKE_SHARED_LINKER_FLAGS_${config_type}} /LTCG /OPT:REF /OPT:ICF")
|
||||
endforeach()
|
||||
if (WIN32)
|
||||
foreach(config_type RELEASE RELWITHDEBINFO MINSIZEREL)
|
||||
set(CMAKE_CXX_FLAGS_${config_type} "${CMAKE_CXX_FLAGS_${config_type}} /Ob2 /Zc:inline")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_${config_type} "${CMAKE_SHARED_LINKER_FLAGS_${config_type}} /LTCG /OPT:REF /OPT:ICF")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
function(GroupSourcesByFolder target)
|
||||
set(SOURCE_GROUP_DELIMITER "/")
|
||||
@@ -33,6 +35,60 @@ function(GroupSourcesByFolder target)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
set(OPENVR_LIB_DIR ${CMAKE_SOURCE_DIR}/vendor/openvr)
|
||||
|
||||
# If not set, determine the platform architecture
|
||||
if (NOT PLATFORM)
|
||||
if (CMAKE_SIZEOF_VOID_P MATCHES 8)
|
||||
set(PLATFORM 64)
|
||||
else ()
|
||||
set(PLATFORM 32)
|
||||
endif ()
|
||||
endif ()
|
||||
message(STATUS "Compilation set for ${PLATFORM}bits architectures.")
|
||||
|
||||
# OpenVR compatibility checking
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
add_definitions(-DLINUX -DPOSIX)
|
||||
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
|
||||
set(ARCH_TARGET linux_arm64)
|
||||
add_definitions(-DLINUXARM64)
|
||||
else()
|
||||
set(ARCH_TARGET linux64)
|
||||
add_definitions(-DLINUX64)
|
||||
endif()
|
||||
|
||||
if (${PLATFORM} MATCHES 32)
|
||||
message(WARNING "OpenVR x86 binaries not provided on GNU/Linux.")
|
||||
endif ()
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(CMAKE_MACOSX_RPATH 0)
|
||||
add_definitions(-DOSX -DPOSIX)
|
||||
set(ARCH_TARGET osx32)
|
||||
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
add_definitions(-D_WIN32)
|
||||
set(ARCH_TARGET win${PLATFORM})
|
||||
|
||||
# Binaries path for thirdparties are not generics so we try to guess their suffixes.
|
||||
set(WINDOWS_PATH_SUFFIXES win${PLATFORM} Win${PLATFORM} x${PLATFORM})
|
||||
endif ()
|
||||
|
||||
find_library(OPENVR_LIBRARIES
|
||||
NAMES
|
||||
openvr_api
|
||||
PATHS
|
||||
${OPENVR_LIB_DIR}/bin
|
||||
${OPENVR_LIB_DIR}/lib
|
||||
PATH_SUFFIXES
|
||||
osx${PLATFORM}
|
||||
linux${PLATFORM}
|
||||
win${PLATFORM}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
@@ -83,28 +139,33 @@ target_include_directories(SpaceCalibratorOverlay
|
||||
|
||||
target_link_libraries(SpaceCalibratorOverlay
|
||||
PRIVATE SpaceCalibratorCommon
|
||||
PRIVATE opengl32.lib
|
||||
PRIVATE dwmapi.lib
|
||||
PRIVATE imgui
|
||||
PRIVATE glad
|
||||
PRIVATE glfw
|
||||
PRIVATE fmt
|
||||
PRIVATE quill
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/vendor/openvr/lib/win64/openvr_api.lib)
|
||||
PRIVATE ${OPENVR_LIBRARIES})
|
||||
|
||||
target_compile_definitions(SpaceCalibratorOverlay
|
||||
PRIVATE NOMINMAX
|
||||
PRIVATE UNICODE
|
||||
PRIVATE _CRT_SECURE_NO_WARNINGS
|
||||
PRIVATE IMGUI_DEFINE_MATH_OPERATORS
|
||||
PRIVATE IS_OVERLAY
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(SpaceCalibratorOverlay
|
||||
PRIVATE opengl32.lib
|
||||
PRIVATE dwmapi.lib)
|
||||
|
||||
target_compile_definitions(SpaceCalibratorOverlay
|
||||
PRIVATE NOMINMAX
|
||||
PRIVATE UNICODE
|
||||
PRIVATE _CRT_SECURE_NO_WARNINGS
|
||||
)
|
||||
endif()
|
||||
|
||||
# Object files are too big with spacecal sooooo
|
||||
if (MSVC)
|
||||
target_compile_options(SpaceCalibratorOverlay PRIVATE /bigobj)
|
||||
else ()
|
||||
target_compile_options(SpaceCalibratorOverlay PRIVATE -Wa,-mbig-obj)
|
||||
endif ()
|
||||
|
||||
set(OVERLAY_BIN_DIR "$<TARGET_FILE_DIR:SpaceCalibratorOverlay>")
|
||||
@@ -150,12 +211,21 @@ add_custom_command(
|
||||
)
|
||||
|
||||
# Copy openvr_api.dll
|
||||
add_custom_command(
|
||||
TARGET SpaceCalibratorOverlay POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_SOURCE_DIR}/vendor/openvr/bin/win64/openvr_api.dll
|
||||
${OVERLAY_BIN_DIR}/openvr_api.dll
|
||||
)
|
||||
if (WIN32)
|
||||
add_custom_command(
|
||||
TARGET SpaceCalibratorOverlay POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_SOURCE_DIR}/vendor/openvr/bin/${ARCH_TARGET}/openvr_api.dll
|
||||
${OVERLAY_BIN_DIR}/openvr_api.dll
|
||||
)
|
||||
else()
|
||||
add_custom_command(
|
||||
TARGET SpaceCalibratorOverlay POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_SOURCE_DIR}/vendor/openvr/bin/${ARCH_TARGET}/libopenvr_api.so
|
||||
${OVERLAY_BIN_DIR}/libopenvr_api.so
|
||||
)
|
||||
endif()
|
||||
|
||||
# Copy assets to output folder
|
||||
add_custom_command(
|
||||
@@ -168,6 +238,8 @@ add_custom_command(
|
||||
)
|
||||
|
||||
# Set as startup project
|
||||
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT SpaceCalibratorOverlay)
|
||||
set_property(TARGET SpaceCalibratorOverlay PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${OVERLAY_BIN_DIR}")
|
||||
if (WIN32)
|
||||
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT SpaceCalibratorOverlay)
|
||||
set_property(TARGET SpaceCalibratorOverlay PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${OVERLAY_BIN_DIR}")
|
||||
endif()
|
||||
set_target_properties(SpaceCalibratorOverlay PROPERTIES OUTPUT_NAME "SpaceCalibrator")
|
||||
@@ -32,7 +32,7 @@ namespace ipc {
|
||||
.szSharedMemoryName = protocol::k_szIpcIdentifier,
|
||||
.dwSharedBufferSizeBytes = protocol::k_unSharedMemoryElementSize,
|
||||
.aFunctions = m_funcs,
|
||||
.dwFunctionCount = _countof(m_funcs),
|
||||
.dwFunctionCount = IPC_COUNT_OF(m_funcs),
|
||||
.aOperations = nullptr,
|
||||
.dwOperationCount = 0,
|
||||
.userData = this,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "localisation.h"
|
||||
|
||||
#if OS_WINDOWS
|
||||
#include "log.h"
|
||||
|
||||
#include <unordered_map>
|
||||
@@ -384,4 +385,5 @@ namespace spacecal {
|
||||
|
||||
return estimatedLocale;
|
||||
}
|
||||
} // namespace localisation
|
||||
} // namespace localisation
|
||||
#endif // OS_WINDOWS
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "platform.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
BEGIN_EXTERNAL_HEADERS
|
||||
#include <filesystem>
|
||||
#include <glaze/glaze.hpp>
|
||||
@@ -116,9 +118,8 @@ namespace spacecal {
|
||||
auto rootDir = util::getSpaceCalibratorLangsDir();
|
||||
std::string langPath = (rootDir / (getLocaleAsRegionString(locale) + ".json")).string();
|
||||
|
||||
FILE* localeFile = nullptr;
|
||||
errno_t fileErr = fopen_s(&localeFile, langPath.c_str(), "rb");
|
||||
switch (fileErr) {
|
||||
FILE* localeFile = fopen(langPath.c_str(), "rb");
|
||||
switch (errno) {
|
||||
case 0: // OK
|
||||
break;
|
||||
case ENOENT:
|
||||
@@ -135,7 +136,7 @@ namespace spacecal {
|
||||
LOG_WARNING("The locale file \"{0}\" could not be loaded as it was too large.", langPath);
|
||||
return false;
|
||||
default:
|
||||
LOG_WARNING("The locale file \"{0}\" could not be loaded due to an unknown error ({1}).", langPath, fileErr);
|
||||
LOG_WARNING("The locale file \"{0}\" could not be loaded due to an unknown error ({1}).", langPath, errno);
|
||||
return false;
|
||||
}
|
||||
if (localeFile) {
|
||||
@@ -202,9 +203,8 @@ namespace spacecal {
|
||||
// fallback to the loaded locale string
|
||||
m_nativeLanguageNames[locale] = getString(expectedKey);
|
||||
|
||||
FILE* file = nullptr;
|
||||
errno_t fileErr = fopen_s(&file, langPath.c_str(), "rb");
|
||||
switch (fileErr) {
|
||||
FILE* file = fopen(langPath.c_str(), "rb");
|
||||
switch (errno) {
|
||||
case 0: // OK
|
||||
break;
|
||||
case ENOENT:
|
||||
@@ -221,7 +221,7 @@ namespace spacecal {
|
||||
LOG_WARNING("The locale file \"{0}\" could not be loaded as it was too large.", langPath);
|
||||
return;
|
||||
default:
|
||||
LOG_WARNING("The locale file \"{0}\" could not be loaded due to an unknown error ({1}).", langPath, fileErr);
|
||||
LOG_WARNING("The locale file \"{0}\" could not be loaded due to an unknown error ({1}).", langPath, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -1,5 +1,4 @@
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include "util.h"
|
||||
#include "window.h"
|
||||
#include "platform.h"
|
||||
@@ -8,13 +7,24 @@
|
||||
#include "localisation.h"
|
||||
#include "vr_core.h"
|
||||
#include "log.h"
|
||||
#if OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if OS_WINDOWS
|
||||
// http://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/OptimusRenderingPolicies.pdf
|
||||
extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||
// http://developer.amd.com/community/blog/2015/10/02/amd-enduro-system-for-developers/
|
||||
extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001;
|
||||
#endif
|
||||
|
||||
#if OS_WINDOWS
|
||||
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
|
||||
#elif OS_LINUX
|
||||
int main(int argc, char* argv[])
|
||||
#else
|
||||
#error "Unsupported platform!"
|
||||
#endif
|
||||
{
|
||||
// Space Calibrator has to be single instance to work well with Steam
|
||||
bool bIsRunningViaSteam = false;
|
||||
|
||||
+14
-2
@@ -1,12 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "platform.h"
|
||||
#include "ipc_client.h"
|
||||
#include "calibration.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
#if OS_WINDOWS
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#elif OS_LINUX
|
||||
#define GLFW_EXPOSE_NATIVE_WAYLAND
|
||||
#define GLFW_EXPOSE_NATIVE_X11
|
||||
#endif
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GLFW/glfw3native.h>
|
||||
|
||||
#include "ipc_client.h"
|
||||
#include "calibration.h"
|
||||
#if OS_LINUX
|
||||
#ifdef None
|
||||
#undef None
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace spacecal {
|
||||
// handles window creation, setting the icon, and initialising a renderer for UI, also handles connecting it to SteamVR as an overlay
|
||||
|
||||
Vendored
+13
-9
@@ -5,8 +5,10 @@ project("vendor")
|
||||
# Includes all 3rd party libraries here
|
||||
|
||||
# Minhook library
|
||||
message("Adding minhook...")
|
||||
add_subdirectory ("minhook")
|
||||
if (WIN32)
|
||||
message("Adding minhook...")
|
||||
add_subdirectory ("minhook")
|
||||
endif()
|
||||
|
||||
# glad
|
||||
message("Adding glad...")
|
||||
@@ -53,11 +55,13 @@ message ("Adding glaze...")
|
||||
add_subdirectory(glaze)
|
||||
|
||||
# Assign solution dirs
|
||||
set_property(TARGET glfw PROPERTY FOLDER "vendor/glfw")
|
||||
set_property(TARGET update_mappings PROPERTY FOLDER "vendor/glfw")
|
||||
if (WIN32)
|
||||
set_property(TARGET glfw PROPERTY FOLDER "vendor/glfw")
|
||||
set_property(TARGET update_mappings PROPERTY FOLDER "vendor/glfw")
|
||||
|
||||
set_property(TARGET minhook PROPERTY FOLDER "vendor")
|
||||
set_property(TARGET imgui PROPERTY FOLDER "vendor")
|
||||
set_property(TARGET fmt PROPERTY FOLDER "vendor")
|
||||
set_property(TARGET quill PROPERTY FOLDER "vendor")
|
||||
set_property(TARGET glad PROPERTY FOLDER "vendor")
|
||||
set_property(TARGET minhook PROPERTY FOLDER "vendor")
|
||||
set_property(TARGET imgui PROPERTY FOLDER "vendor")
|
||||
set_property(TARGET fmt PROPERTY FOLDER "vendor")
|
||||
set_property(TARGET quill PROPERTY FOLDER "vendor")
|
||||
set_property(TARGET glad PROPERTY FOLDER "vendor")
|
||||
endif()
|
||||
Vendored
+251
-26
@@ -43,6 +43,8 @@
|
||||
// o-----------------o
|
||||
//
|
||||
|
||||
#define IPC_COUNT_OF(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
typedef void* IpcHandle_t;
|
||||
static const IpcHandle_t k_hInvalidIpcHandle = ((IpcHandle_t)(-1));
|
||||
typedef uint64_t IpcCommandType_t;
|
||||
@@ -89,7 +91,20 @@ bool ipc_client_read_shared_memory(IpcHandle_t hIpcClient, IpcOperation_t ipcOpe
|
||||
|
||||
#ifdef IPC_IMPLEMENTATION
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define IPC_OS_WIN32 1
|
||||
#else
|
||||
#define IPC_OS_WIN32 0
|
||||
#endif
|
||||
|
||||
#if defined(__gnu_linux__) || defined(__linux__)
|
||||
#define IPC_OS_LINUX 1
|
||||
#else
|
||||
#define IPC_OS_LINUX 0
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@@ -100,7 +115,7 @@ bool ipc_client_read_shared_memory(IpcHandle_t hIpcClient, IpcOperation_t ipcOpe
|
||||
#define IPC_FUNCTION_ARGS_TOTAL_SIZE (1024*16)
|
||||
#endif // IPC_FUNCTION_ARGS_TOTAL_SIZE
|
||||
|
||||
#if _WIN32
|
||||
#if IPC_OS_WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif // WIN32_LEAN_AND_MEAN
|
||||
@@ -117,6 +132,11 @@ bool ipc_client_read_shared_memory(IpcHandle_t hIpcClient, IpcOperation_t ipcOpe
|
||||
#define NOMINMAX
|
||||
#endif // NOMINMAX
|
||||
#include <windows.h>
|
||||
#elif IPC_OS_LINUX
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <semaphore.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
struct __internal__IpcFunction_t {
|
||||
@@ -139,10 +159,14 @@ struct __internal__IpcHandle_t {
|
||||
void* userData = nullptr;
|
||||
};
|
||||
|
||||
#if IPC_OS_LINUX
|
||||
#define IPC_S_RW_ALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
|
||||
#endif
|
||||
|
||||
void __internal_ipc_server_poll_requests(IpcHandle_t hIpcServer) {
|
||||
__internal__IpcHandle_t* handleInternal = (__internal__IpcHandle_t*)hIpcServer;
|
||||
|
||||
#if _WIN32
|
||||
#if IPC_OS_WIN32
|
||||
while (handleInternal->is_running) {
|
||||
DWORD result = WaitForSingleObject((HANDLE)handleInternal->hNativeEvent, 100);
|
||||
|
||||
@@ -164,6 +188,41 @@ void __internal_ipc_server_poll_requests(IpcHandle_t hIpcServer) {
|
||||
ReleaseMutex((HANDLE)handleInternal->hNativeMutex);
|
||||
}
|
||||
}
|
||||
#elif IPC_OS_LINUX
|
||||
sem_t* semEvt = (sem_t*)handleInternal->hNativeEvent;
|
||||
sem_t* semMtx = (sem_t*)handleInternal->hNativeMutex;
|
||||
|
||||
while (handleInternal->is_running) {
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) == -1) continue;
|
||||
ts.tv_nsec += 100000000; // 100ms
|
||||
if (ts.tv_nsec >= 1000000000) {
|
||||
ts.tv_sec += 1;
|
||||
ts.tv_nsec -= 1000000000;
|
||||
}
|
||||
|
||||
int res = sem_timedwait(semEvt, &ts);
|
||||
if (res == 0) {
|
||||
if (sem_wait(semMtx) == 0) {
|
||||
IpcCommandType_t* cmdType = (IpcCommandType_t*)handleInternal->pSharedMemory;
|
||||
void* pArgs = (void*)((char*)handleInternal->pSharedMemory + sizeof(IpcCommandType_t));
|
||||
|
||||
for (const auto& func : handleInternal->registed_functions) {
|
||||
if (func.unCmdType == *cmdType) {
|
||||
if (func.pfnCallback) {
|
||||
func.pfnCallback(*cmdType, hIpcServer, pArgs, handleInternal->userData);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sem_post(semMtx);
|
||||
}
|
||||
}
|
||||
else if (errno != ETIMEDOUT && errno != EINTR) {
|
||||
handleInternal->is_running = false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
@@ -184,7 +243,7 @@ IpcHandle_t ipc_server_init(IpcCreateArguments_t args) {
|
||||
handleInternal->szSharedMemoryName = args.szSharedMemoryName;
|
||||
size_t totalSharedMemSize = IPC_FUNCTION_ARGS_TOTAL_SIZE + args.dwSharedBufferSizeBytes;
|
||||
|
||||
#if _WIN32
|
||||
#if IPC_OS_WIN32
|
||||
handleInternal->hSharedMemory = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)totalSharedMemSize, args.szSharedMemoryName);
|
||||
if (handleInternal->hSharedMemory == NULL) {
|
||||
free(handleInternal);
|
||||
@@ -207,6 +266,39 @@ IpcHandle_t ipc_server_init(IpcCreateArguments_t args) {
|
||||
ipc_server_shutdown(&hIpcHandle);
|
||||
return k_hInvalidIpcHandle;
|
||||
}
|
||||
#elif IPC_OS_LINUX
|
||||
// shared mem needs a leading / on linux
|
||||
std::string szSharedMemoryPath = (args.szSharedMemoryName[0] == '/') ? args.szSharedMemoryName : "/" + std::string(args.szSharedMemoryName);
|
||||
|
||||
int hSharedMemFd = shm_open(szSharedMemoryPath.c_str(), O_CREAT | O_RDWR, IPC_S_RW_ALL);
|
||||
if (hSharedMemFd == -1) {
|
||||
free(handleInternal);
|
||||
return k_hInvalidIpcHandle;
|
||||
}
|
||||
|
||||
handleInternal->hSharedMemory = (IpcNativeHandle_t)(intptr_t)hSharedMemFd;
|
||||
ftruncate(hSharedMemFd, totalSharedMemSize);
|
||||
|
||||
handleInternal->pSharedMemory = mmap(NULL, totalSharedMemSize, PROT_READ | PROT_WRITE, MAP_SHARED, hSharedMemFd, 0);
|
||||
if (handleInternal->pSharedMemory == MAP_FAILED) {
|
||||
close(hSharedMemFd);
|
||||
free(handleInternal);
|
||||
return k_hInvalidIpcHandle;
|
||||
}
|
||||
|
||||
std::string mutexName = szSharedMemoryPath + "_FUNC_MTX";
|
||||
std::string eventName = szSharedMemoryPath + "_FUNC_EVT";
|
||||
|
||||
handleInternal->hNativeMutex = (IpcNativeHandle_t)sem_open(mutexName.c_str(), O_CREAT, IPC_S_RW_ALL, 1);
|
||||
handleInternal->hNativeEvent = (IpcNativeHandle_t)sem_open(eventName.c_str(), O_CREAT, IPC_S_RW_ALL, 0);
|
||||
if (handleInternal->hNativeMutex == SEM_FAILED || handleInternal->hNativeEvent == SEM_FAILED) {
|
||||
IpcHandle_t hIpcHandle = ((IpcHandle_t)handleInternal);
|
||||
ipc_server_shutdown(&hIpcHandle);
|
||||
return k_hInvalidIpcHandle;
|
||||
}
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < args.dwFunctionCount; ++i) {
|
||||
const IpcFunction_t& reg = args.aFunctions[i];
|
||||
@@ -219,9 +311,6 @@ IpcHandle_t ipc_server_init(IpcCreateArguments_t args) {
|
||||
|
||||
handleInternal->is_running = true;
|
||||
handleInternal->poll_thread = std::thread(__internal_ipc_server_poll_requests, (IpcHandle_t)handleInternal);
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
|
||||
return (IpcHandle_t)handleInternal;
|
||||
}
|
||||
@@ -239,7 +328,7 @@ IpcHandle_t ipc_client_init(IpcCreateArguments_t args) {
|
||||
|
||||
handleInternal->szSharedMemoryName = args.szSharedMemoryName;
|
||||
|
||||
#if _WIN32
|
||||
#if IPC_OS_WIN32
|
||||
handleInternal->hSharedMemory = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, args.szSharedMemoryName);
|
||||
if (handleInternal->hSharedMemory == NULL) {
|
||||
free(handleInternal);
|
||||
@@ -262,6 +351,32 @@ IpcHandle_t ipc_client_init(IpcCreateArguments_t args) {
|
||||
ipc_client_shutdown(&handleFinal);
|
||||
return k_hInvalidIpcHandle;
|
||||
}
|
||||
#elif IPC_OS_LINUX
|
||||
std::string szSharedMemoryPath = (args.szSharedMemoryName[0] == '/') ? args.szSharedMemoryName : "/" + std::string(args.szSharedMemoryName);
|
||||
|
||||
int hSharedMemFd = shm_open(szSharedMemoryPath.c_str(), O_RDWR, IPC_S_RW_ALL);
|
||||
if (hSharedMemFd == -1) {
|
||||
free(handleInternal);
|
||||
return k_hInvalidIpcHandle;
|
||||
}
|
||||
|
||||
handleInternal->hSharedMemory = (IpcNativeHandle_t)(intptr_t)hSharedMemFd;
|
||||
struct stat st = {};
|
||||
fstat(hSharedMemFd, &st);
|
||||
handleInternal->pSharedMemory = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, hSharedMemFd, 0);
|
||||
|
||||
std::string mutexName = szSharedMemoryPath + "_FUNC_MTX";
|
||||
std::string eventName = szSharedMemoryPath + "_FUNC_EVT";
|
||||
handleInternal->hNativeMutex = (IpcNativeHandle_t)sem_open(mutexName.c_str(), 1);
|
||||
handleInternal->hNativeEvent = (IpcNativeHandle_t)sem_open(eventName.c_str(), 0);
|
||||
if (handleInternal->hNativeMutex == SEM_FAILED || handleInternal->hNativeEvent == SEM_FAILED) {
|
||||
IpcHandle_t hIpcHandle = ((IpcHandle_t)handleInternal);
|
||||
ipc_client_shutdown(&hIpcHandle);
|
||||
return k_hInvalidIpcHandle;
|
||||
}
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < args.dwFunctionCount; ++i) {
|
||||
const IpcFunction_t& reg = args.aFunctions[i];
|
||||
@@ -270,9 +385,6 @@ IpcHandle_t ipc_client_init(IpcCreateArguments_t args) {
|
||||
};
|
||||
handleInternal->registed_functions.push_back(func);
|
||||
}
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
|
||||
return (IpcHandle_t)handleInternal;
|
||||
}
|
||||
@@ -281,11 +393,11 @@ bool ipc_server_shutdown(IpcHandle_t* hIpcServer) {
|
||||
if (hIpcServer && *hIpcServer != k_hInvalidIpcHandle) {
|
||||
__internal__IpcHandle_t* handleInternal = (__internal__IpcHandle_t*)*hIpcServer;
|
||||
|
||||
#if _WIN32
|
||||
handleInternal->is_running = false;
|
||||
if (handleInternal->poll_thread.joinable()) {
|
||||
handleInternal->poll_thread.join();
|
||||
}
|
||||
#if IPC_OS_WIN32
|
||||
|
||||
for (size_t i = 0; i < handleInternal->registed_operations.size(); ++i) {
|
||||
if (handleInternal->registed_operations[i].hNativeEvent)
|
||||
@@ -303,6 +415,40 @@ bool ipc_server_shutdown(IpcHandle_t* hIpcServer) {
|
||||
UnmapViewOfFile(handleInternal->pSharedMemory);
|
||||
if (handleInternal->hSharedMemory)
|
||||
CloseHandle(handleInternal->hSharedMemory);
|
||||
#elif IPC_OS_LINUX
|
||||
std::string szSharedMemoryPath = (handleInternal->szSharedMemoryName[0] == '/') ? handleInternal->szSharedMemoryName : "/" + std::string(handleInternal->szSharedMemoryName);
|
||||
|
||||
if ((sem_t*)handleInternal->hNativeMutex != SEM_FAILED) {
|
||||
sem_close((sem_t*)handleInternal->hNativeMutex);
|
||||
sem_unlink((szSharedMemoryPath + "_FUNC_MTX").c_str());
|
||||
}
|
||||
if ((sem_t*)handleInternal->hNativeEvent != SEM_FAILED) {
|
||||
sem_close((sem_t*)handleInternal->hNativeEvent);
|
||||
sem_unlink((szSharedMemoryPath + "_FUNC_EVT").c_str());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < handleInternal->registed_operations.size(); ++i) {
|
||||
IpcOperation_t& op = handleInternal->registed_operations[i];
|
||||
std::string opMutexName = szSharedMemoryPath + "_" + std::string(op.szIdentifier) + "_MTX";
|
||||
std::string opEventName = szSharedMemoryPath + "_" + std::string(op.szIdentifier) + "_EVT";
|
||||
if ((sem_t*)op.hNativeMutex != SEM_FAILED) {
|
||||
sem_close((sem_t*)op.hNativeMutex);
|
||||
sem_unlink(opMutexName.c_str());
|
||||
}
|
||||
if ((sem_t*)op.hNativeEvent != SEM_FAILED) {
|
||||
sem_close((sem_t*)op.hNativeEvent);
|
||||
sem_unlink(opEventName.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (handleInternal->pSharedMemory) {
|
||||
struct stat st = {};
|
||||
fstat((int)(intptr_t)handleInternal->hSharedMemory, &st);
|
||||
munmap(handleInternal->pSharedMemory, st.st_size);
|
||||
}
|
||||
if (handleInternal->hSharedMemory)
|
||||
close((int)(intptr_t)handleInternal->hSharedMemory);
|
||||
shm_unlink(szSharedMemoryPath.c_str());
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
@@ -317,7 +463,7 @@ bool ipc_client_shutdown(IpcHandle_t* hIpcClient) {
|
||||
if (hIpcClient && *hIpcClient != k_hInvalidIpcHandle) {
|
||||
__internal__IpcHandle_t* handleInternal = (__internal__IpcHandle_t*)*hIpcClient;
|
||||
|
||||
#if _WIN32
|
||||
#if IPC_OS_WIN32
|
||||
for (size_t i = 0; i < handleInternal->registed_operations.size(); ++i) {
|
||||
if (handleInternal->registed_operations[i].hNativeEvent)
|
||||
CloseHandle((HANDLE)handleInternal->registed_operations[i].hNativeEvent);
|
||||
@@ -334,6 +480,29 @@ bool ipc_client_shutdown(IpcHandle_t* hIpcClient) {
|
||||
UnmapViewOfFile(handleInternal->pSharedMemory);
|
||||
if (handleInternal->hSharedMemory)
|
||||
CloseHandle(handleInternal->hSharedMemory);
|
||||
#elif IPC_OS_LINUX
|
||||
std::string szSharedMemoryPath = (handleInternal->szSharedMemoryName[0] == '/') ? handleInternal->szSharedMemoryName : "/" + std::string(handleInternal->szSharedMemoryName);
|
||||
|
||||
for (size_t i = 0; i < handleInternal->registed_operations.size(); ++i) {
|
||||
IpcOperation_t& op = handleInternal->registed_operations[i];
|
||||
if ((sem_t*)op.hNativeMutex != SEM_FAILED)
|
||||
sem_close((sem_t*)op.hNativeMutex);
|
||||
if ((sem_t*)op.hNativeEvent != SEM_FAILED)
|
||||
sem_close((sem_t*)op.hNativeEvent);
|
||||
}
|
||||
|
||||
if ((sem_t*)handleInternal->hNativeMutex != SEM_FAILED)
|
||||
sem_close((sem_t*)handleInternal->hNativeMutex);
|
||||
if ((sem_t*)handleInternal->hNativeEvent != SEM_FAILED)
|
||||
sem_close((sem_t*)handleInternal->hNativeEvent);
|
||||
|
||||
if (handleInternal->pSharedMemory) {
|
||||
struct stat st = {};
|
||||
fstat((int)(intptr_t)handleInternal->hSharedMemory, &st);
|
||||
munmap(handleInternal->pSharedMemory, st.st_size);
|
||||
}
|
||||
if (handleInternal->hSharedMemory)
|
||||
close((int)(intptr_t)handleInternal->hSharedMemory);
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
@@ -363,14 +532,23 @@ bool ipc_client_dispatch_function(IpcHandle_t hIpcClient, IpcCommandType_t unCmd
|
||||
return false;
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
#if IPC_OS_WIN32
|
||||
WaitForSingleObject((HANDLE)handleInternal->hNativeMutex, INFINITE);
|
||||
void* pSharedMem = handleInternal->pSharedMemory;
|
||||
*((IpcCommandType_t*)pSharedMem) = unCmdType;
|
||||
memcpy((char*)pSharedMem + sizeof(IpcCommandType_t), pArgs, dwArgsSize);
|
||||
SetEvent((HANDLE)handleInternal->hNativeEvent);
|
||||
WaitForSingleObject((HANDLE)handleInternal->hNativeEvent, INFINITE);
|
||||
ReleaseMutex((HANDLE)handleInternal->hNativeMutex);
|
||||
#elif IPC_OS_LINUX
|
||||
sem_t* semMtx = (sem_t*)handleInternal->hNativeMutex;
|
||||
sem_t* semEvt = (sem_t*)handleInternal->hNativeEvent;
|
||||
|
||||
sem_wait(semMtx);
|
||||
void* pSharedMem = handleInternal->pSharedMemory;
|
||||
*((IpcCommandType_t*)pSharedMem) = unCmdType;
|
||||
memcpy((char*)pSharedMem + sizeof(IpcCommandType_t), pArgs, dwArgsSize);
|
||||
sem_post(semEvt);
|
||||
sem_post(semMtx);
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
@@ -384,7 +562,7 @@ bool ipc_server_register_operation(IpcHandle_t hIpcServer, IpcOperation_t* ipcOp
|
||||
}
|
||||
__internal__IpcHandle_t* handleInternal = (__internal__IpcHandle_t*)hIpcServer;
|
||||
|
||||
#if _WIN32
|
||||
#if IPC_OS_WIN32
|
||||
std::string mutexName = std::string(handleInternal->szSharedMemoryName) + "_" + std::string(ipcOperation->szIdentifier) + "_MTX";
|
||||
std::string eventName = std::string(handleInternal->szSharedMemoryName) + "_" + std::string(ipcOperation->szIdentifier) + "_EVT";
|
||||
|
||||
@@ -398,12 +576,31 @@ bool ipc_server_register_operation(IpcHandle_t hIpcServer, IpcOperation_t* ipcOp
|
||||
CloseHandle((HANDLE)ipcOperation->hNativeEvent);
|
||||
return false;
|
||||
}
|
||||
#elif IPC_OS_LINUX
|
||||
std::string szSharedMemoryPath = (handleInternal->szSharedMemoryName[0] == '/') ? handleInternal->szSharedMemoryName : "/" + std::string(handleInternal->szSharedMemoryName);
|
||||
std::string mutexName = szSharedMemoryPath + "_" + std::string(ipcOperation->szIdentifier) + "_MTX";
|
||||
std::string eventName = szSharedMemoryPath + "_" + std::string(ipcOperation->szIdentifier) + "_EVT";
|
||||
|
||||
handleInternal->registed_operations.push_back(*ipcOperation);
|
||||
ipcOperation->hNativeMutex = (IpcNativeHandle_t)sem_open(mutexName.c_str(), O_CREAT, IPC_S_RW_ALL, 1);
|
||||
ipcOperation->hNativeEvent = (IpcNativeHandle_t)sem_open(eventName.c_str(), O_CREAT, IPC_S_RW_ALL, 0);
|
||||
|
||||
if (ipcOperation->hNativeMutex == SEM_FAILED || ipcOperation->hNativeEvent == SEM_FAILED) {
|
||||
if ((sem_t*)ipcOperation->hNativeMutex != SEM_FAILED) {
|
||||
sem_close((sem_t*)ipcOperation->hNativeMutex);
|
||||
sem_unlink(mutexName.c_str());
|
||||
}
|
||||
if ((sem_t*)ipcOperation->hNativeEvent != SEM_FAILED) {
|
||||
sem_close((sem_t*)ipcOperation->hNativeEvent);
|
||||
sem_unlink(eventName.c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
|
||||
handleInternal->registed_operations.push_back(*ipcOperation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -415,16 +612,31 @@ bool ipc_server_write_shared_memory(IpcHandle_t hIpcServer, IpcOperation_t ipcOp
|
||||
return false;
|
||||
__internal__IpcHandle_t* handleInternal = (__internal__IpcHandle_t*)hIpcServer;
|
||||
|
||||
#if _WIN32
|
||||
#if IPC_OS_WIN32
|
||||
DWORD ret = WaitForSingleObject((HANDLE)ipcOperation.hNativeMutex, 10);
|
||||
if (ret == WAIT_TIMEOUT) {
|
||||
ReleaseMutex((HANDLE)ipcOperation.hNativeMutex);
|
||||
return false;
|
||||
}
|
||||
void* pDest = (char*)handleInternal->pSharedMemory + IPC_FUNCTION_ARGS_TOTAL_SIZE + ipcOperation.dwSharedMemoryOffset;
|
||||
memcpy(pDest, pSrc, destSize);
|
||||
SetEvent((HANDLE)ipcOperation.hNativeEvent);
|
||||
ReleaseMutex((HANDLE)ipcOperation.hNativeMutex);
|
||||
#elif IPC_OS_LINUX
|
||||
sem_t* semMtx = (sem_t*)ipcOperation.hNativeMutex;
|
||||
sem_t* semEvt = (sem_t*)ipcOperation.hNativeEvent;
|
||||
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_nsec += 10000000; // 10ms
|
||||
if (ts.tv_nsec >= 1000000000) { ts.tv_sec += 1; ts.tv_nsec -= 1000000000; }
|
||||
|
||||
if (sem_timedwait(semMtx, &ts) != 0) {
|
||||
return false;
|
||||
}
|
||||
void* pDest = (char*)handleInternal->pSharedMemory + IPC_FUNCTION_ARGS_TOTAL_SIZE + ipcOperation.dwSharedMemoryOffset;
|
||||
memcpy(pDest, pSrc, destSize);
|
||||
sem_post(semEvt);
|
||||
sem_post(semMtx);
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
@@ -440,20 +652,29 @@ bool ipc_client_read_shared_memory(IpcHandle_t hIpcClient, IpcOperation_t ipcOpe
|
||||
return false;
|
||||
__internal__IpcHandle_t* handleInternal = (__internal__IpcHandle_t*)hIpcClient;
|
||||
|
||||
#if _WIN32
|
||||
DWORD ret = WaitForSingleObject((HANDLE)ipcOperation.hNativeEvent, 10);
|
||||
#if IPC_OS_WIN32
|
||||
DWORD ret = WaitForSingleObject((HANDLE)ipcOperation.hNativeMutex, 10);
|
||||
if (ret == WAIT_TIMEOUT) {
|
||||
ReleaseMutex((HANDLE)ipcOperation.hNativeMutex);
|
||||
return false;
|
||||
}
|
||||
ret = WaitForSingleObject((HANDLE)ipcOperation.hNativeMutex, 10);
|
||||
if (ret == WAIT_TIMEOUT) {
|
||||
ReleaseMutex((HANDLE)ipcOperation.hNativeMutex);
|
||||
return false;
|
||||
}
|
||||
void* pSrc = (char*)handleInternal->pSharedMemory + IPC_FUNCTION_ARGS_TOTAL_SIZE + ipcOperation.dwSharedMemoryOffset;
|
||||
memcpy(pDest, pSrc, destSize);
|
||||
ReleaseMutex((HANDLE)ipcOperation.hNativeMutex);
|
||||
#elif IPC_OS_LINUX
|
||||
sem_t* semMtx = (sem_t*)ipcOperation.hNativeMutex;
|
||||
sem_t* semEvt = (sem_t*)ipcOperation.hNativeEvent;
|
||||
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_nsec += 10000000;
|
||||
if (ts.tv_nsec >= 1000000000) { ts.tv_sec += 1; ts.tv_nsec -= 1000000000; }
|
||||
|
||||
if (sem_timedwait(semMtx, &ts) != 0) {
|
||||
return false;
|
||||
}
|
||||
void* pSrc = (char*)handleInternal->pSharedMemory + IPC_FUNCTION_ARGS_TOTAL_SIZE + ipcOperation.dwSharedMemoryOffset;
|
||||
memcpy(pDest, pSrc, destSize);
|
||||
sem_post(semMtx);
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
@@ -461,5 +682,9 @@ bool ipc_client_read_shared_memory(IpcHandle_t hIpcClient, IpcOperation_t ipcOpe
|
||||
return true;
|
||||
}
|
||||
|
||||
#if IPC_OS_LINUX
|
||||
#undef IPC_S_RW_ALL
|
||||
#endif
|
||||
|
||||
#endif // IPC_IMPLEMENTATION
|
||||
#endif // HEKKY_IPC_INC
|
||||
Reference in new issue
Block a user