#include "lighthouse_driver_wrapper.h" #include #include #include #include #include #include #include #include #include #if defined(_WIN32) #include #define OPENVR_DLL_EXPORT extern "C" __declspec(dllexport) #define OPENVR_DLL_IMPORT extern "C" __declspec(dllimport) #define OPENVR_FNTABLE_CALLTYPE __stdcall #define HMODULE_TYPE HMODULE #define LOAD_LIBRARY(path) LoadLibraryA(path) #define GET_PROC_ADDRESS(handle, name) GetProcAddress((HMODULE)handle, name) #define FREE_LIBRARY(handle) FreeLibrary((HMODULE)handle) #define PATH_SEPARATOR "\\" #elif defined(__linux__) || defined(__APPLE__) #include #define OPENVR_DLL_EXPORT extern "C" __attribute__((visibility("default"))) #define OPENVR_DLL_IMPORT extern "C" #define OPENVR_FNTABLE_CALLTYPE #define HMODULE_TYPE void* #define LOAD_LIBRARY(path) dlopen(path, RTLD_NOW) #define GET_PROC_ADDRESS(handle, name) dlsym(handle, name) #define FREE_LIBRARY(handle) dlclose(handle) #define PATH_SEPARATOR "/" #endif namespace sauna { LighthouseDriverWrapper::LighthouseDriverWrapper() : m_pLighthouseDriverLib(nullptr) , m_pLighthouseProvider(nullptr) , m_fnCreateInterface(nullptr) , m_fnGetDriverCount(nullptr) , m_fnGetDriverName(nullptr) { } LighthouseDriverWrapper::~LighthouseDriverWrapper() { Shutdown(); } bool LighthouseDriverWrapper::Initialize() { // Create a debug log file FILE* logFile = fopen("lighthouse_init_debug.log", "w"); if (logFile) { fprintf(logFile, "=== Initialize called at %lld ===\n", (long long)time(nullptr)); } auto Log = [&](const char* format, ...) { if (logFile) { va_list args; va_start(args, format); vfprintf(logFile, format, args); fprintf(logFile, "\n"); fflush(logFile); va_end(args); } }; Log("Starting lighthouse driver initialization"); if (m_pLighthouseProvider) { Log("Provider already initialized, returning true"); if (logFile) fclose(logFile); return true; } Log("Calling LoadLighthouseDriver()"); if (!LoadLighthouseDriver()) { Log("LoadLighthouseDriver() failed"); if (logFile) fclose(logFile); return false; } Log("LoadLighthouseDriver() succeeded"); // Get the lighthouse driver provider Log("Getting lighthouse driver provider interface"); vr::EVRInitError eError = vr::VRInitError_None; m_pLighthouseProvider = static_cast( m_fnCreateInterface(vr::IServerTrackedDeviceProvider_Version, &eError)); if (!m_pLighthouseProvider || eError != vr::VRInitError_None) { Log("Failed to get lighthouse driver provider interface, error code: %d", eError); UnloadLighthouseDriver(); if (logFile) fclose(logFile); return false; } Log("Successfully got lighthouse driver provider interface"); // Initialize the lighthouse driver Log("Initializing lighthouse driver with proper context initialization"); // We've already successfully preloaded openvr_api.dll in LoadLighthouseDriver // Let's focus on initializing the driver context properly // Let's try a different approach based on how lighthouse_console.exe might be using the driver // First, let's try to initialize the driver context using the approach from the documentation Log("Trying to initialize driver context using approach from documentation"); // Get the driver context vr::IVRDriverContext* pDriverContext = vr::VRDriverContext(); if (!pDriverContext) { Log("ERROR: VRDriverContext() returned NULL"); m_pLighthouseProvider = nullptr; UnloadLighthouseDriver(); if (logFile) fclose(logFile); return false; } Log("Successfully got driver context"); // Initialize the driver context Log("Initializing driver context with VR_INIT_SERVER_DRIVER_CONTEXT"); VR_INIT_SERVER_DRIVER_CONTEXT(pDriverContext); Log("Driver context initialized"); // Now initialize the provider with the initialized context Log("Calling m_pLighthouseProvider->Init with initialized context"); try { // Let's try to get some information about the provider before initializing Log("Provider interface version: %s", m_pLighthouseProvider->GetInterfaceVersions()[0]); // Now initialize the provider Log("About to call Init on provider"); eError = m_pLighthouseProvider->Init(pDriverContext); Log("Init call completed with error code: %d", eError); if (eError != vr::VRInitError_None) { Log("Failed to initialize lighthouse driver, error code: %d", eError); // Try a different approach - similar to how lighthouse_console.exe might do it Log("Trying alternative initialization approach"); // Let's try to initialize with a null context Log("Calling m_pLighthouseProvider->Init with null context"); eError = m_pLighthouseProvider->Init(nullptr); if (eError != vr::VRInitError_None) { Log("Failed to initialize lighthouse driver with null context, error code: %d", eError); // Let's try one more approach - create a minimal context Log("Trying with minimal context"); // Create a minimal context with just the essential interfaces struct MinimalContext : public vr::IVRDriverContext { virtual void* GetGenericInterface(const char* pchInterfaceVersion, vr::EVRInitError* peError) override { *peError = vr::VRInitError_None; return nullptr; } virtual vr::DriverHandle_t GetDriverHandle() override { return 0; } }; MinimalContext minimalContext; eError = m_pLighthouseProvider->Init(&minimalContext); if (eError != vr::VRInitError_None) { Log("Failed to initialize lighthouse driver with minimal context, error code: %d", eError); m_pLighthouseProvider = nullptr; UnloadLighthouseDriver(); if (logFile) fclose(logFile); return false; } else { Log("Successfully initialized lighthouse driver with minimal context"); } } else { Log("Successfully initialized lighthouse driver with null context"); } } else { Log("Successfully initialized lighthouse driver with standard context"); } } catch (const std::exception& e) { Log("Exception during lighthouse driver initialization: %s", e.what()); m_pLighthouseProvider = nullptr; UnloadLighthouseDriver(); if (logFile) fclose(logFile); return false; } catch (...) { Log("Unknown exception during lighthouse driver initialization"); m_pLighthouseProvider = nullptr; UnloadLighthouseDriver(); if (logFile) fclose(logFile); return false; } Log("Lighthouse driver initialized successfully"); if (eError != vr::VRInitError_None) { Log("Failed to initialize lighthouse driver, error code: %d", eError); Log("Trying alternative initialization approach..."); // Try a different approach - pass null context Log("Calling m_pLighthouseProvider->Init with null context"); eError = m_pLighthouseProvider->Init(nullptr); if (eError != vr::VRInitError_None) { Log("Failed to initialize lighthouse driver with null context, error code: %d", eError); m_pLighthouseProvider = nullptr; UnloadLighthouseDriver(); if (logFile) fclose(logFile); return false; } } Log("Lighthouse driver initialized successfully"); if (logFile) fclose(logFile); return true; } void LighthouseDriverWrapper::Shutdown() { if (m_pLighthouseProvider) { m_pLighthouseProvider->Cleanup(); m_pLighthouseProvider = nullptr; } UnloadLighthouseDriver(); } void LighthouseDriverWrapper::RunFrame() { // Create a debug log file FILE* logFile = fopen("lighthouse_runframe_debug.log", "a"); if (logFile) { fprintf(logFile, "RunFrame called at %lld\n", (long long)time(nullptr)); } if (m_pLighthouseProvider) { if (logFile) { fprintf(logFile, "Calling m_pLighthouseProvider->RunFrame()\n"); fflush(logFile); } // Since we skipped initialization, this might not work properly // But we'll try it anyway try { m_pLighthouseProvider->RunFrame(); if (logFile) { fprintf(logFile, "RunFrame completed successfully\n"); fflush(logFile); } } catch (...) { if (logFile) { fprintf(logFile, "Exception in RunFrame\n"); fflush(logFile); } } } else { if (logFile) { fprintf(logFile, "m_pLighthouseProvider is null\n"); fflush(logFile); } } if (logFile) { fclose(logFile); } } void LighthouseDriverWrapper::EnterStandby() { // Create a debug log file FILE* logFile = fopen("lighthouse_standby_debug.log", "a"); if (logFile) { fprintf(logFile, "EnterStandby called at %lld\n", (long long)time(nullptr)); } if (m_pLighthouseProvider) { if (logFile) { fprintf(logFile, "Calling m_pLighthouseProvider->EnterStandby()\n"); fflush(logFile); } try { m_pLighthouseProvider->EnterStandby(); if (logFile) { fprintf(logFile, "EnterStandby completed successfully\n"); fflush(logFile); } } catch (...) { if (logFile) { fprintf(logFile, "Exception in EnterStandby\n"); fflush(logFile); } } } else { if (logFile) { fprintf(logFile, "m_pLighthouseProvider is null\n"); fflush(logFile); } } if (logFile) { fclose(logFile); } } void LighthouseDriverWrapper::LeaveStandby() { // Create a debug log file FILE* logFile = fopen("lighthouse_standby_debug.log", "a"); if (logFile) { fprintf(logFile, "LeaveStandby called at %lld\n", (long long)time(nullptr)); } if (m_pLighthouseProvider) { if (logFile) { fprintf(logFile, "Calling m_pLighthouseProvider->LeaveStandby()\n"); fflush(logFile); } try { m_pLighthouseProvider->LeaveStandby(); if (logFile) { fprintf(logFile, "LeaveStandby completed successfully\n"); fflush(logFile); } } catch (...) { if (logFile) { fprintf(logFile, "Exception in LeaveStandby\n"); fflush(logFile); } } } else { if (logFile) { fprintf(logFile, "m_pLighthouseProvider is null\n"); fflush(logFile); } } if (logFile) { fclose(logFile); } } bool LighthouseDriverWrapper::LoadLighthouseDriver() { // Create a direct debug log file FILE* logFile = fopen("lighthouse_driver_debug.log", "w"); if (!logFile) { return false; } fprintf(logFile, "=== LoadLighthouseDriver called at %lld ===\n", (long long)time(nullptr)); fflush(logFile); // Define a simple logging function auto Log = [&](const char* format, ...) { va_list args; va_start(args, format); vfprintf(logFile, format, args); fprintf(logFile, "\n"); fflush(logFile); va_end(args); }; Log("Attempting to load lighthouse driver directly"); // Clear the driver path m_strDriverPath = ""; // Define a simple set of paths to try - focus on the most common locations std::vector paths; #if defined(_WIN32) // Windows paths - we know this one exists from the test output paths.push_back("C:\\Program Files (x86)\\Steam\\steamapps\\common\\SteamVR\\drivers\\lighthouse\\bin\\win64\\driver_lighthouse.dll"); // Add other potential paths as fallbacks paths.push_back("C:\\Program Files\\Steam\\steamapps\\common\\SteamVR\\drivers\\lighthouse\\bin\\win64\\driver_lighthouse.dll"); // Get user profile path char* userProfile = getenv("USERPROFILE"); if (userProfile) { std::string userPath = userProfile; paths.push_back(userPath + "\\AppData\\Local\\OpenVR\\drivers\\lighthouse\\bin\\win64\\driver_lighthouse.dll"); } #elif defined(__linux__) // Linux paths paths.push_back("/usr/share/steam/steamapps/common/SteamVR/drivers/lighthouse/bin/linux64/driver_lighthouse.so"); paths.push_back("~/.steam/steam/steamapps/common/SteamVR/drivers/lighthouse/bin/linux64/driver_lighthouse.so"); #elif defined(__APPLE__) // macOS paths paths.push_back("~/Library/Application Support/Steam/steamapps/common/SteamVR/drivers/lighthouse/bin/osx64/driver_lighthouse.dylib"); #endif // Try each path for (const auto& path : paths) { Log("Trying path: %s", path.c_str()); // Set the current path m_strDriverPath = path; // Check if file exists FILE* file = fopen(path.c_str(), "rb"); if (!file) { Log("File does not exist: %s", path.c_str()); continue; } // Get file size fseek(file, 0, SEEK_END); long size = ftell(file); fclose(file); Log("File exists with size: %ld bytes", size); #if defined(_WIN32) // On Windows, add the directory containing the DLL to the DLL search path std::string directory = path.substr(0, path.find_last_of('\\')); Log("Adding directory to DLL search path: %s", directory.c_str()); // Save the current directory char currentDir[MAX_PATH]; GetCurrentDirectoryA(MAX_PATH, currentDir); // Set the directory containing the DLL as the current directory SetCurrentDirectoryA(directory.c_str()); // Try to preload common dependencies Log("Preloading common dependencies..."); // Look for openvr_api.dll in various locations std::vector apiPaths; apiPaths.push_back(directory + "\\openvr_api.dll"); // Same directory as driver apiPaths.push_back("C:\\Program Files (x86)\\Steam\\steamapps\\common\\SteamVR\\bin\\win64\\openvr_api.dll"); apiPaths.push_back("C:\\Program Files\\Steam\\steamapps\\common\\SteamVR\\bin\\win64\\openvr_api.dll"); bool foundApi = false; for (const auto& apiPath : apiPaths) { Log("Checking for openvr_api.dll at: %s", apiPath.c_str()); FILE* apiFile = fopen(apiPath.c_str(), "rb"); if (apiFile) { fclose(apiFile); Log("Found openvr_api.dll at: %s", apiPath.c_str()); // Try to load it HMODULE hDep = LoadLibraryA(apiPath.c_str()); if (hDep) { Log(" Successfully preloaded openvr_api.dll from %s", apiPath.c_str()); foundApi = true; // Keep the dependency loaded break; } else { DWORD depError = GetLastError(); Log(" Failed to preload openvr_api.dll from %s (Error %d)", apiPath.c_str(), depError); } } } if (!foundApi) { Log("Could not find or load openvr_api.dll in any location"); } #endif // Try to load the library Log("Loading library..."); // If we found the API DLL but couldn't load it, try copying it to our directory if (!foundApi) { for (const auto& apiPath : apiPaths) { FILE* apiFile = fopen(apiPath.c_str(), "rb"); if (apiFile) { // Read the file fseek(apiFile, 0, SEEK_END); long size = ftell(apiFile); fseek(apiFile, 0, SEEK_SET); std::vector buffer(size); if (fread(buffer.data(), 1, size, apiFile) == size) { fclose(apiFile); // Write to our directory FILE* outFile = fopen("openvr_api.dll", "wb"); if (outFile) { if (fwrite(buffer.data(), 1, size, outFile) == size) { fclose(outFile); Log("Copied openvr_api.dll to current directory"); // Try to load it HMODULE hDep = LoadLibraryA("openvr_api.dll"); if (hDep) { Log(" Successfully loaded openvr_api.dll from current directory"); foundApi = true; break; } } else { fclose(outFile); } } } else { fclose(apiFile); } } } } m_pLighthouseDriverLib = LOAD_LIBRARY(path.c_str()); #if defined(_WIN32) // Restore the current directory SetCurrentDirectoryA(currentDir); #endif if (!m_pLighthouseDriverLib) { #if defined(_WIN32) DWORD error = GetLastError(); Log("Failed to load library. Error code: %d", error); // Get the error message char errorMsg[256] = {0}; FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), errorMsg, sizeof(errorMsg), NULL ); Log("Error message: %s", errorMsg); #else Log("Failed to load library"); #endif continue; } Log("Library loaded successfully"); // Get the factory function Log("Getting HmdDriverFactory function..."); m_fnCreateInterface = reinterpret_cast( GET_PROC_ADDRESS(m_pLighthouseDriverLib, "HmdDriverFactory")); if (!m_fnCreateInterface) { #if defined(_WIN32) DWORD error = GetLastError(); Log("Failed to get HmdDriverFactory function. Error code: %d", error); #else Log("Failed to get HmdDriverFactory function"); #endif UnloadLighthouseDriver(); continue; } Log("HmdDriverFactory function found"); Log("Lighthouse driver loaded successfully from: %s", path.c_str()); fclose(logFile); return true; } Log("Failed to load lighthouse driver from any location"); fclose(logFile); return false; } void LighthouseDriverWrapper::UnloadLighthouseDriver() { if (m_pLighthouseDriverLib) { FREE_LIBRARY(m_pLighthouseDriverLib); m_pLighthouseDriverLib = nullptr; } m_fnCreateInterface = nullptr; m_fnGetDriverCount = nullptr; m_fnGetDriverName = nullptr; } } // namespace sauna