diff options
Diffstat (limited to 'LibOVRKernel/Src/Util')
-rw-r--r-- | LibOVRKernel/Src/Util/GUIConsole.h | 48 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_Direct3D.cpp | 154 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_Direct3D.h | 102 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_GetSystemSpecs.cpp | 455 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_ImageWindow.cpp | 591 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_ImageWindow.h | 201 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_LongPollThread.cpp | 97 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_LongPollThread.h | 72 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_SystemGUI.cpp | 239 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_SystemGUI.h | 40 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_SystemGUI_OSX.mm | 69 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_SystemInfo.cpp | 416 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_SystemInfo.h | 52 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_SystemInfo_OSX.mm | 111 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_Watchdog.cpp | 249 | ||||
-rw-r--r-- | LibOVRKernel/Src/Util/Util_Watchdog.h | 113 |
16 files changed, 3009 insertions, 0 deletions
diff --git a/LibOVRKernel/Src/Util/GUIConsole.h b/LibOVRKernel/Src/Util/GUIConsole.h new file mode 100644 index 0000000..b5a3784 --- /dev/null +++ b/LibOVRKernel/Src/Util/GUIConsole.h @@ -0,0 +1,48 @@ +/************************************************************************************ + +Filename : GUIConsole.h +Content : A stdout console window that runs alongside Windows GUI applications +Created : Feb 4, 2013 +Authors : Brant Lewis + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#ifndef OVR_Util_GuiConsole_h +#define OVR_Util_GuiConsole_h + +#include "../../Include/OVR_Kernel.h" + +#ifdef OVR_INTERNAL_USE + +#include "../Kernel/OVR_Win32_IncludeWindows.h" + +class GUIConsole +{ +public: + // constructors + GUIConsole(); + ~GUIConsole(); + + // member variables + HANDLE hStdIn, hStdOut, hStdError; +}; +#endif // #ifdef OVR_INTERNAL_USE + +#endif //OVR_Util_GuiConsole_h diff --git a/LibOVRKernel/Src/Util/Util_Direct3D.cpp b/LibOVRKernel/Src/Util/Util_Direct3D.cpp new file mode 100644 index 0000000..5aff711 --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_Direct3D.cpp @@ -0,0 +1,154 @@ +/************************************************************************************ + +Filename : Util_Direct3D.cpp +Content : Shared code for Direct3D +Created : Oct 14, 2014 +Authors : Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +#include "Util_Direct3D.h" + +#include "Kernel/OVR_Log.h" + +namespace OVR { namespace D3DUtil { + + +bool VerifyHRESULT(const char* file, int line, HRESULT hr) +{ + if (FAILED(hr)) + { + LogError("D3D function returned fail HRESULT at %s on line %d : %s", + file, line, D3DUtil::GetWindowsErrorString(hr).ToCStr()); + OVR_ASSERT(false); + return false; + } + + return true; +} + +bool CheckD3D9Ex() +{ + bool available = false; + HMODULE libHandle = LoadLibraryW(L"d3d9.dll"); + + if (libHandle != nullptr) + { + available = (GetProcAddress(libHandle, "Direct3DCreate9Ex") != nullptr); + FreeLibrary(libHandle); + } + + return available; +} + +String GetWindowsErrorString(HRESULT hr) +{ + // DirectX 9 error strings + switch (hr) + { + case D3DERR_WRONGTEXTUREFORMAT: return "D3DERR_WRONGTEXTUREFORMAT"; + case D3DERR_UNSUPPORTEDCOLOROPERATION: return "D3DERR_UNSUPPORTEDCOLOROPERATION"; + case D3DERR_UNSUPPORTEDCOLORARG: return "D3DERR_UNSUPPORTEDCOLORARG"; + case D3DERR_UNSUPPORTEDALPHAOPERATION: return "D3DERR_UNSUPPORTEDALPHAOPERATION"; + case D3DERR_UNSUPPORTEDALPHAARG: return "D3DERR_UNSUPPORTEDALPHAARG"; + case D3DERR_TOOMANYOPERATIONS: return "D3DERR_TOOMANYOPERATIONS"; + case D3DERR_CONFLICTINGTEXTUREFILTER: return "D3DERR_CONFLICTINGTEXTUREFILTER"; + case D3DERR_UNSUPPORTEDFACTORVALUE: return "D3DERR_UNSUPPORTEDFACTORVALUE"; + case D3DERR_CONFLICTINGRENDERSTATE: return "D3DERR_CONFLICTINGRENDERSTATE"; + case D3DERR_UNSUPPORTEDTEXTUREFILTER: return "D3DERR_UNSUPPORTEDTEXTUREFILTER"; + case D3DERR_CONFLICTINGTEXTUREPALETTE: return "D3DERR_CONFLICTINGTEXTUREPALETTE"; + case D3DERR_DRIVERINTERNALERROR: return "D3DERR_DRIVERINTERNALERROR"; + case D3DERR_NOTFOUND: return "D3DERR_NOTFOUND"; + case D3DERR_MOREDATA: return "D3DERR_MOREDATA"; + case D3DERR_DEVICELOST: return "D3DERR_DEVICELOST"; + case D3DERR_DEVICENOTRESET: return "D3DERR_DEVICENOTRESET"; + case D3DERR_NOTAVAILABLE: return "D3DERR_NOTAVAILABLE"; + case D3DERR_OUTOFVIDEOMEMORY: return "D3DERR_OUTOFVIDEOMEMORY"; + case D3DERR_INVALIDDEVICE: return "D3DERR_INVALIDDEVICE"; + case D3DERR_INVALIDCALL: return "D3DERR_INVALIDCALL"; + case D3DERR_DRIVERINVALIDCALL: return "D3DERR_DRIVERINVALIDCALL"; + case D3DERR_WASSTILLDRAWING: return "D3DERR_WASSTILLDRAWING"; + case D3DOK_NOAUTOGEN: return "D3DOK_NOAUTOGEN"; + case D3DERR_DEVICEREMOVED: return "D3DERR_DEVICEREMOVED"; + case S_NOT_RESIDENT: return "S_NOT_RESIDENT"; + case S_RESIDENT_IN_SHARED_MEMORY: return "S_RESIDENT_IN_SHARED_MEMORY"; + case S_PRESENT_MODE_CHANGED: return "S_PRESENT_MODE_CHANGED"; + case S_PRESENT_OCCLUDED: return "S_PRESENT_OCCLUDED"; + case D3DERR_DEVICEHUNG: return "D3DERR_DEVICEHUNG"; + case D3DERR_UNSUPPORTEDOVERLAY: return "D3DERR_UNSUPPORTEDOVERLAY"; + case D3DERR_UNSUPPORTEDOVERLAYFORMAT: return "D3DERR_UNSUPPORTEDOVERLAYFORMAT"; + case D3DERR_CANNOTPROTECTCONTENT: return "D3DERR_CANNOTPROTECTCONTENT"; + case D3DERR_UNSUPPORTEDCRYPTO: return "D3DERR_UNSUPPORTEDCRYPTO"; + case D3DERR_PRESENT_STATISTICS_DISJOINT: return "D3DERR_PRESENT_STATISTICS_DISJOINT"; + default: break; // Not a DirectX 9 error, use FormatMessageA... + } + + char errorTextAddr[256] = {}; + + DWORD slen = FormatMessageA( + // use system message tables to retrieve error text + FORMAT_MESSAGE_FROM_SYSTEM + // allocate buffer on local heap for error text + | FORMAT_MESSAGE_ALLOCATE_BUFFER + // Important! will fail otherwise, since we're not + // (and CANNOT) pass insertion parameters + | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, // unused with FORMAT_MESSAGE_FROM_SYSTEM + hr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + errorTextAddr, // output + 256, // minimum size for output buffer + nullptr); // arguments - see note + + char* errorText = *(char**)errorTextAddr; + + char formatStr[512]; + OVR_snprintf(formatStr, sizeof(formatStr), "[Code=%x = %d]", hr, hr); + + String retStr = formatStr; + + if (slen > 0 && errorText) + { + retStr += " "; + retStr += errorText; + + // release memory allocated by FormatMessage() + LocalFree(errorText); + } + + return retStr; +} + +void LogD3DCompileError(HRESULT hr, ID3DBlob* blob) +{ + if (FAILED(hr)) + { + char* errStr = (char*)blob->GetBufferPointer(); + SIZE_T len = blob->GetBufferSize(); + + if (errStr && len > 0) + { + LogError("Error compiling shader: %s", errStr); + } + } +} + + +}} // namespace OVR::D3DUtil diff --git a/LibOVRKernel/Src/Util/Util_Direct3D.h b/LibOVRKernel/Src/Util/Util_Direct3D.h new file mode 100644 index 0000000..958ef2b --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_Direct3D.h @@ -0,0 +1,102 @@ +/************************************************************************************ + +Filename : Util_Direct3D.h +Content : Shared code for Direct3D +Created : Oct 14, 2014 +Authors : Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +#ifndef OVR_Util_Direct3D_h +#define OVR_Util_Direct3D_h + +// Include Windows correctly first before implicitly including it below +#include "Kernel/OVR_Win32_IncludeWindows.h" +#include "Kernel/OVR_String.h" + +// DirectX 9 Ex +#include <d3d9.h> + +// Direct3D 11 +#include <D3D11Shader.h> +#include <d3dcompiler.h> + +#if _MSC_VER >= 1800 + // Visual Studio 2013+ support newer D3D/DXGI headers. + #define OVR_D3D11_VER 2 + #include <d3d11_2.h> + #define OVR_DXGI_VER 3 + #include <dxgi1_3.h> // Used in place of 1.2 for IDXGIFactory2 debug version (when available) +#elif _MSC_VER >= 1700 + // Visual Studio 2012+ only supports older D3D/DXGI headers. + #define OVR_D3D11_VER 1 + #include <d3d11_1.h> +#else + // Visual Studio 2010+ only supports original D3D/DXGI headers. + #define OVR_D3D11_VER 1 + #include <d3d11.h> +#endif + +namespace OVR { namespace D3DUtil { + + +// Check if D3D9Ex support exists in the environment +bool CheckD3D9Ex(); + +String GetWindowsErrorString(HRESULT hr); + + +//----------------------------------------------------------------------------- +// Helper macros for verifying HRESULT values from Direct3D API calls +// +// These will assert on failure in debug mode, and in release or debug mode +// these functions will report the file and line where the error occurred, +// and what the error code was to the log at Error-level. + +// Assert on HRESULT failure +bool VerifyHRESULT(const char* file, int line, HRESULT hr); + +#define OVR_D3D_CHECK(hr) OVR::D3DUtil::VerifyHRESULT(__FILE__, __LINE__, hr) + +// Returns provided value on failure +#define OVR_D3D_CHECK_RET_VAL(hr, failureValue) \ + { \ + if (!OVR_D3D_CHECK(hr)) \ + { \ + return failureValue; \ + } \ + } + +// Returns void on failure +#define OVR_D3D_CHECK_RET(hr) OVR_D3D_CHECK_RET_VAL(hr, ;) + +// Returns false on failure +#define OVR_D3D_CHECK_RET_FALSE(hr) OVR_D3D_CHECK_RET_VAL(hr, false) + +// Returns nullptr on failure +#define OVR_D3D_CHECK_RET_NULL(hr) OVR_D3D_CHECK_RET_VAL(hr, nullptr) + +// If the result is a failure, it will write the exact compile error to the error log +void LogD3DCompileError(HRESULT hr, ID3DBlob* errorBlob); + + +}} // namespace OVR::D3DUtil + +#endif // OVR_Util_Direct3D_h diff --git a/LibOVRKernel/Src/Util/Util_GetSystemSpecs.cpp b/LibOVRKernel/Src/Util/Util_GetSystemSpecs.cpp new file mode 100644 index 0000000..d2cbbab --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_GetSystemSpecs.cpp @@ -0,0 +1,455 @@ +/************************************************************************************ + +Filename : Util_GetSystemSpecs.cpp +Content : This code needs to be shared by applications, but can't be in LibOVR. + Define GET_SYSTEM_SPECS and include directly in a cpp file. +Created : Feb 27, 2015 +Authors : Kevin Jenkins (moved from RiftConfigUtil) + +Copyright : Copyright 2015 Oculus, Inc. All Rights reserved. + +Use of this software is subject to the terms of the Oculus Inc license +agreement provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +*************************************************************************************/ + +#if defined(GET_SYSTEM_SPECS) + +#ifndef WCHAR_TO_OVR_STRING +//Qt redefines wchar_t , but our String has an explicit constructor. Use this hack for desired behavior +#define WCHAR_TO_OVR_STRING(wchar_array) String() + wchar_array +#endif + +#include <QtCore/QMap> +#include <QtCore/QStringList> +#include "Util/Util_SystemInfo.h" + +#if defined(OVR_OS_WIN32) + +#define _WIN32_DCOM +#include <comdef.h> +#include <Wbemidl.h> +# pragma comment(lib, "wbemuuid.lib") +#include "DXGI.h" + +JSON* GetSystemSpecs() +{ + JSON* specs = JSON::CreateObject(); + HRESULT hres; + + IWbemLocator *pLoc = NULL; + + hres = CoCreateInstance( + CLSID_WbemLocator, + 0, + CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID *)&pLoc); + + if (FAILED(hres)) + { + + return specs; // Program has failed. + } + + IWbemServices *pSvc = NULL; + + // Connect to the root\cimv2 namespace with + // the current user and obtain pointer pSvc + // to make IWbemServices calls. + hres = pLoc->ConnectServer( + _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace + NULL, // User name. NULL = current user + NULL, // User password. NULL = current + 0, // Locale. NULL indicates current + NULL, // Security flags. + 0, // Authority (for example, Kerberos) + 0, // Context object + &pSvc // pointer to IWbemServices proxy + ); + + if (FAILED(hres)) + { + + pLoc->Release(); + return specs; // Program has failed. + } + + hres = CoSetProxyBlanket( + pSvc, // Indicates the proxy to set + RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx + RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx + NULL, // Server principal name + RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx + RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx + NULL, // client identity + EOAC_NONE // proxy capabilities + ); + + if (FAILED(hres)) + { + + pSvc->Release(); + pLoc->Release(); + return specs; // Program has failed. + } + + + IEnumWbemClassObject* pEnumerator = NULL; + hres = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT Caption FROM Win32_OperatingSystem"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator); + + if (FAILED(hres)) + { + + pSvc->Release(); + pLoc->Release(); + return specs; // Program has failed. + } + + IWbemClassObject *pclsObj; + ULONG uReturn = 0; + + while (pEnumerator) + { + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, + &pclsObj, &uReturn); + + if (0 == uReturn) + { + break; + } + + VARIANT vtProp; + + // Get the value of the Name property + hr = pclsObj->Get(L"Caption", 0, &vtProp, 0, 0); + specs->AddStringItem("Operating System", WCHAR_TO_OVR_STRING(vtProp.bstrVal)); + VariantClear(&vtProp); + + pclsObj->Release(); + } + pEnumerator = NULL; + hres = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT Name FROM Win32_processor"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator); + + if (FAILED(hres)) + { + + pSvc->Release(); + pLoc->Release(); + return specs; // Program has failed. + } + + uReturn = 0; + while (pEnumerator) + { + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, + &pclsObj, &uReturn); + + if (0 == uReturn) + { + break; + } + + VARIANT vtProp; + + // Get the value of the Name property + hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0); + specs->AddStringItem("Processor", WCHAR_TO_OVR_STRING(vtProp.bstrVal)); + VariantClear(&vtProp); + + pclsObj->Release(); + } + + pEnumerator = NULL; + hres = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT Name , AdapterRam, DriverVersion, VideoModeDescription FROM Win32_VideoController"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator); + + if (FAILED(hres)) + { + + pSvc->Release(); + pLoc->Release(); + return specs; // Program has failed. + } + + JSON* graphicsadapters = JSON::CreateArray(); + + uReturn = 0; + while (pEnumerator) + { + JSON* graphicscard = JSON::CreateObject(); + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, + &pclsObj, &uReturn); + + if (0 == uReturn) + { + break; + } + + VARIANT vtProp; + + // Get the value of the Name property + hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0); + graphicscard->AddStringItem("Name", WCHAR_TO_OVR_STRING(vtProp.bstrVal)); + VariantClear(&vtProp); + + // Get the value of the Name property + hr = pclsObj->Get(L"AdapterRam", 0, &vtProp, 0, 0); + uint32_t capacity = vtProp.uintVal; + graphicscard->AddNumberItem("Video Controller RAM (MB)", capacity / 1048576); + VariantClear(&vtProp); + + //get driver version + hr = pclsObj->Get(L"DriverVersion", 0, &vtProp, 0, 0); + graphicscard->AddStringItem("Driver Version", WCHAR_TO_OVR_STRING(vtProp.bstrVal)); + + //get resolution + hr = pclsObj->Get(L"VideoModeDescription", 0, &vtProp, 0, 0); + graphicscard->AddStringItem("Video Mode", WCHAR_TO_OVR_STRING(vtProp.bstrVal)); + + VariantClear(&vtProp); + pclsObj->Release(); + + graphicsadapters->AddArrayElement(graphicscard); + } + + specs->AddItem("Graphics Adapters", graphicsadapters); + + pEnumerator = NULL; + hres = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT Capacity FROM Win32_PhysicalMemory"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator); + + if (FAILED(hres)) + { + + pSvc->Release(); + pLoc->Release(); + return specs; // Program has failed. + } + + uint64_t totalram = 0; + uReturn = 0; + while (pEnumerator) + { + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, + &pclsObj, &uReturn); + + if (0 == uReturn) + { + break; + } + + VARIANT vtProp; + + // Get the value of the Name property + hr = pclsObj->Get(L"Capacity", 0, &vtProp, 0, 0); + uint64_t capacity = QString::fromWCharArray(vtProp.bstrVal).toLongLong(); + totalram += capacity; + VariantClear(&vtProp); + pclsObj->Release(); + } + + specs->AddNumberItem("Total RAM (GB)", totalram / 1073741824.0); + + JSON* usbtree = JSON::CreateArray(); + + QMap<QString, QStringList> antecedents; + + pEnumerator = NULL; + hres = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT Antecedent,Dependent FROM Win32_USBControllerDevice"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator); + + if (FAILED(hres)) + { + + pSvc->Release(); + pLoc->Release(); + return specs; // Program has failed. + } + + VARIANT vtProp; + + while (pEnumerator) + { + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, + &pclsObj, &uReturn); + + if (0 == uReturn) + { + break; + } + + // Get the reference value of the Antecedent property. There is not a function to dereference the value. + hr = pclsObj->Get(L"Antecedent", 0, &vtProp, 0, 0); + BSTR name = vtProp.bstrVal; + //sanitize the string input to just the output + QString antecedent = QString::fromWCharArray(name).split("=")[1].replace("\"", ""); + VariantClear(&vtProp); + + // Get the reference value of the Dependent property. There is not a function to dereference the value. + hr = pclsObj->Get(L"Dependent", 0, &vtProp, 0, 0); + name = vtProp.bstrVal; + //sanitize the string input to just the output + QString dependent = QString::fromWCharArray(name).split("=")[1].replace("\"", ""); + antecedents[antecedent].append(dependent); + VariantClear(&vtProp); + + } + for (int ant = 0; ant < antecedents.size(); ant++) + { + QString antecedent_name = antecedents.keys()[ant]; + //get antecedent object in a new enumerator + IEnumWbemClassObject* pEnumerator2 = NULL; + IWbemClassObject *pclsObj2; + hres = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT Manufacturer, Name, DeviceID, Caption FROM WIN32_USBController where deviceid = '") + bstr_t(antecedent_name.toUtf8()) + bstr_t("'"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator2); + if (FAILED(hres)) + { + + pSvc->Release(); + pLoc->Release(); + return specs; // Program has failed. + } + + JSON* USBAntecedent = JSON::CreateObject(); + + while (pEnumerator2) + { + HRESULT hr = pEnumerator2->Next(WBEM_INFINITE, 1, + &pclsObj2, &uReturn); + + if (0 == uReturn) + { + break; + } + + VARIANT vtProp; + + // Get the value of the Name property + hr = pclsObj2->Get(L"Name", 0, &vtProp, 0, 0); + USBAntecedent->AddStringItem("name", WCHAR_TO_OVR_STRING(vtProp.bstrVal)); + VariantClear(&vtProp); + + // Get the value of the DeviceID property + hr = pclsObj2->Get(L"DeviceID", 0, &vtProp, 0, 0); + USBAntecedent->AddStringItem("deviceid", WCHAR_TO_OVR_STRING(vtProp.bstrVal)); + VariantClear(&vtProp); + + // Get the value of the caption property + hr = pclsObj2->Get(L"Caption", 0, &vtProp, 0, 0); + USBAntecedent->AddStringItem("caption", WCHAR_TO_OVR_STRING(vtProp.bstrVal)); + VariantClear(&vtProp); + + // Get the value of the manufacturer property + hr = pclsObj2->Get(L"Manufacturer", 0, &vtProp, 0, 0); + USBAntecedent->AddStringItem("manufacturer", WCHAR_TO_OVR_STRING(vtProp.bstrVal)); + VariantClear(&vtProp); + + pclsObj2->Release(); + } + JSON* devices = JSON::CreateArray(); + for (int dev = 0; dev < antecedents[antecedent_name].size(); ++dev) + { + //get antecedent object in a new enumerator + pEnumerator2 = NULL; + if (!pclsObj2) pclsObj2->Release(); + hres = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT Manufacturer,Name FROM Win32_PnPEntity where DeviceID = '") + bstr_t(antecedents[antecedent_name][dev].toUtf8()) + bstr_t("'"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator2); + if (FAILED(hres)) + { + + pSvc->Release(); + pLoc->Release(); + return specs; // Program has failed. + } + + + while (pEnumerator2) + { + HRESULT hr = pEnumerator2->Next(WBEM_INFINITE, 1, + &pclsObj2, &uReturn); + + if (0 == uReturn) + { + break; + } + + VARIANT vtProp; + + JSON* properties = JSON::CreateObject(); + + // Get the value of the Manufacturer property + hr = pclsObj2->Get(L"Manufacturer", 0, &vtProp, 0, 0); + properties->AddStringItem("manufacturer", WCHAR_TO_OVR_STRING(vtProp.bstrVal)); + VariantClear(&vtProp); + + // Get the value of the Manufacturer property + hr = pclsObj2->Get(L"Name", 0, &vtProp, 0, 0); + properties->AddStringItem("name", WCHAR_TO_OVR_STRING(vtProp.bstrVal)); + VariantClear(&vtProp); + + pclsObj2->Release(); + devices->AddArrayElement(properties); + } + } + + USBAntecedent->AddItem("Devices", devices); + usbtree->AddArrayElement(USBAntecedent); + } + + specs->AddItem("USB Tree", usbtree); + + + // Cleanup + // ======== + pSvc->Release(); + pLoc->Release(); + pEnumerator->Release(); + if (!pclsObj) pclsObj->Release(); + return specs; +} +#endif +#ifdef OVR_OS_MAC +JSON* GetSystemSpecs() +{ + return nullptr; +} +#endif +#ifdef OVR_OS_LINUX +JSON* GetSystemSpecs() +{ + return nullptr; +} +#endif + +#endif // GET_SYSTEM_SPECS diff --git a/LibOVRKernel/Src/Util/Util_ImageWindow.cpp b/LibOVRKernel/Src/Util/Util_ImageWindow.cpp new file mode 100644 index 0000000..93a1aa4 --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_ImageWindow.cpp @@ -0,0 +1,591 @@ +/************************************************************************************ + +Filename : Util_ImageWindow.cpp +Content : An output object for windows that can display raw images for testing +Created : March 13, 2014 +Authors : Dean Beeler + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + + +#include "Kernel/OVR_Types.h" + +OVR_DISABLE_ALL_MSVC_WARNINGS() + +#include "Kernel/OVR_Allocator.h" +#include "Kernel/OVR_RefCount.h" +#include "Kernel/OVR_Log.h" +#include "Kernel/OVR_System.h" +#include "Kernel/OVR_Nullptr.h" +#include "Kernel/OVR_String.h" +#include "Kernel/OVR_Array.h" +#include "Kernel/OVR_Timer.h" +#include "Kernel/OVR_SysFile.h" + +#include "Util_ImageWindow.h" + +#if defined(OVR_OS_WIN32) + #include "Kernel/OVR_Win32_IncludeWindows.h" + #include "DWrite.h" +#endif + +OVR_RESTORE_ALL_MSVC_WARNINGS() + + +#if defined(OVR_OS_WIN32) + +typedef HRESULT (WINAPI *D2D1CreateFactoryFn)( + _In_ D2D1_FACTORY_TYPE, + _In_ REFIID, + _In_opt_ const D2D1_FACTORY_OPTIONS*, + _Out_ ID2D1Factory ** + ); + +typedef HRESULT (WINAPI *DWriteCreateFactoryFn)( + _In_ DWRITE_FACTORY_TYPE factoryType, + _In_ REFIID iid, + _Out_ IUnknown **factory + ); + + +namespace OVR { namespace Util { + +ID2D1Factory* ImageWindow::pD2DFactory = NULL; +IDWriteFactory* ImageWindow::pDWriteFactory = NULL; +HINSTANCE ImageWindow::hInstD2d1 = NULL; +HINSTANCE ImageWindow::hInstDwrite = NULL; + + +// TODO(review): This appears to be (at present) necessary, the global list is accessed by the +// render loop in Samples. In the current version, windows will just be lost when windowCount +// exceeds MaxWindows; I've left that in place, since this is unfamiliar code. I'm not sure what +// thread-safety guarantees this portion of the code needs to satisfy, so I don't want to +// change it to a list or whatever. Asserts added to catch the error. +ImageWindow* ImageWindow::globalWindow[ImageWindow::MaxWindows]; +int ImageWindow::windowCount = 0; + +LRESULT CALLBACK MainWndProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + return 0; + + case WM_PAINT: + { + LONG_PTR ptr = GetWindowLongPtr( hwnd, GWLP_USERDATA ); + if( ptr ) + { + ImageWindow* iw = (ImageWindow*)ptr; + iw->OnPaint(); + } + } + + return 0; + + case WM_SIZE: + // Set the size and position of the window. + return 0; + + case WM_DESTROY: + // Clean up window-specific data objects. + return 0; + + // + // Process other messages. + // + + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + //return 0; +} + + +ImageWindow::ImageWindow( uint32_t width, uint32_t height ) : + hWindow(NULL), + pRT(NULL), + //resolution(), + frontBufferMutex( new Mutex() ), + frames(), + greyBitmap(NULL), + colorBitmap(NULL) +{ + D2D1CreateFactoryFn createFactory = NULL; + DWriteCreateFactoryFn writeFactory = NULL; + + if (!hInstD2d1) + { + hInstD2d1 = LoadLibraryW( L"d2d1.dll" ); + } + + if (!hInstD2d1) + { + hInstD2d1 = LoadLibraryW( L"Dwrite.dll" ); + } + + if( hInstD2d1 ) + { + createFactory = (D2D1CreateFactoryFn)GetProcAddress( hInstD2d1, "D2D1CreateFactory" ); + } + + if( hInstDwrite ) + { + writeFactory = (DWriteCreateFactoryFn)GetProcAddress( hInstDwrite, "DWriteCreateFactory" ); + } + + // TODO: see note where globalWindow is declared. + globalWindow[windowCount++ % MaxWindows] = this; + OVR_ASSERT(windowCount < MaxWindows); + + if( pD2DFactory == NULL && createFactory && writeFactory ) + { + // Create a Direct2D factory. + HRESULT hResult = createFactory( + D2D1_FACTORY_TYPE_MULTI_THREADED, + __uuidof(ID2D1Factory), + NULL, + &pD2DFactory // This will be AddRef'd for us. + ); + OVR_ASSERT_AND_UNUSED(hResult == S_OK, hResult); + + // Create a DirectWrite factory. + hResult = writeFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(pDWriteFactory), // This probably should instead be __uuidof(IDWriteFactory) + reinterpret_cast<IUnknown **>(&pDWriteFactory) // This will be AddRef'd for us. + ); + OVR_ASSERT_AND_UNUSED(hResult == S_OK, hResult); + } + + resolution = D2D1::SizeU( width, height ); + + if (hWindow) + { + SetWindowLongPtr( hWindow, GWLP_USERDATA, (LONG_PTR)this ); + } +} + +ImageWindow::~ImageWindow() +{ + for( int i = 0; i < MaxWindows; ++i ) + { + if( globalWindow[i] == this ) + { + globalWindow[i] = NULL; + break; + } + } + + if( greyBitmap ) + greyBitmap->Release(); + + if( colorBitmap ) + colorBitmap->Release(); + + if( pRT ) + pRT->Release(); + + { + Mutex::Locker locker( frontBufferMutex ); + + while( frames.GetSize() ) + { + Ptr<Frame> aFrame = frames.PopBack(); + } + } + + delete frontBufferMutex; + + if (hWindow) + { + ShowWindow( hWindow, SW_HIDE ); + DestroyWindow( hWindow ); + } + + if (pD2DFactory) + { + pD2DFactory->Release(); + pD2DFactory = NULL; + } + + if (pDWriteFactory) + { + pDWriteFactory->Release(); + pDWriteFactory = NULL; + } + + if( hInstD2d1 ) + { + FreeLibrary(hInstD2d1); + hInstD2d1 = NULL; + } + + if( hInstDwrite ) + { + FreeLibrary(hInstDwrite); + hInstDwrite = NULL; + } +} + +void ImageWindow::AssociateSurface( void* surface ) +{ + if (pD2DFactory) + { + // Assume an IUnknown + IUnknown* unknown = (IUnknown*)surface; + + IDXGISurface *pDxgiSurface = NULL; + HRESULT hr = unknown->QueryInterface(&pDxgiSurface); + if( hr == S_OK ) + { + D2D1_RENDER_TARGET_PROPERTIES props = + D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED), + 96, + 96 + ); + + pRT = NULL; + ID2D1RenderTarget* tmpTarget; + + hr = pD2DFactory->CreateDxgiSurfaceRenderTarget( pDxgiSurface, &props, &tmpTarget ); + + if( hr == S_OK ) + { + DXGI_SURFACE_DESC desc = {0}; + pDxgiSurface->GetDesc( &desc ); + int width = desc.Width; + int height = desc.Height; + + D2D1_SIZE_U size = D2D1::SizeU( width, height ); + + D2D1_PIXEL_FORMAT pixelFormat = D2D1::PixelFormat( + DXGI_FORMAT_A8_UNORM, + D2D1_ALPHA_MODE_PREMULTIPLIED + ); + + D2D1_PIXEL_FORMAT colorPixelFormat = D2D1::PixelFormat( + DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_PREMULTIPLIED + ); + + D2D1_BITMAP_PROPERTIES bitmapProps; + bitmapProps.dpiX = 96; + bitmapProps.dpiY = 96; + bitmapProps.pixelFormat = pixelFormat; + + D2D1_BITMAP_PROPERTIES colorBitmapProps; + colorBitmapProps.dpiX = 96; + colorBitmapProps.dpiY = 96; + colorBitmapProps.pixelFormat = colorPixelFormat; + + HRESULT result = tmpTarget->CreateBitmap( size, bitmapProps, &greyBitmap ); + if( result != S_OK ) + { + tmpTarget->Release(); + tmpTarget = NULL; + } + + if (tmpTarget) + { + result = tmpTarget->CreateBitmap(size, colorBitmapProps, &colorBitmap); + if (result != S_OK) + { + tmpTarget->Release(); + tmpTarget = NULL; + } + } + pRT = tmpTarget; + } + } + } +} + +void ImageWindow::Process() +{ + if( pRT && greyBitmap ) + { + OnPaint(); + + pRT->Flush(); + } +} + +void ImageWindow::Complete() +{ + Mutex::Locker locker( frontBufferMutex ); + + if( frames.IsEmpty() ) + return; + + if( frames.PeekBack(0)->ready ) + return; + + Ptr<Frame> frame = frames.PeekBack(0); + + frame->ready = true; +} + +void ImageWindow::OnPaint() +{ + Mutex::Locker locker( frontBufferMutex ); + + // Nothing to do + if( frames.IsEmpty() ) + return; + + if( !frames.PeekFront(0)->ready ) + return; + + Ptr<Frame> currentFrame = frames.PopFront(); + + Ptr<Frame> nextFrame = NULL; + + if( !frames.IsEmpty() ) + nextFrame = frames.PeekFront(0); + + while( nextFrame && nextFrame->ready ) + { + // Free up the current frame since it's been removed from the deque + currentFrame = frames.PopFront(); + + if( frames.IsEmpty() ) + break; + + nextFrame = frames.PeekFront(0); + } + + if( currentFrame->imageData ) + greyBitmap->CopyFromMemory( NULL, currentFrame->imageData, currentFrame->width ); + + if( currentFrame->colorImageData ) + colorBitmap->CopyFromMemory( NULL, currentFrame->colorImageData, currentFrame->colorPitch ); + + pRT->BeginDraw(); + + pRT->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); + + pRT->Clear( D2D1::ColorF(D2D1::ColorF::Black) ); + + // This will mirror our image + D2D1_MATRIX_3X2_F m; + m._11 = -1; m._12 = 0; + m._21 = 0; m._22 = 1; + m._31 = 0; m._32 = 0; + pRT->SetTransform( m ); + + ID2D1SolidColorBrush* whiteBrush; + + pRT->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::White, 1.0f), &whiteBrush ); + + if( currentFrame->imageData ) + { + pRT->FillOpacityMask( greyBitmap, whiteBrush, + D2D1_OPACITY_MASK_CONTENT_TEXT_NATURAL, + D2D1::RectF( -(FLOAT)resolution.width, 0.0f, (FLOAT)0.0f, (FLOAT)resolution.height ), + //D2D1::RectF( 0.0f, 0.0f, (FLOAT)0.0f, (FLOAT)resolution.height ), + D2D1::RectF( 0.0f, 0.0f, (FLOAT)resolution.width, (FLOAT)resolution.height ) ); + } + else if( currentFrame->colorImageData ) + { + pRT->DrawBitmap( colorBitmap, + D2D1::RectF( -(FLOAT)resolution.width, 0.0f, (FLOAT)0.0f, (FLOAT)resolution.height ) ); + + } + + pRT->SetTransform(D2D1::Matrix3x2F::Identity()); + + whiteBrush->Release(); + + Array<CirclePlot>::Iterator it; + + for( it = currentFrame->plots.Begin(); it != currentFrame->plots.End(); ++it ) + { + ID2D1SolidColorBrush* aBrush; + + pRT->CreateSolidColorBrush( D2D1::ColorF( it->r, it->g, it->b), &aBrush ); + + D2D1_ELLIPSE ellipse; + ellipse.point.x = it->x; + ellipse.point.y = it->y; + ellipse.radiusX = it->radius; + ellipse.radiusY = it->radius; + + if( it->fill ) + pRT->FillEllipse( &ellipse, aBrush ); + else + pRT->DrawEllipse( &ellipse, aBrush ); + + aBrush->Release(); + } + + static const WCHAR msc_fontName[] = L"Verdana"; + static const FLOAT msc_fontSize = 20; + + IDWriteTextFormat* textFormat = NULL; + + // Create a DirectWrite text format object. + pDWriteFactory->CreateTextFormat( + msc_fontName, + NULL, + DWRITE_FONT_WEIGHT_NORMAL, + DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, + msc_fontSize, + L"", //locale + &textFormat + ); + + D2D1_SIZE_F renderTargetSize = pRT->GetSize(); + + Array<TextPlot>::Iterator textIt; + for( textIt = currentFrame->textLines.Begin(); textIt != currentFrame->textLines.End(); ++textIt ) + { + ID2D1SolidColorBrush* aBrush; + + pRT->CreateSolidColorBrush( D2D1::ColorF( textIt->r, textIt->g, textIt->b), &aBrush ); + + WCHAR* tmpString = (WCHAR*)calloc( textIt->text.GetLength(), sizeof( WCHAR ) ); + for( unsigned i = 0; i < textIt->text.GetLength(); ++i ) + { + tmpString[i] = (WCHAR)textIt->text.GetCharAt( i ); + } + + pRT->DrawText( tmpString, (UINT32)textIt->text.GetLength(), textFormat, + D2D1::RectF(textIt->x, textIt->y, renderTargetSize.width, renderTargetSize.height), aBrush ); + + free( tmpString ); + + aBrush->Release(); + } + + if( textFormat ) + textFormat->Release(); + + pRT->EndDraw(); + + pRT->Flush(); +} + +Ptr<Frame> ImageWindow::lastUnreadyFrame() +{ + static int framenumber = 0; + + if( frames.GetSize() && !frames.PeekBack( 0 )->ready ) + return frames.PeekBack( 0 ); + + // Create a new frame if an unready one doesn't already exist + Ptr<Frame> tmpFrame = *new Frame( framenumber ); + frames.PushBack( tmpFrame ); + + ++framenumber; + + return tmpFrame; +} + +void ImageWindow::UpdateImageBW( const uint8_t* imageData, uint32_t width, uint32_t height ) +{ + if( pRT && greyBitmap ) + { + Mutex::Locker locker( frontBufferMutex ); + + Ptr<Frame> frame = lastUnreadyFrame(); + frame->imageData = malloc( width * height ); + frame->width = width; + frame->height = height; + memcpy( frame->imageData, imageData, width * height ); + } +} + +void ImageWindow::UpdateImageRGBA( const uint8_t* imageData, uint32_t width, uint32_t height, uint32_t pitch ) +{ + if( pRT && colorBitmap ) + { + Mutex::Locker locker( frontBufferMutex ); + + Ptr<Frame> frame = lastUnreadyFrame(); + frame->colorImageData = malloc( pitch * height ); + frame->width = width; + frame->height = height; + frame->colorPitch = pitch; + memcpy( frame->colorImageData, imageData, pitch * height ); + } +} + +void ImageWindow::addCircle( float x, float y, float radius, float r, float g, float b, bool fill ) +{ + if( pRT ) + { + CirclePlot cp; + + cp.x = x; + cp.y = y; + cp.radius = radius; + cp.r = r; + cp.g = g; + cp.b = b; + cp.fill = fill; + + Mutex::Locker locker( frontBufferMutex ); + + Ptr<Frame> frame = lastUnreadyFrame(); + frame->plots.PushBack( cp ); + } + +} + +void ImageWindow::addText( float x, float y, float r, float g, float b, OVR::String text ) +{ + if( pRT ) + { + TextPlot tp; + + tp.x = x; + tp.y = y; + tp.r = r; + tp.g = g; + tp.b = b; + tp.text = text; + + Mutex::Locker locker( frontBufferMutex ); + Ptr<Frame> frame = lastUnreadyFrame(); + frame->textLines.PushBack( tp ); + } +} + +}} + +#else //defined(OVR_OS_WIN32) + +namespace OVR { namespace Util { + +ImageWindow* ImageWindow::globalWindow[4]; +int ImageWindow::windowCount = 0; + +}} + +#endif //#else //defined(OVR_OS_WIN32) + diff --git a/LibOVRKernel/Src/Util/Util_ImageWindow.h b/LibOVRKernel/Src/Util/Util_ImageWindow.h new file mode 100644 index 0000000..9874178 --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_ImageWindow.h @@ -0,0 +1,201 @@ +/************************************************************************************ + +Filename : Util_ImageWindow.h +Content : An output object for windows that can display raw images for testing +Created : March 13, 2014 +Authors : Dean Beeler + +Copyright : Copyright 2014 Oculus, Inc. All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#ifndef OVR_Util_ImageWindow_h +#define OVR_Util_ImageWindow_h + +#if defined(OVR_OS_WIN32) +#include "Kernel/OVR_Win32_IncludeWindows.h" +#include <d2d1.h> +#include <dwrite.h> +#endif + +#include "Kernel/OVR_Hash.h" +#include "Kernel/OVR_Array.h" +#include "Kernel/OVR_Threads.h" +#include "Kernel/OVR_Deque.h" + +#include <stdint.h> + +namespace OVR { namespace Util { + +typedef struct +{ + float x; + float y; + float radius; + float r; + float g; + float b; + bool fill; +} CirclePlot; + +typedef struct +{ + float x; + float y; + float r; + float g; + float b; +OVR::String text; +} TextPlot; + +class Frame : virtual public RefCountBaseV<Frame> +{ +public: + + Frame( int frame ) : + frameNumber( frame ), + plots(), + textLines(), + imageData( NULL ), + colorImageData( NULL ), + width( 0 ), + height( 0 ), + colorPitch( 0 ), + ready( false ) + { + + } + + ~Frame() + { + if( imageData ) + free( imageData ); + if( colorImageData ) + free( colorImageData ); + + plots.ClearAndRelease(); + textLines.ClearAndRelease(); + } + + int frameNumber; + + Array<CirclePlot> plots; + Array<TextPlot> textLines; + void* imageData; + void* colorImageData; + int width; + int height; + int colorPitch; + bool ready; +}; + +#if defined(OVR_OS_WIN32) +class ImageWindow +{ + HWND hWindow; + ID2D1RenderTarget* pRT; + D2D1_SIZE_U resolution; + + Mutex* frontBufferMutex; + + InPlaceMutableDeque< Ptr<Frame> > frames; + + ID2D1Bitmap* greyBitmap; + ID2D1Bitmap* colorBitmap; + +public: + // constructors + ImageWindow(); + ImageWindow( uint32_t width, uint32_t height ); + virtual ~ImageWindow(); + + void GetResolution( size_t& width, size_t& height ) { width = resolution.width; height = resolution.height; } + + void OnPaint(); // Called by Windows when it receives a WM_PAINT message + + void UpdateImage( const uint8_t* imageData, uint32_t width, uint32_t height ) { UpdateImageBW( imageData, width, height ); } + void UpdateImageBW( const uint8_t* imageData, uint32_t width, uint32_t height ); + void UpdateImageRGBA( const uint8_t* imageData, uint32_t width, uint32_t height, uint32_t pitch ); + void Complete(); // Called by drawing thread to submit a frame + + void Process(); // Called by rendering thread to do window processing + + void AssociateSurface( void* surface ); + + void addCircle( float x , float y, float radius, float r, float g, float b, bool fill ); + void addText( float x, float y, float r, float g, float b, OVR::String text ); + + static ImageWindow* GlobalWindow( int window ) { return globalWindow[window]; } + static int WindowCount() { return windowCount; } + +private: + + Ptr<Frame> lastUnreadyFrame(); + + static const int MaxWindows = 4; + static ImageWindow* globalWindow[MaxWindows]; + static int windowCount; + static ID2D1Factory* pD2DFactory; + static IDWriteFactory* pDWriteFactory; + static HINSTANCE hInstD2d1; + static HINSTANCE hInstDwrite; + +}; + +#else + +class ImageWindow +{ +public: + // constructors + ImageWindow() {} + ImageWindow( uint32_t width, uint32_t height ) { OVR_UNUSED( width ); OVR_UNUSED( height ); } + virtual ~ImageWindow() { } + + void GetResolution( size_t& width, size_t& height ) { width = 0; height = 0; } + + void OnPaint() { } + + void UpdateImage( const uint8_t* imageData, uint32_t width, uint32_t height ) { UpdateImageBW( imageData, width, height ); } + void UpdateImageBW( const uint8_t* imageData, uint32_t width, uint32_t height ) { OVR_UNUSED( imageData ); OVR_UNUSED( width ); OVR_UNUSED( height ); } + void UpdateImageRGBA( const uint8_t* imageData, uint32_t width, uint32_t height, uint32_t pitch ) { OVR_UNUSED( imageData ); OVR_UNUSED( width ); OVR_UNUSED( height ); OVR_UNUSED( pitch ); } + void Complete() { } + + void Process() { } + + void AssociateSurface( void* surface ) { OVR_UNUSED(surface); } + + void addCircle( float x , float y, float radius, float r, float g, float b, bool fill ) { OVR_UNUSED( x ); OVR_UNUSED( y ); OVR_UNUSED( radius ); OVR_UNUSED( r ); OVR_UNUSED( g ); OVR_UNUSED( b ); OVR_UNUSED( fill ); } + void addText( float x, float y, float r, float g, float b, OVR::String text ) { OVR_UNUSED( x ); OVR_UNUSED( y ); OVR_UNUSED( r ); OVR_UNUSED( g ); OVR_UNUSED( b ); OVR_UNUSED( text ); } + + static ImageWindow* GlobalWindow( int window ) { return globalWindow[window]; } + static int WindowCount() { return windowCount; } + +private: + + static const int MaxWindows = 4; + static ImageWindow* globalWindow[4]; + static int windowCount; +}; + +#endif + +}} // namespace OVR::Util + + +#endif diff --git a/LibOVRKernel/Src/Util/Util_LongPollThread.cpp b/LibOVRKernel/Src/Util/Util_LongPollThread.cpp new file mode 100644 index 0000000..4feffc1 --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_LongPollThread.cpp @@ -0,0 +1,97 @@ +/************************************************************************************ + +Filename : Util_LongPollThread.cpp +Content : Allows us to do all long polling tasks from a single thread to minimize deadlock risk +Created : June 30, 2013 +Authors : Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#include "Util_LongPollThread.h" +#include "Util_Watchdog.h" + +OVR_DEFINE_SINGLETON(OVR::Util::LongPollThread); + +namespace OVR { namespace Util { + + +void LongPollThread::AddPollFunc(CallbackListener<PollFunc>* func) +{ + PollSubject.AddListener(func); +} + +LongPollThread::LongPollThread() : + Terminated(false) +{ + Start(); + + // Must be at end of function + PushDestroyCallbacks(); +} + +LongPollThread::~LongPollThread() +{ + fireTermination(); + + Join(); +} + +void LongPollThread::OnThreadDestroy() +{ + fireTermination(); +} + +void LongPollThread::Wake() +{ + WakeEvent.SetEvent(); +} + +void LongPollThread::fireTermination() +{ + Terminated = true; + Wake(); +} + +void LongPollThread::OnSystemDestroy() +{ + Release(); +} + +int LongPollThread::Run() +{ + SetThreadName("LongPoll"); + WatchDog watchdog("LongPoll"); + + // While not terminated, + do + { + watchdog.Feed(10000); + + PollSubject.Call(); + + WakeEvent.Wait(WakeupInterval); + WakeEvent.ResetEvent(); + } while (!Terminated); + + return 0; +} + + +}} // namespace OVR::Util diff --git a/LibOVRKernel/Src/Util/Util_LongPollThread.h b/LibOVRKernel/Src/Util/Util_LongPollThread.h new file mode 100644 index 0000000..ac89781 --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_LongPollThread.h @@ -0,0 +1,72 @@ +/************************************************************************************ + +Filename : Util_LongPollThread.h +Content : Allows us to do all long polling tasks from a single thread to minimize deadlock risk +Created : June 30, 2013 +Authors : Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#ifndef OVR_Util_LongPollThread_h +#define OVR_Util_LongPollThread_h + +#include "Kernel/OVR_Timer.h" +#include "Kernel/OVR_Atomic.h" +#include "Kernel/OVR_Allocator.h" +#include "Kernel/OVR_String.h" +#include "Kernel/OVR_System.h" +#include "Kernel/OVR_Threads.h" +#include "Kernel/OVR_Callbacks.h" + +namespace OVR { namespace Util { + + +//----------------------------------------------------------------------------- +// LongPollThread + +// This thread runs long-polling subsystems that wake up every second or so +// The motivation is to reduce the number of threads that are running to minimize the risk of deadlock +class LongPollThread : public Thread, public SystemSingletonBase<LongPollThread> +{ + OVR_DECLARE_SINGLETON(LongPollThread); + virtual void OnThreadDestroy(); + +public: + typedef Delegate0<void> PollFunc; + static const int WakeupInterval = 1000; // milliseconds + + void AddPollFunc(CallbackListener<PollFunc>* func); + + void Wake(); + +protected: + CallbackEmitter<PollFunc> PollSubject; + + bool Terminated; + Event WakeEvent; + void fireTermination(); + + virtual int Run(); +}; + + +}} // namespace OVR::Util + +#endif // OVR_Util_LongPollThread_h diff --git a/LibOVRKernel/Src/Util/Util_SystemGUI.cpp b/LibOVRKernel/Src/Util/Util_SystemGUI.cpp new file mode 100644 index 0000000..ffab71e --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_SystemGUI.cpp @@ -0,0 +1,239 @@ +/************************************************************************************ + +Filename : Util_SystemGUI.cpp +Content : OS GUI access, usually for diagnostics. +Created : October 20, 2014 +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#include "Util_SystemGUI.h" + +#include "Kernel/OVR_UTF8Util.h" +#if defined(OVR_OS_WIN32) + #include "Kernel/OVR_Win32_IncludeWindows.h" +#endif // OVR_OS_WIN32 +#include "Kernel/OVR_Std.h" +#include <stdio.h> +#include <stdarg.h> + + +namespace OVR { namespace Util { + + +static bool DisplayMessageBoxVaList(const char* pTitle, const char* pFormat, va_list argList) +{ + char buffer[512]; + char* pBuffer = buffer; + char* pAllocated = nullptr; + + va_list argListSaved; + OVR_VA_COPY(argListSaved, argList); + + int result = OVR_vsnprintf(buffer, OVR_ARRAY_COUNT(buffer), pFormat, argList); // Returns the required strlen of buffer. + + if(result >= (int)OVR_ARRAY_COUNT(buffer)) // If there was insufficient capacity... + { + pAllocated = new char[result + 1]; + pBuffer = pAllocated; + + va_end(argList); // The caller owns argList and will call va_end on it. + OVR_VA_COPY(argList, argListSaved); + + OVR_vsnprintf(pBuffer, (size_t)result + 1, pFormat, argList); + } + + bool returnValue = DisplayMessageBox(pTitle, pBuffer); + + delete[] pAllocated; // OK if it's nullptr. + + return returnValue; +} + + +bool DisplayMessageBoxF(const char* pTitle, const char* pFormat, ...) +{ + va_list argList; + va_start(argList, pFormat); + bool returnValue = DisplayMessageBoxVaList(pTitle, pFormat, argList); + va_end(argList); + return returnValue; +} + + + +#if defined(OVR_OS_MS) + +// On Windows we implement a manual dialog message box. The reason for this is that there's no way to +// have a message box like this without either using MFC or WinForms or relying on Windows Vista+. + +bool DisplayMessageBox(const char* pTitle, const char* pText) +{ + #define ID_EDIT 100 + + struct Dialog + { + static size_t LineCount(const char* pText) + { + size_t count = 0; + while(*pText) + { + if(*pText++ == '\n') + count++; + } + return count; + } + + static WORD* WordUp(WORD* pIn){ return (WORD*)((((uintptr_t)pIn + 3) >> 2) << 2); } + + static BOOL CALLBACK Proc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) + { + switch (iMsg) + { + case WM_INITDIALOG: + { + HWND hWndEdit = GetDlgItem(hDlg, ID_EDIT); + + const char* pText = (const char*)lParam; + SetWindowTextA(hWndEdit, pText); + + HFONT hFont = CreateFontW(-11, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, L"Courier New"); + if(hFont) + SendMessage(hWndEdit, WM_SETFONT, WPARAM(hFont), TRUE); + + SendMessage(hWndEdit, EM_SETSEL, (WPARAM)0, (LPARAM)0); + + return TRUE; + } + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case ID_EDIT: + { + // Handle messages from the edit control here. + HWND hWndEdit = GetDlgItem(hDlg, ID_EDIT); + SendMessage(hWndEdit, EM_SETSEL, (WPARAM)0, (LPARAM)0); + return TRUE; + } + + case IDOK: + EndDialog(hDlg, 0); + return TRUE; + } + break; + case WM_CLOSE: + + EndDialog(hDlg, 0); + return TRUE; + } + + return FALSE; + } + }; + + + char dialogTemplateMemory[1024]; + memset(dialogTemplateMemory, 0, sizeof(dialogTemplateMemory)); + DLGTEMPLATE* pDlg = (LPDLGTEMPLATE)dialogTemplateMemory; + + const size_t textLength = strlen(pText); + const size_t textLineCount = Dialog::LineCount(pText); + + // Sizes are in Windows dialog units, which are relative to a character size. Depends on the font and environment settings. Often the pixel size will be ~3x the dialog unit x size. Often the pixel size will be ~3x the dialog unit y size. + const int kGutterSize = 6; // Empty border space around controls within the dialog + const int kButtonWidth = 24; + const int kButtonHeight = 10; + const int kDialogWidth = ((textLength > 1000) ? 600 : ((textLength > 400) ? 300 : 200)); // To do: Clip this against screen bounds. + const int kDialogHeight = ((textLineCount > 100) ? 400 : ((textLineCount > 25) ? 300 : ((textLineCount > 10) ? 200 : 100))); + + // Define a dialog box. + pDlg->style = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION; + pDlg->cdit = 2; // Control count + pDlg->x = 10; // X position To do: Center the dialog. + pDlg->y = 10; + pDlg->cx = (short)kDialogWidth; + pDlg->cy = (short)kDialogHeight; + WORD* pWord = (WORD*)(pDlg + 1); + *pWord++ = 0; // No menu + *pWord++ = 0; // Default dialog box class + + WCHAR* pWchar = (WCHAR*)pWord; + const size_t titleLength = strlen(pTitle); + size_t wcharCount = OVR::UTF8Util::DecodeString(pWchar, pTitle, (titleLength > 128) ? 128 : titleLength); + pWord += wcharCount + 1; + + // Define an OK button. + pWord = Dialog::WordUp(pWord); + + DLGITEMTEMPLATE* pDlgItem = (DLGITEMTEMPLATE*)pWord; + pDlgItem->x = pDlg->cx - (kGutterSize + kButtonWidth); + pDlgItem->y = pDlg->cy - (kGutterSize + kButtonHeight); + pDlgItem->cx = kButtonWidth; + pDlgItem->cy = kButtonHeight; + pDlgItem->id = IDOK; + pDlgItem->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + pWord = (WORD*)(pDlgItem + 1); + *pWord++ = 0xFFFF; + *pWord++ = 0x0080; // button class + + pWchar = (WCHAR*)pWord; + pWchar[0] = 'O'; pWchar[1] = 'K'; pWchar[2] = '\0'; // Not currently localized. + pWord += 3; // OK\0 + *pWord++ = 0; // no creation data + + // Define an EDIT contol. + pWord = Dialog::WordUp(pWord); + + pDlgItem = (DLGITEMTEMPLATE*)pWord; + pDlgItem->x = kGutterSize; + pDlgItem->y = kGutterSize; + pDlgItem->cx = pDlg->cx - (kGutterSize + kGutterSize); + pDlgItem->cy = pDlg->cy - (kGutterSize + kButtonHeight + kGutterSize + (kGutterSize / 2)); + pDlgItem->id = ID_EDIT; + pDlgItem->style = ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | ES_READONLY | WS_VSCROLL | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE; + + pWord = (WORD*)(pDlgItem + 1); + *pWord++ = 0xFFFF; + *pWord++ = 0x0081; // edit class atom + *pWord++ = 0; // no creation data + + LRESULT ret = DialogBoxIndirectParam(NULL, (LPDLGTEMPLATE)pDlg, NULL, (DLGPROC)Dialog::Proc, (LPARAM)pText); + + return (ret != 0); +} + +#elif defined(OVR_OS_MAC) + +// For Apple we use the Objective C implementation in Util_GUI.mm + +#else + +// To do. +bool DisplayMessageBox(const char* pTitle, const char* pText) +{ + printf("\n\nMessageBox\n%s\n", pTitle); + printf("%s\n\n", pText); + return false; +} + +#endif + + +}} // namespace OVR::Util diff --git a/LibOVRKernel/Src/Util/Util_SystemGUI.h b/LibOVRKernel/Src/Util/Util_SystemGUI.h new file mode 100644 index 0000000..1cf99a2 --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_SystemGUI.h @@ -0,0 +1,40 @@ +/************************************************************************************ + +Filename : Util_SystemGUI.h +Content : OS GUI access, usually for diagnostics. +Created : October 20, 2014 +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#ifndef OVR_Util_GUI_h +#define OVR_Util_GUI_h + + +namespace OVR { namespace Util { + + // Displays a modal message box on the default GUI display (not on a VR device). + // The message box interface (e.g. OK button) is not localized. + bool DisplayMessageBox(const char* pTitle, const char* pText); + + bool DisplayMessageBoxF(const char* pTitle, const char* pFormat, ...); + +} } // namespace OVR::Util + + +#endif diff --git a/LibOVRKernel/Src/Util/Util_SystemGUI_OSX.mm b/LibOVRKernel/Src/Util/Util_SystemGUI_OSX.mm new file mode 100644 index 0000000..cbfd057 --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_SystemGUI_OSX.mm @@ -0,0 +1,69 @@ +/************************************************************************************
+
+Filename : Util_SystemGUI.mm
+Content : OS GUI access, usually for diagnostics.
+Created : October 20, 2014
+Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.2
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*************************************************************************************/
+
+
+
+#include "Util_SystemGUI.h"
+
+#include <Cocoa/Cocoa.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+
+namespace OVR { namespace Util {
+
+
+bool DisplayMessageBox(const char* pTitle, const char* pText)
+{
+ // To consider: Replace usage of CFUserNotificationDisplayAlert with something a little smarter.
+
+ size_t titleLength = strlen(pTitle);
+ size_t textLength = strlen(pText);
+ if(textLength > 1500) // CFUserNotificationDisplayAlert isn't smart enough to handle large text sizes and screws up its size if so.
+ textLength = 1500; // Problem: this can theoretically split a UTF8 multibyte sequence. Need to find a divisible boundary.
+ CFAllocatorRef allocator = NULL; // To do: support alternative allocator.
+ CFStringRef titleRef = CFStringCreateWithBytes(allocator, (const UInt8*)pTitle, (CFIndex)titleLength, kCFStringEncodingUTF8, false);
+ CFStringRef textRef = CFStringCreateWithBytes(allocator, (const UInt8*)pText, (CFIndex)textLength, kCFStringEncodingUTF8, false);
+ CFOptionFlags result;
+
+ CFUserNotificationDisplayAlert(0, // No timeout
+ kCFUserNotificationNoteAlertLevel,
+ NULL, // Icon URL, use default.
+ NULL, // Unused
+ NULL, // Localization of strings
+ titleRef, // Title text
+ textRef, // Body text
+ CFSTR("OK"), // Default "OK" text in button
+ CFSTR("Cancel"), // Other button title
+ NULL, // Yet another button title, NULL means no other button.
+ &result); // response flags
+ CFRelease(titleRef);
+ CFRelease(textRef);
+
+ return (result == kCFUserNotificationDefaultResponse);
+}
+
+
+} } // namespace OVR { namespace Util {
+
+
diff --git a/LibOVRKernel/Src/Util/Util_SystemInfo.cpp b/LibOVRKernel/Src/Util/Util_SystemInfo.cpp new file mode 100644 index 0000000..5ebdf65 --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_SystemInfo.cpp @@ -0,0 +1,416 @@ +/************************************************************************************ + +Filename : Util_SystemInfo.cpp +Content : Various operations to get information about the system +Created : September 26, 2014 +Author : Kevin Jenkins + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +#include "Util_SystemInfo.h" +#include "Kernel/OVR_Timer.h" +#include "Kernel/OVR_Threads.h" +#include "Kernel/OVR_Log.h" +#include "Kernel/OVR_Array.h" + +#if defined(OVR_OS_LINUX) +#include <sys/utsname.h> +#endif + +/* +// Disabled, can't link RiftConfigUtil +#ifdef OVR_OS_WIN32 +#define _WIN32_DCOM +#include <comdef.h> +#include <Wbemidl.h> + +# pragma comment(lib, "wbemuuid.lib") +#endif +*/ + + +namespace OVR { namespace Util { + +// From http://blogs.msdn.com/b/oldnewthing/archive/2005/02/01/364563.aspx +#if defined (OVR_OS_WIN64) || defined (OVR_OS_WIN32) + +#pragma comment(lib, "version.lib") + +typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); +BOOL Is64BitWindows() +{ +#if defined(_WIN64) + return TRUE; // 64-bit programs run only on Win64 +#elif defined(_WIN32) + // 32-bit programs run on both 32-bit and 64-bit Windows + // so must sniff + BOOL f64 = FALSE; + LPFN_ISWOW64PROCESS fnIsWow64Process; + + fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process"); + if (NULL != fnIsWow64Process) + { + return fnIsWow64Process(GetCurrentProcess(), &f64) && f64; + } + return FALSE; +#else + return FALSE; // Win64 does not support Win16 +#endif +} +#endif + +const char * OSAsString() +{ +#if defined (OVR_OS_IPHONE) + return "IPhone"; +#elif defined (OVR_OS_DARWIN) + return "Darwin"; +#elif defined (OVR_OS_MAC) + return "Mac"; +#elif defined (OVR_OS_BSD) + return "BSD"; +#elif defined (OVR_OS_WIN64) || defined (OVR_OS_WIN32) + if (Is64BitWindows()) + return "Win64"; + else + return "Win32"; +#elif defined (OVR_OS_ANDROID) + return "Android"; +#elif defined (OVR_OS_LINUX) + return "Linux"; +#elif defined (OVR_OS_BSD) + return "BSD"; +#else + return "Other"; +#endif +} + +uint64_t GetGuidInt() +{ + uint64_t g = Timer::GetTicksNanos(); + + uint64_t lastTime, thisTime; + int j; + // Sleep a small random time, then use the last 4 bits as a source of randomness + for (j = 0; j < 8; j++) + { + lastTime = Timer::GetTicksNanos(); + Thread::MSleep(1); + Thread::MSleep(0); + thisTime = Timer::GetTicksNanos(); + uint64_t diff = thisTime - lastTime; + unsigned int diff4Bits = (unsigned int)(diff & 15); + diff4Bits <<= 32 - 4; + diff4Bits >>= j * 4; + ((char*)&g)[j] ^= diff4Bits; + } + + return g; +} +String GetGuidString() +{ + uint64_t guid = GetGuidInt(); + + char buff[64]; +#if defined(OVR_CC_MSVC) + OVR_sprintf(buff, sizeof(buff), "%I64u", guid); +#else + OVR_sprintf(buff, sizeof(buff), "%llu", (unsigned long long) guid); +#endif + return String(buff); +} + +const char * GetProcessInfo() +{ + #if defined (OVR_CPU_X86_64 ) + return "64 bit"; +#elif defined (OVR_CPU_X86) + return "32 bit"; +#else + return "TODO"; +#endif +} +#ifdef OVR_OS_WIN32 + + +String OSVersionAsString() +{ + return GetSystemFileVersionString("\\kernel32.dll"); +} +String GetSystemFileVersionString(String filePath) +{ + char strFilePath[MAX_PATH]; // Local variable + UINT sysDirLen = GetSystemDirectoryA(strFilePath, ARRAYSIZE(strFilePath)); + if (sysDirLen != 0) + { + OVR_strcat(strFilePath, MAX_PATH, filePath.ToCStr()); + return GetFileVersionString(strFilePath); + } + else + { + return "GetSystemDirectoryA failed"; + } +} +// See http://stackoverflow.com/questions/940707/how-do-i-programatically-get-the-version-of-a-dll-or-exe-file +String GetFileVersionString(String filePath) +{ + String result; + + DWORD dwSize = GetFileVersionInfoSizeA(filePath.ToCStr(), NULL); + if (dwSize == 0) + { + OVR_DEBUG_LOG(("Error in GetFileVersionInfoSizeA: %d (for %s)", GetLastError(), filePath.ToCStr())); + result = filePath + " not found"; + } + else + { + BYTE* pVersionInfo = new BYTE[dwSize]; + if (!pVersionInfo) + { + OVR_DEBUG_LOG(("Out of memory allocating %d bytes (for %s)", dwSize, filePath.ToCStr())); + result = "Out of memory"; + } + else + { + if (!GetFileVersionInfoA(filePath.ToCStr(), 0, dwSize, pVersionInfo)) + { + OVR_DEBUG_LOG(("Error in GetFileVersionInfo: %d (for %s)", GetLastError(), filePath.ToCStr())); + result = "Cannot get version info"; + } + else + { + VS_FIXEDFILEINFO* pFileInfo = NULL; + UINT pLenFileInfo = 0; + if (!VerQueryValue(pVersionInfo, TEXT("\\"), (LPVOID*)&pFileInfo, &pLenFileInfo)) + { + OVR_DEBUG_LOG(("Error in VerQueryValue: %d (for %s)", GetLastError(), filePath.ToCStr())); + result = "File has no version info"; + } + else + { + int major = (pFileInfo->dwFileVersionMS >> 16) & 0xffff; + int minor = (pFileInfo->dwFileVersionMS) & 0xffff; + int hotfix = (pFileInfo->dwFileVersionLS >> 16) & 0xffff; + int other = (pFileInfo->dwFileVersionLS) & 0xffff; + + char str[128]; + OVR::OVR_sprintf(str, 128, "%d.%d.%d.%d", major, minor, hotfix, other); + + result = str; + } + } + + delete[] pVersionInfo; + } + } + + return result; +} + + +String GetDisplayDriverVersion() +{ + return GetSystemFileVersionString("\\OVRDisplay32.dll"); +} +String GetCameraDriverVersion() +{ + return GetSystemFileVersionString("\\drivers\\OCUSBVID.sys"); +} + +// From http://stackoverflow.com/questions/9524309/enumdisplaydevices-function-not-working-for-me +void GetGraphicsCardList( Array< String > &gpus) +{ + gpus.Clear(); + + DISPLAY_DEVICEA dd; + + dd.cb = sizeof(dd); + + DWORD deviceNum = 0; + while( EnumDisplayDevicesA(NULL, deviceNum, &dd, 0) ){ + if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + gpus.PushBack(dd.DeviceString); + deviceNum++; + } +} + + +String GetProcessorInfo() +{ + char brand[0x40] = {}; + int cpui[4] = { -1 }; + + __cpuidex(cpui, 0x80000002, 0); + + //unsigned int blocks = cpui[0]; + for (int i = 0; i <= 2; ++i) + { + __cpuidex(cpui, 0x80000002 + i, 0); + *reinterpret_cast<int*>(brand + i * 16) = cpui[0]; + *reinterpret_cast<int*>(brand + 4 + i * 16) = cpui[1]; + *reinterpret_cast<int*>(brand + 8 + i * 16) = cpui[2]; + *reinterpret_cast<int*>(brand + 12 + i * 16) = cpui[3]; + + } + return String(brand, 0x40); +} + +#else + +#ifdef OVR_OS_MAC +//use objective c source + +// used for driver files +String GetFileVersionString(String /*filePath*/) +{ + return String(); +} + +String GetSystemFileVersionString(String /*filePath*/) +{ + return String(); +} + +String GetDisplayDriverVersion() +{ + return String(); +} + +String GetCameraDriverVersion() +{ + return String(); +} + +#else + +// used for driver files +String GetFileVersionString(String /*filePath*/) +{ + return String(); +} + +String GetSystemFileVersionString(String /*filePath*/) +{ + return String(); +} + +String GetDisplayDriverVersion() +{ + char info[256] = { 0 }; + FILE *file = popen("/usr/bin/glxinfo", "r"); + if (file) + { + int status = 0; + while (status == 0) + { + status = fscanf(file, "%*[^\n]\n"); // Read up till the end of the current line, leaving the file pointer at the beginning of the next line (skipping any leading whitespace). + OVR_UNUSED(status); // Prevent GCC compiler warning: "ignoring return value of ‘int fscanf(FILE*, const char*, ...)" + + status = fscanf(file, "OpenGL version string: %255[^\n]", info); + } + pclose(file); + if (status == 1) + { + return String(info); + } + } + return String("No graphics driver details found."); +} + +String GetCameraDriverVersion() +{ + struct utsname kver; + if (uname(&kver)) + { + return String(); + } + return String(kver.release); +} + +void GetGraphicsCardList(OVR::Array< OVR::String > &gpus) +{ + gpus.Clear(); + + char info[256] = { 0 }; + FILE *file = popen("/usr/bin/lspci", "r"); + if (file) + { + int status = 0; + while (status >= 0) + { + status = fscanf(file, "%*[^\n]\n"); // Read up till the end of the current line, leaving the file pointer at the beginning of the next line (skipping any leading whitespace). + OVR_UNUSED(status); // Prevent GCC compiler warning: "ignoring return value of ‘int fscanf(FILE*, const char*, ...)" + + status = fscanf(file, "%*[^ ] VGA compatible controller: %255[^\n]", info); + if (status == 1) + { + gpus.PushBack(String(info)); + } + } + pclose(file); + } + if (gpus.GetSizeI() <= 0) + { + gpus.PushBack(String("No video card details found.")); + } +} + +String OSVersionAsString() +{ + char info[256] = { 0 }; + FILE *file = fopen("/etc/issue", "r"); + if (file) + { + int status = fscanf(file, "%255[^\n\\]", info); + fclose(file); + if (status == 1) + { + return String(info); + } + } + return String("No OS version details found."); +} + +String GetProcessorInfo() +{ + char info[256] = { 0 }; + FILE *file = fopen("/proc/cpuinfo", "r"); + if (file) + { + int status = 0; + while (status == 0) + { + status = fscanf(file, "%*[^\n]\n"); // Read up till the end of the current line, leaving the file pointer at the beginning of the next line (skipping any leading whitespace). + OVR_UNUSED(status); // Prevent GCC compiler warning: "ignoring return value of ‘int fscanf(FILE*, const char*, ...)" + + status = fscanf(file, "model name : %255[^\n]", info); + } + fclose(file); + if (status == 1) + { + return String(info); + } + } + return String("No processor details found."); +} +#endif //OVR_OS_MAC +#endif // WIN32 + +} } // namespace OVR { namespace Util { diff --git a/LibOVRKernel/Src/Util/Util_SystemInfo.h b/LibOVRKernel/Src/Util/Util_SystemInfo.h new file mode 100644 index 0000000..5c886c7 --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_SystemInfo.h @@ -0,0 +1,52 @@ +/************************************************************************************ + +Filename : Util_SystemInfo.h +Content : Various operations to get information about the system +Created : September 26, 2014 +Author : Kevin Jenkins + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + + +#ifndef OVR_Util_SystemInfo_h +#define OVR_Util_SystemInfo_h + +#include "../Kernel/OVR_String.h" +#include "../Kernel/OVR_Types.h" +#include "../Kernel/OVR_Array.h" + +namespace OVR { namespace Util { + +const char * OSAsString(); +String OSVersionAsString(); +uint64_t GetGuidInt(); +String GetGuidString(); +const char * GetProcessInfo(); +String GetFileVersionString(String filePath); +String GetSystemFileVersionString(String filePath); +String GetDisplayDriverVersion(); +String GetCameraDriverVersion(); +void GetGraphicsCardList(OVR::Array< OVR::String > &gpus); +String GetProcessorInfo(); + + +} } // namespace OVR { namespace Util { + +#endif // OVR_Util_SystemInfo_h diff --git a/LibOVRKernel/Src/Util/Util_SystemInfo_OSX.mm b/LibOVRKernel/Src/Util/Util_SystemInfo_OSX.mm new file mode 100644 index 0000000..6ee8ff5 --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_SystemInfo_OSX.mm @@ -0,0 +1,111 @@ + /************************************************************************************
+
+ Filename : Util_SystemInfo_OSX.mm
+ Content : Various operations to get information about the mac system
+ Created : October 2, 2014
+
+ Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
+
+ Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
+ you may not use the Oculus VR Rift SDK except in compliance with the License,
+ which is provided at the time of installation or download, or which
+ otherwise accompanies this software in either electronic or hard copy form.
+
+ You may obtain a copy of the License at
+
+ http://www.oculusvr.com/licenses/LICENSE-3.2
+
+ Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ ************************************************************************************/
+
+#include "Util_SystemInfo.h"
+
+#include <Cocoa/Cocoa.h>
+
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include "../Kernel/OVR_String.h"
+#include "../Kernel/OVR_System.h"
+
+using namespace OVR;
+namespace OVR { namespace Util {
+
+//from http://opensource.apple.com/source/CF/CF-744/CFUtilities.c
+OVR::String OSVersionAsString(){
+
+ NSDictionary *systemVersionDictionary =
+ [NSDictionary dictionaryWithContentsOfFile:
+ @"/System/Library/CoreServices/SystemVersion.plist"];
+
+ NSString *systemVersion =
+ [systemVersionDictionary objectForKey:@"ProductVersion"];
+ return OVR::String([systemVersion UTF8String]);
+}
+
+
+//from http://www.starcoder.com/wordpress/2011/10/using-iokit-to-detect-graphics-hardware/
+void GetGraphicsCardList(Array< String > &gpus)
+{
+ // Check the PCI devices for video cards.
+ CFMutableDictionaryRef match_dictionary = IOServiceMatching("IOPCIDevice");
+
+ // Create a iterator to go through the found devices.
+ io_iterator_t entry_iterator;
+
+ if (IOServiceGetMatchingServices(kIOMasterPortDefault,
+ match_dictionary,
+ &entry_iterator) == kIOReturnSuccess)
+ {
+ // Actually iterate through the found devices.
+ io_registry_entry_t serviceObject;
+ while ((serviceObject = IOIteratorNext(entry_iterator)))
+ {
+ // Put this services object into a dictionary object.
+ CFMutableDictionaryRef serviceDictionary;
+ if (IORegistryEntryCreateCFProperties(serviceObject,
+ &serviceDictionary,
+ kCFAllocatorDefault,
+ kNilOptions) != kIOReturnSuccess)
+ {
+ // Failed to create a service dictionary, release and go on.
+ IOObjectRelease(serviceObject);
+ continue;
+ }
+
+ //
+ // that points to a CFDataRef.
+ const void *modelarr = CFDictionaryGetValue(serviceDictionary, CFSTR("model"));
+ if (modelarr != nil) {
+ if(CFGetTypeID(modelarr) == CFDataGetTypeID())
+ {
+ NSData *data = (__bridge NSData*)(CFDataRef)modelarr;
+ NSString *s = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
+ gpus.PushBack([s UTF8String]);
+ }
+ }
+
+ // Release the dictionary created by IORegistryEntryCreateCFProperties.
+ CFRelease(serviceDictionary);
+
+ // Release the serviceObject returned by IOIteratorNext.
+ IOObjectRelease(serviceObject);
+ }
+
+ // Release the entry_iterator created by IOServiceGetMatchingServices.
+ IOObjectRelease(entry_iterator);
+ }
+}
+
+OVR::String GetProcessorInfo()
+{
+ return OVR::String();
+}
+
+} } // namespace OVR { namespace Util {
+
diff --git a/LibOVRKernel/Src/Util/Util_Watchdog.cpp b/LibOVRKernel/Src/Util/Util_Watchdog.cpp new file mode 100644 index 0000000..a5420b1 --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_Watchdog.cpp @@ -0,0 +1,249 @@ +/************************************************************************************ + +Filename : Util_Watchdog.cpp +Content : Deadlock reaction +Created : June 27, 2013 +Authors : Kevin Jenkins, Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#include "Util_Watchdog.h" +#include <Kernel/OVR_DebugHelp.h> +#include <Kernel/OVR_Win32_IncludeWindows.h> + +#if defined(OVR_OS_LINUX) || defined(OVR_OS_MAC) + #include <unistd.h> + #include <sys/types.h> + #include <sys/ptrace.h> + + #if defined(OVR_OS_LINUX) + #include <sys/wait.h> + #endif +#endif + +OVR_DEFINE_SINGLETON(OVR::Util::WatchDogObserver); + +namespace OVR { namespace Util { + +const int DefaultThreshhold = 60000; // milliseconds + +//----------------------------------------------------------------------------- +// Tools + +static uint32_t GetFastMsTime() +{ +#if defined(OVR_OS_MS) + return ::GetTickCount(); +#else + return Timer::GetTicksMs(); +#endif +} + + +//----------------------------------------------------------------------------- +// WatchDogObserver + +static bool ExitingOnDeadlock = false; + +bool WatchDogObserver::IsExitingOnDeadlock() +{ + return ExitingOnDeadlock; +} + +void WatchDogObserver::SetExitingOnDeadlock(bool enabled) +{ + ExitingOnDeadlock = enabled; +} + +WatchDogObserver::WatchDogObserver() : + IsReporting(false) +{ + Start(); + + // Must be at end of function + PushDestroyCallbacks(); +} + +WatchDogObserver::~WatchDogObserver() +{ + TerminationEvent.SetEvent(); + + Join(); +} + +void WatchDogObserver::OnThreadDestroy() +{ + TerminationEvent.SetEvent(); +} + +void WatchDogObserver::OnSystemDestroy() +{ + Release(); +} + +int WatchDogObserver::Run() +{ + OVR_DEBUG_LOG(("[WatchDogObserver] Starting")); + + SetThreadName("WatchDog"); + + while (!TerminationEvent.Wait(WakeupInterval)) + { + Lock::Locker locker(&ListLock); + + const uint32_t t1 = GetFastMsTime(); + + const int count = DogList.GetSizeI(); + for (int i = 0; i < count; ++i) + { + WatchDog* dog = DogList[i]; + + const int threshold = dog->ThreshholdMilliseconds; + const uint32_t t0 = dog->WhenLastFedMilliseconds; + + // If threshold exceeded, assume there is thread deadlock of some sort. + int delta = (int)(t1 - t0); + if (delta > threshold) + { + // Expected behavior: + // SingleProcessDebug, SingleProcessRelease, Debug: This is only ever done for internal testing, so we don't want it to trigger the deadlock termination. + // Release: This is our release configuration where we want it to terminate itself. + + // Print a stack trace of all threads if there's no debugger present. + const bool debuggerPresent = OVRIsDebuggerPresent(); + + LogError("{ERR-027} [WatchDogObserver] Deadlock detected: %s", dog->ThreadName.ToCStr()); + if (!debuggerPresent) // We don't print threads if a debugger is present because otherwise every time the developer paused the app to debug, it would spit out a long thread trace upon resuming. + { + if (SymbolLookup::Initialize()) + { + // symbolLookup is static here to avoid putting 32 KB on the stack + // and potentially overflowing the stack. This function is only ever + // run by one thread so it should be safe. + static SymbolLookup symbolLookup; + String threadListOutput, moduleListOutput; + symbolLookup.ReportThreadCallstacks(threadListOutput); + symbolLookup.ReportModuleInformation(moduleListOutput); + LogText("---DEADLOCK STATE---\n\n%s\n\n%s\n---END OF DEADLOCK STATE---\n", threadListOutput.ToCStr(), moduleListOutput.ToCStr()); + } + + if (IsReporting) + { + ExceptionHandler::ReportDeadlock(DogList[i]->ThreadName, OrganizationName , ApplicationName); + + // Disable reporting after the first deadlock report. + IsReporting = false; + } + } + + if (IsExitingOnDeadlock()) + { + OVR_ASSERT_M(false, "Watchdog detected a deadlock. Exiting the process."); // This won't have an effect unless asserts are enabled in release builds. + OVR::ExitProcess(-1); + } + } + } + } + + OVR_DEBUG_LOG(("[WatchDogObserver] Good night")); + + return 0; +} + +void WatchDogObserver::Add(WatchDog *dog) +{ + Lock::Locker locker(&ListLock); + + if (!dog->Listed) + { + DogList.PushBack(dog); + dog->Listed = true; + } +} + +void WatchDogObserver::Remove(WatchDog *dog) +{ + Lock::Locker locker(&ListLock); + + if (dog->Listed) + { + for (int i = 0; i < DogList.GetSizeI(); ++i) + { + if (DogList[i] == dog) + { + DogList.RemoveAt(i--); + } + } + + dog->Listed = false; + } +} + +void WatchDogObserver::EnableReporting(const String organization, const String application) +{ + OrganizationName = organization; + ApplicationName = application; + IsReporting = true; +} + +void WatchDogObserver::DisableReporting() +{ + IsReporting = false; +} + + +//----------------------------------------------------------------------------- +// WatchDog + +WatchDog::WatchDog(const String& threadName) : + ThreshholdMilliseconds(DefaultThreshhold), + ThreadName(threadName), + Listed(false) +{ + WhenLastFedMilliseconds = GetFastMsTime(); +} + +WatchDog::~WatchDog() +{ + Disable(); +} + +void WatchDog::Disable() +{ + WatchDogObserver::GetInstance()->Remove(this); +} + +void WatchDog::Enable() +{ + WatchDogObserver::GetInstance()->Add(this); +} + +void WatchDog::Feed(int threshold) +{ + WhenLastFedMilliseconds = GetFastMsTime(); + ThreshholdMilliseconds = threshold; + + if (!Listed) + { + Enable(); + } +} + +}} // namespace OVR::Util diff --git a/LibOVRKernel/Src/Util/Util_Watchdog.h b/LibOVRKernel/Src/Util/Util_Watchdog.h new file mode 100644 index 0000000..5dfe8c6 --- /dev/null +++ b/LibOVRKernel/Src/Util/Util_Watchdog.h @@ -0,0 +1,113 @@ +/************************************************************************************ + +Filename : Util_Watchdog.h +Content : Deadlock reaction +Created : June 27, 2013 +Authors : Kevin Jenkins, Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#ifndef OVR_Util_Watchdog_h +#define OVR_Util_Watchdog_h + +#include "Kernel/OVR_Timer.h" +#include "Kernel/OVR_Atomic.h" +#include "Kernel/OVR_Allocator.h" +#include "Kernel/OVR_String.h" +#include "Kernel/OVR_System.h" +#include "Kernel/OVR_Threads.h" + +namespace OVR { namespace Util { + + +//----------------------------------------------------------------------------- +// WatchDog + +class WatchDog : public NewOverrideBase +{ + friend class WatchDogObserver; + +public: + WatchDog(const String& threadName); + ~WatchDog(); + + void Disable(); + void Enable(); + + void Feed(int threshold); + +protected: + // Use 32 bit int so assignment and comparison is atomic + AtomicInt<uint32_t> WhenLastFedMilliseconds; + AtomicInt<int> ThreshholdMilliseconds; + + String ThreadName; + bool Listed; +}; + + +//----------------------------------------------------------------------------- +// WatchDogObserver + +class WatchDogObserver : public Thread, public SystemSingletonBase<WatchDogObserver> +{ + OVR_DECLARE_SINGLETON(WatchDogObserver); + virtual void OnThreadDestroy(); + + friend class WatchDog; + +public: + // Uses the exception logger to write deadlock reports + void EnableReporting(const String organization = String(), + const String application = String()); + + // Disables deadlock reports + void DisableReporting(); + +protected: + Lock ListLock; + Array< WatchDog* > DogList; + + static const int WakeupInterval = 1000; // milliseconds between checks + Event TerminationEvent; + + // Used in deadlock reporting. + bool IsReporting; + + // On Windows, deadlock logs are stored in %AppData%\OrganizationName\ApplicationName\. + // See ExceptionHandler::ReportDeadlock() for how these are used. + String ApplicationName; + String OrganizationName; + +protected: + virtual int Run(); + + void Add(WatchDog* dog); + void Remove(WatchDog* dog); + +public: + static bool IsExitingOnDeadlock(); + static void SetExitingOnDeadlock(bool enabled); +}; + + +}} // namespace OVR::Util + +#endif // OVR_Util_Watchdog_h |