aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVRKernel/Src/Util
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2015-03-28 01:43:35 +0100
committerSven Gothel <[email protected]>2015-03-28 01:43:35 +0100
commit4207f9c279e832e3afcb3f5fc6cd8d84cb4cfe4c (patch)
treecf3671058d55b47ab6cb6f36f369928606137628 /LibOVRKernel/Src/Util
parentc29cd1a2fbff6282bab956ad61661ac9d48c4e6e (diff)
Bump OculusVR RIFT SDK to 0.5.0.1vanilla_0.5.0.1
Diffstat (limited to 'LibOVRKernel/Src/Util')
-rw-r--r--LibOVRKernel/Src/Util/GUIConsole.h48
-rw-r--r--LibOVRKernel/Src/Util/Util_Direct3D.cpp154
-rw-r--r--LibOVRKernel/Src/Util/Util_Direct3D.h102
-rw-r--r--LibOVRKernel/Src/Util/Util_GetSystemSpecs.cpp455
-rw-r--r--LibOVRKernel/Src/Util/Util_ImageWindow.cpp591
-rw-r--r--LibOVRKernel/Src/Util/Util_ImageWindow.h201
-rw-r--r--LibOVRKernel/Src/Util/Util_LongPollThread.cpp97
-rw-r--r--LibOVRKernel/Src/Util/Util_LongPollThread.h72
-rw-r--r--LibOVRKernel/Src/Util/Util_SystemGUI.cpp239
-rw-r--r--LibOVRKernel/Src/Util/Util_SystemGUI.h40
-rw-r--r--LibOVRKernel/Src/Util/Util_SystemGUI_OSX.mm69
-rw-r--r--LibOVRKernel/Src/Util/Util_SystemInfo.cpp416
-rw-r--r--LibOVRKernel/Src/Util/Util_SystemInfo.h52
-rw-r--r--LibOVRKernel/Src/Util/Util_SystemInfo_OSX.mm111
-rw-r--r--LibOVRKernel/Src/Util/Util_Watchdog.cpp249
-rw-r--r--LibOVRKernel/Src/Util/Util_Watchdog.h113
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