diff options
author | Sven Gothel <[email protected]> | 2015-03-21 23:01:12 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-03-21 23:01:12 +0100 |
commit | 0c5c4be020c2d55540058a49b2a879f46d5a1e13 (patch) | |
tree | 00f84c2ca18cc233b826014094b9cad0769a3ea5 /LibOVR/Src/Util | |
parent | cbbd775b6c754927632c333ff01424a0d2048c7c (diff) | |
parent | e490c3c7f7bb5461cfa78a214827aa534fb43a3e (diff) |
Merge branch 'vanilla_0.4.4' and resolve conflicts
TODO: Validate for removed patches due to relocation
Resolved Conflicts:
LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp
LibOVR/Src/OVR_Linux_HMDDevice.cpp
LibOVR/Src/OVR_OSX_HMDDevice.cpp
LibOVR/Src/OVR_Profile.cpp
LibOVR/Src/OVR_Sensor2Impl.cpp
LibOVR/Src/OVR_SensorFusion.cpp
LibOVR/Src/OVR_SensorImpl.cpp
LibOVR/Src/OVR_Win32_DeviceStatus.cpp
LibOVR/Src/OVR_Win32_HIDDevice.cpp
LibOVR/Src/OVR_Win32_HIDDevice.h
LibOVR/Src/OVR_Win32_HMDDevice.cpp
Diffstat (limited to 'LibOVR/Src/Util')
-rw-r--r-- | LibOVR/Src/Util/GUIConsole.h | 51 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_ImageWindow.cpp | 265 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_ImageWindow.h | 26 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_Interface.cpp | 8 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_Interface.h | 9 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_LatencyTest.cpp | 570 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_LatencyTest.h | 173 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_LatencyTest2.cpp | 191 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_LatencyTest2.h | 238 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_LatencyTest2Reader.cpp | 118 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_LatencyTest2Reader.h | 63 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_LatencyTest2State.h | 96 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_Render_Stereo.cpp | 446 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_Render_Stereo.h | 64 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_SystemGUI.cpp | 190 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_SystemGUI.h | 39 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_SystemGUI_OSX.mm | 69 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_SystemInfo.cpp | 289 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_SystemInfo.h | 51 | ||||
-rw-r--r-- | LibOVR/Src/Util/Util_SystemInfo_OSX.mm | 106 |
20 files changed, 1556 insertions, 1506 deletions
diff --git a/LibOVR/Src/Util/GUIConsole.h b/LibOVR/Src/Util/GUIConsole.h new file mode 100644 index 0000000..a1b35ed --- /dev/null +++ b/LibOVR/Src/Util/GUIConsole.h @@ -0,0 +1,51 @@ +/************************************************************************************ + +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 GUICONSOLE_H +#define GUICONSOLE_H + +#include "../../Include/OVR_Kernel.h" + +#ifdef OVR_INTERNAL_USE + +#include <WinSock2.h> +#include <WS2tcpip.h> +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> + +class GUIConsole +{ +public: + // constructors + GUIConsole(); + ~GUIConsole(); + + // member variables + HANDLE hStdIn, hStdOut, hStdError; +}; +#endif // #ifdef OVR_INTERNAL_USE + +#endif diff --git a/LibOVR/Src/Util/Util_ImageWindow.cpp b/LibOVR/Src/Util/Util_ImageWindow.cpp index cb091c7..4c120f9 100644 --- a/LibOVR/Src/Util/Util_ImageWindow.cpp +++ b/LibOVR/Src/Util/Util_ImageWindow.cpp @@ -5,16 +5,16 @@ Content : An output object for windows that can display raw images for tes Created : March 13, 2014 Authors : Dean Beeler -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +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.1 +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, @@ -23,12 +23,13 @@ See the License for the specific language governing permissions and limitations under the License. *************************************************************************************/ -#include "../../Include/OVR.h" +#include "../../Include/OVR_Kernel.h" #include "Util_ImageWindow.h" #if defined(OVR_OS_WIN32) +#define WIN32_LEAN_AND_MEAN #include <Windows.h> #include "DWrite.h" @@ -51,7 +52,16 @@ namespace OVR { namespace Util { ID2D1Factory* ImageWindow::pD2DFactory = NULL; IDWriteFactory* ImageWindow::pDWriteFactory = NULL; -ImageWindow* ImageWindow::globalWindow[4]; +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( @@ -95,55 +105,69 @@ LRESULT CALLBACK MainWndProc( //return 0; } + ImageWindow::ImageWindow( uint32_t width, uint32_t height ) : - frontBufferMutex( new Mutex() ) + hWindow(NULL), + pRT(NULL), + //resolution(), + frontBufferMutex( new Mutex() ), + frames(), + greyBitmap(NULL), + colorBitmap(NULL) { - - HINSTANCE hInst = LoadLibrary( L"d2d1.dll" ); - HINSTANCE hInstWrite = LoadLibrary( L"Dwrite.dll" ); - D2D1CreateFactoryFn createFactory = NULL; DWriteCreateFactoryFn writeFactory = NULL; - if( hInst ) + if (!hInstD2d1) + { + hInstD2d1 = LoadLibraryW( L"d2d1.dll" ); + } + + if (!hInstD2d1) + { + hInstD2d1 = LoadLibraryW( L"Dwrite.dll" ); + } + + if( hInstD2d1 ) { - createFactory = (D2D1CreateFactoryFn)GetProcAddress( hInst, "D2D1CreateFactory" ); + createFactory = (D2D1CreateFactoryFn)GetProcAddress( hInstD2d1, "D2D1CreateFactory" ); } - if( hInstWrite ) + if( hInstDwrite ) { - writeFactory = (DWriteCreateFactoryFn)GetProcAddress( hInstWrite, "DWriteCreateFactory" ); + writeFactory = (DWriteCreateFactoryFn)GetProcAddress( hInstDwrite, "DWriteCreateFactory" ); } - globalWindow[windowCount] = this; - - ++windowCount; + // TODO: see note where globalWindow is declared. + globalWindow[windowCount++ % MaxWindows] = this; + OVR_ASSERT(windowCount < MaxWindows); if( pD2DFactory == NULL && createFactory && writeFactory ) { - createFactory( + // Create a Direct2D factory. + HRESULT hResult = createFactory( D2D1_FACTORY_TYPE_MULTI_THREADED, __uuidof(ID2D1Factory), NULL, - &pD2DFactory + &pD2DFactory // This will be AddRef'd for us. ); + OVR_ASSERT_AND_UNUSED(hResult == S_OK, hResult); // Create a DirectWrite factory. - writeFactory( + hResult = writeFactory( DWRITE_FACTORY_TYPE_SHARED, - __uuidof(pDWriteFactory), - reinterpret_cast<IUnknown **>(&pDWriteFactory) + __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 ); - SetWindowLongPtr( hWindow, GWLP_USERDATA, (LONG_PTR)this ); - - pRT = NULL; - greyBitmap = NULL; - colorBitmap = NULL; + if (hWindow) + { + SetWindowLongPtr( hWindow, GWLP_USERDATA, (LONG_PTR)this ); + } } ImageWindow::~ImageWindow() @@ -155,7 +179,7 @@ ImageWindow::~ImageWindow() globalWindow[i] = NULL; break; } -} + } if( greyBitmap ) greyBitmap->Release(); @@ -177,81 +201,110 @@ ImageWindow::~ImageWindow() delete frontBufferMutex; - ShowWindow( hWindow, SW_HIDE ); - DestroyWindow( hWindow ); + 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 ) { - // 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; - } - - result = tmpTarget->CreateBitmap( size, colorBitmapProps, &colorBitmap ); - if( result != S_OK ) - { - greyBitmap->Release(); - greyBitmap = NULL; - - tmpTarget->Release(); - tmpTarget = NULL; - } - pRT = tmpTarget; - } - } + 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() @@ -508,4 +561,14 @@ void ImageWindow::addText( float x, float y, float r, float g, float b, OVR::Str }} -#endif //defined(OVR_OS_WIN32)
\ No newline at end of file +#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/LibOVR/Src/Util/Util_ImageWindow.h b/LibOVR/Src/Util/Util_ImageWindow.h index 4b88959..979dd93 100644 --- a/LibOVR/Src/Util/Util_ImageWindow.h +++ b/LibOVR/Src/Util/Util_ImageWindow.h @@ -7,14 +7,14 @@ Authors : Dean Beeler Copyright : Copyright 2014 Oculus, Inc. All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +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.1 +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, @@ -28,13 +28,14 @@ limitations under the License. #define UTIL_IMAGEWINDOW_H #if defined(OVR_OS_WIN32) -#define WIN32_LEAN_AND_MEAN 1 -#include <windows.h> +#include <WinSock2.h> +#include <WS2tcpip.h> +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> #include <d2d1.h> #include <dwrite.h> #endif -#include "../../Include/OVR.h" #include "../Kernel/OVR_Hash.h" #include "../Kernel/OVR_Array.h" #include "../Kernel/OVR_Threads.h" @@ -154,6 +155,9 @@ private: static int windowCount; static ID2D1Factory* pD2DFactory; static IDWriteFactory* pDWriteFactory; + static HINSTANCE hInstD2d1; + static HINSTANCE hInstDwrite; + }; #else @@ -171,16 +175,16 @@ public: 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 ) { } - void UpdateImageRGBA( const uint8_t* imageData, uint32_t width, uint32_t height, uint32_t pitch ) { } + 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 ) { } + void AssociateSurface( void* surface ) { OVR_UNUSED(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 ) { } + 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; } @@ -197,4 +201,4 @@ private: }} // namespace OVR::Util -#endif
\ No newline at end of file +#endif diff --git a/LibOVR/Src/Util/Util_Interface.cpp b/LibOVR/Src/Util/Util_Interface.cpp index d96423c..5090729 100644 --- a/LibOVR/Src/Util/Util_Interface.cpp +++ b/LibOVR/Src/Util/Util_Interface.cpp @@ -8,16 +8,16 @@ Content : Simple interface, utilised by internal demos, Created : February 20, 2014 Authors : Tom Heath -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +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.1 +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, @@ -31,4 +31,4 @@ limitations under the License. -//Files left in to ease its possible return......
\ No newline at end of file +//Files left in to ease its possible return...... diff --git a/LibOVR/Src/Util/Util_Interface.h b/LibOVR/Src/Util/Util_Interface.h index 1bbf638..ab08715 100644 --- a/LibOVR/Src/Util/Util_Interface.h +++ b/LibOVR/Src/Util/Util_Interface.h @@ -1,6 +1,5 @@ /************************************************************************************ -PublicHeader: OVR.h Filename : Util_Interface.h Content : Simple interface, utilised by internal demos, with access to wider SDK as needed. @@ -9,16 +8,16 @@ Content : Simple interface, utilised by internal demos, Created : February 20, 2014 Authors : Tom Heath -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +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.1 +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, @@ -30,7 +29,7 @@ limitations under the License. #ifndef OVR_Util_Interface_h #define OVR_Util_Interface_h -#include "../../Src/OVR_CAPI.h" +#include "../OVR_CAPI.h" //Files left in to ease its possible return...... diff --git a/LibOVR/Src/Util/Util_LatencyTest.cpp b/LibOVR/Src/Util/Util_LatencyTest.cpp deleted file mode 100644 index 3017c72..0000000 --- a/LibOVR/Src/Util/Util_LatencyTest.cpp +++ /dev/null @@ -1,570 +0,0 @@ -/************************************************************************************ - -Filename : Util_LatencyTest.cpp -Content : Wraps the lower level LatencyTester interface and adds functionality. -Created : February 14, 2013 -Authors : Lee Cooper - -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. - -Licensed under the Oculus VR Rift SDK License Version 3.1 (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.1 - -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_LatencyTest.h" - -#include "../Kernel/OVR_Log.h" -#include "../Kernel/OVR_Timer.h" - -namespace OVR { namespace Util { - -static const UInt32 TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION = 16*10; -static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION = 16*10; -static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT = 16*5; -static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS = 16*5; -static const UInt32 DEFAULT_NUMBER_OF_SAMPLES = 10; // For both color 1->2 and color 2->1 transitions. -static const UInt32 INITIAL_SAMPLES_TO_IGNORE = 4; -static const UInt32 TIMEOUT_WAITING_FOR_TEST_STARTED = 1000; -static const UInt32 TIMEOUT_WAITING_FOR_COLOR_DETECTED = 4000; -static const Color CALIBRATE_BLACK(0, 0, 0); -static const Color CALIBRATE_WHITE(255, 255, 255); -static const Color COLOR1(0, 0, 0); -static const Color COLOR2(255, 255, 255); -static const Color SENSOR_DETECT_THRESHOLD(128, 255, 255); -static const float BIG_FLOAT = 1000000.0f; -static const float SMALL_FLOAT = -1000000.0f; - -//------------------------------------------------------------------------------------- -// ***** LatencyTest - -LatencyTest::LatencyTest(LatencyTestDevice* device) - : Handler(getThis()) -{ - if (device != NULL) - { - SetDevice(device); - } - - reset(); - - srand(Timer::GetTicksMs()); -} - -LatencyTest::~LatencyTest() -{ - clearMeasurementResults(); -} - -bool LatencyTest::SetDevice(LatencyTestDevice* device) -{ - - if (device != Device) - { - Handler.RemoveHandlerFromDevices(); - - Device = device; - - if (Device != NULL) - { - Device->AddMessageHandler(&Handler); - - // Set trigger threshold. - LatencyTestConfiguration configuration(SENSOR_DETECT_THRESHOLD, false); // No samples streaming. - Device->SetConfiguration(configuration, true); - - // Set display to initial (3 dashes). - LatencyTestDisplay ltd(2, 0x40400040); - Device->SetDisplay(ltd); - } - } - - return true; -} - -UInt32 LatencyTest::getRandomComponent(UInt32 range) -{ - UInt32 val = rand() % range; - return val; -} - -void LatencyTest::BeginTest() -{ - if (State == State_WaitingForButton) - { - // Set color to black and wait a while. - RenderColor = CALIBRATE_BLACK; - - State = State_WaitingForSettlePreCalibrationColorBlack; - OVR_DEBUG_LOG(("State_WaitingForButton -> State_WaitingForSettlePreCalibrationColorBlack.")); - - setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION); - } -} - -void LatencyTest::handleMessage(const Message& msg, LatencyTestMessageType latencyTestMessage) -{ - // For debugging. -/* if (msg.Type == Message_LatencyTestSamples) - { - MessageLatencyTestSamples* pSamples = (MessageLatencyTestSamples*) &msg; - - if (pSamples->Samples.GetSize() > 0) - { - // Just show the first one for now. - Color c = pSamples->Samples[0]; - OVR_DEBUG_LOG(("%d %d %d", c.R, c.G, c.B)); - } - return; - } -*/ - - if (latencyTestMessage == LatencyTest_Timer) - { - if (!Device) - { - reset(); - return; - } - - if (State == State_WaitingForSettlePreCalibrationColorBlack) - { - // Send calibrate message to device and wait a while. - Device->SetCalibrate(CALIBRATE_BLACK); - - State = State_WaitingForSettlePostCalibrationColorBlack; - OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorBlack -> State_WaitingForSettlePostCalibrationColorBlack.")); - - setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION); - } - else if (State == State_WaitingForSettlePostCalibrationColorBlack) - { - // Change color to white and wait a while. - RenderColor = CALIBRATE_WHITE; - - State = State_WaitingForSettlePreCalibrationColorWhite; - OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorBlack -> State_WaitingForSettlePreCalibrationColorWhite.")); - - setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION); - } - else if (State == State_WaitingForSettlePreCalibrationColorWhite) - { - // Send calibrate message to device and wait a while. - Device->SetCalibrate(CALIBRATE_WHITE); - - State = State_WaitingForSettlePostCalibrationColorWhite; - OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorWhite -> State_WaitingForSettlePostCalibrationColorWhite.")); - - setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION); - } - else if (State == State_WaitingForSettlePostCalibrationColorWhite) - { - // Calibration is done. Switch to color 1 and wait for it to settle. - RenderColor = COLOR1; - - State = State_WaitingForSettlePostMeasurement; - OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorWhite -> State_WaitingForSettlePostMeasurement.")); - - UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS); - setTimer(waitTime); - } - else if (State == State_WaitingForSettlePostMeasurement) - { - // Prepare for next measurement. - - // Create a new result object. - MeasurementResult* pResult = new MeasurementResult(); - Results.PushBack(pResult); - - State = State_WaitingToTakeMeasurement; - OVR_DEBUG_LOG(("State_WaitingForSettlePostMeasurement -> State_WaitingToTakeMeasurement.")); - } - else if (State == State_WaitingForTestStarted) - { - // We timed out waiting for 'TestStarted'. Abandon this measurement and setup for the next. - getActiveResult()->TimedOutWaitingForTestStarted = true; - - State = State_WaitingForSettlePostMeasurement; - OVR_DEBUG_LOG(("** Timed out waiting for 'TestStarted'.")); - OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForSettlePostMeasurement.")); - - UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS); - setTimer(waitTime); - } - else if (State == State_WaitingForColorDetected) - { - // We timed out waiting for 'ColorDetected'. Abandon this measurement and setup for the next. - getActiveResult()->TimedOutWaitingForColorDetected = true; - - State = State_WaitingForSettlePostMeasurement; - OVR_DEBUG_LOG(("** Timed out waiting for 'ColorDetected'.")); - OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement.")); - - UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS); - setTimer(waitTime); - } - } - else if (latencyTestMessage == LatencyTest_ProcessInputs) - { - if (State == State_WaitingToTakeMeasurement) - { - if (!Device) - { - reset(); - return; - } - - // Send 'StartTest' feature report with opposite target color. - if (RenderColor == COLOR1) - { - RenderColor = COLOR2; - } - else - { - RenderColor = COLOR1; - } - - getActiveResult()->TargetColor = RenderColor; - - // Record time so we can determine usb roundtrip time. - getActiveResult()->StartTestSeconds = Timer::GetSeconds(); - - Device->SetStartTest(RenderColor); - - State = State_WaitingForTestStarted; - OVR_DEBUG_LOG(("State_WaitingToTakeMeasurement -> State_WaitingForTestStarted.")); - - setTimer(TIMEOUT_WAITING_FOR_TEST_STARTED); - - LatencyTestDisplay ltd(2, 0x40090040); - Device->SetDisplay(ltd); - } - } - else if (msg.Type == Message_LatencyTestButton) - { - BeginTest(); - } - else if (msg.Type == Message_LatencyTestStarted) - { - if (State == State_WaitingForTestStarted) - { - clearTimer(); - - // Record time so we can determine usb roundtrip time. - getActiveResult()->TestStartedSeconds = Timer::GetSeconds(); - - State = State_WaitingForColorDetected; - OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForColorDetected.")); - - setTimer(TIMEOUT_WAITING_FOR_COLOR_DETECTED); - } - } - else if (msg.Type == Message_LatencyTestColorDetected) - { - if (State == State_WaitingForColorDetected) - { - // Record time to detect color. - MessageLatencyTestColorDetected* pDetected = (MessageLatencyTestColorDetected*) &msg; - UInt16 elapsedTime = pDetected->Elapsed; - OVR_DEBUG_LOG(("Time to 'ColorDetected' = %d", elapsedTime)); - - getActiveResult()->DeviceMeasuredElapsedMilliS = elapsedTime; - - if (areResultsComplete()) - { - // We're done. - processResults(); - reset(); - } - else - { - // Run another measurement. - State = State_WaitingForSettlePostMeasurement; - OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement.")); - - UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS); - setTimer(waitTime); - - LatencyTestDisplay ltd(2, 0x40400040); - Device->SetDisplay(ltd); - } - } - } - else if (msg.Type == Message_DeviceRemoved) - { - reset(); - } -} - -LatencyTest::MeasurementResult* LatencyTest::getActiveResult() -{ - OVR_ASSERT(!Results.IsEmpty()); - return Results.GetLast(); -} - -void LatencyTest::setTimer(UInt32 timeMilliS) -{ - ActiveTimerMilliS = timeMilliS; -} - -void LatencyTest::clearTimer() -{ - ActiveTimerMilliS = 0; -} - -void LatencyTest::reset() -{ - clearMeasurementResults(); - State = State_WaitingForButton; - - HaveOldTime = false; - ActiveTimerMilliS = 0; -} - -void LatencyTest::clearMeasurementResults() -{ - while(!Results.IsEmpty()) - { - MeasurementResult* pElem = Results.GetFirst(); - pElem->RemoveNode(); - delete pElem; - } -} - -LatencyTest::LatencyTestHandler::~LatencyTestHandler() -{ - RemoveHandlerFromDevices(); -} - -void LatencyTest::LatencyTestHandler::OnMessage(const Message& msg) -{ - pLatencyTestUtil->handleMessage(msg); -} - -void LatencyTest::ProcessInputs() -{ - updateForTimeouts(); - handleMessage(Message(), LatencyTest_ProcessInputs); -} - -bool LatencyTest::DisplayScreenColor(Color& colorToDisplay) -{ - updateForTimeouts(); - - if (State == State_WaitingForButton) - { - return false; - } - - colorToDisplay = RenderColor; - return true; -} - -const char* LatencyTest::GetResultsString() -{ - if (!ResultsString.IsEmpty() && ReturnedResultString != ResultsString.ToCStr()) - { - ReturnedResultString = ResultsString; - return ReturnedResultString.ToCStr(); - } - - return NULL; -} - -bool LatencyTest::areResultsComplete() -{ - UInt32 initialMeasurements = 0; - - UInt32 measurements1to2 = 0; - UInt32 measurements2to1 = 0; - - MeasurementResult* pCurr = Results.GetFirst(); - while(true) - { - // Process. - if (!pCurr->TimedOutWaitingForTestStarted && - !pCurr->TimedOutWaitingForColorDetected) - { - initialMeasurements++; - - if (initialMeasurements > INITIAL_SAMPLES_TO_IGNORE) - { - if (pCurr->TargetColor == COLOR2) - { - measurements1to2++; - } - else - { - measurements2to1++; - } - } - } - - if (Results.IsLast(pCurr)) - { - break; - } - pCurr = Results.GetNext(pCurr); - } - - if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES && - measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES) - { - return true; - } - - return false; -} - -void LatencyTest::processResults() -{ - - UInt32 minTime1To2 = UINT_MAX; - UInt32 maxTime1To2 = 0; - float averageTime1To2 = 0.0f; - UInt32 minTime2To1 = UINT_MAX; - UInt32 maxTime2To1 = 0; - float averageTime2To1 = 0.0f; - - float minUSBTripMilliS = BIG_FLOAT; - float maxUSBTripMilliS = SMALL_FLOAT; - float averageUSBTripMilliS = 0.0f; - UInt32 countUSBTripTime = 0; - - UInt32 measurementsCount = 0; - UInt32 measurements1to2 = 0; - UInt32 measurements2to1 = 0; - - MeasurementResult* pCurr = Results.GetFirst(); - UInt32 count = 0; - while(true) - { - count++; - - if (!pCurr->TimedOutWaitingForTestStarted && - !pCurr->TimedOutWaitingForColorDetected) - { - measurementsCount++; - - if (measurementsCount > INITIAL_SAMPLES_TO_IGNORE) - { - if (pCurr->TargetColor == COLOR2) - { - measurements1to2++; - - if (measurements1to2 <= DEFAULT_NUMBER_OF_SAMPLES) - { - UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS; - - minTime1To2 = Alg::Min(elapsed, minTime1To2); - maxTime1To2 = Alg::Max(elapsed, maxTime1To2); - - averageTime1To2 += (float) elapsed; - } - } - else - { - measurements2to1++; - - if (measurements2to1 <= DEFAULT_NUMBER_OF_SAMPLES) - { - UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS; - - minTime2To1 = Alg::Min(elapsed, minTime2To1); - maxTime2To1 = Alg::Max(elapsed, maxTime2To1); - - averageTime2To1 += (float) elapsed; - } - } - - float usbRountripElapsedMilliS = Timer::MsPerSecond * (float) (pCurr->TestStartedSeconds - pCurr->StartTestSeconds); - minUSBTripMilliS = Alg::Min(usbRountripElapsedMilliS, minUSBTripMilliS); - maxUSBTripMilliS = Alg::Max(usbRountripElapsedMilliS, maxUSBTripMilliS); - averageUSBTripMilliS += usbRountripElapsedMilliS; - countUSBTripTime++; - } - } - - if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES && - measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES) - { - break; - } - - if (Results.IsLast(pCurr)) - { - break; - } - pCurr = Results.GetNext(pCurr); - } - - averageTime1To2 /= (float) DEFAULT_NUMBER_OF_SAMPLES; - averageTime2To1 /= (float) DEFAULT_NUMBER_OF_SAMPLES; - - averageUSBTripMilliS /= countUSBTripTime; - - float finalResult = 0.5f * (averageTime1To2 + averageTime2To1); - finalResult += averageUSBTripMilliS; - - ResultsString.Clear(); - ResultsString.AppendFormat("RESULT=%.1f (add half Tracker period) [b->w %d|%.1f|%d] [w->b %d|%.1f|%d] [usb rndtrp %.1f|%.1f|%.1f] [cnt %d] [tmouts %d]", - finalResult, - minTime1To2, averageTime1To2, maxTime1To2, - minTime2To1, averageTime2To1, maxTime2To1, - minUSBTripMilliS, averageUSBTripMilliS, maxUSBTripMilliS, - DEFAULT_NUMBER_OF_SAMPLES*2, count - measurementsCount); - - // Display result on latency tester display. - LatencyTestDisplay ltd(1, (int)finalResult); - Device->SetDisplay(ltd); -} - -void LatencyTest::updateForTimeouts() -{ - if (!HaveOldTime) - { - HaveOldTime = true; - OldTime = Timer::GetTicksMs(); - return; - } - - UInt32 newTime = Timer::GetTicksMs(); - UInt32 elapsedMilliS = newTime - OldTime; - if (newTime < OldTime) - { - elapsedMilliS = OldTime - newTime; - elapsedMilliS = UINT_MAX - elapsedMilliS; - } - OldTime = newTime; - - elapsedMilliS = Alg::Min(elapsedMilliS, (UInt32) 100); // Clamp at 100mS in case we're not being called very often. - - - if (ActiveTimerMilliS == 0) - { - return; - } - - if (elapsedMilliS >= ActiveTimerMilliS) - { - ActiveTimerMilliS = 0; - handleMessage(Message(), LatencyTest_Timer); - return; - } - - ActiveTimerMilliS -= elapsedMilliS; -} - -}} // namespace OVR::Util diff --git a/LibOVR/Src/Util/Util_LatencyTest.h b/LibOVR/Src/Util/Util_LatencyTest.h deleted file mode 100644 index 0844603..0000000 --- a/LibOVR/Src/Util/Util_LatencyTest.h +++ /dev/null @@ -1,173 +0,0 @@ -/************************************************************************************ - -PublicHeader: OVR.h -Filename : Util_LatencyTest.h -Content : Wraps the lower level LatencyTesterDevice and adds functionality. -Created : February 14, 2013 -Authors : Lee Cooper - -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. - -Licensed under the Oculus VR Rift SDK License Version 3.1 (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.1 - -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_LatencyTest_h -#define OVR_Util_LatencyTest_h - -#include "../OVR_Device.h" - -#include "../Kernel/OVR_String.h" -#include "../Kernel/OVR_List.h" - -namespace OVR { namespace Util { - - -//------------------------------------------------------------------------------------- -// ***** LatencyTest -// -// LatencyTest utility class wraps the low level LatencyTestDevice and manages the scheduling -// of a latency test. A single test is composed of a series of individual latency measurements -// which are used to derive min, max, and an average latency value. -// -// Developers are required to call the following methods: -// SetDevice - Sets the LatencyTestDevice to be used for the tests. -// ProcessInputs - This should be called at the same place in the code where the game engine -// reads the headset orientation from LibOVR (typically done by calling -// 'GetOrientation' on the SensorFusion object). Calling this at the right time -// enables us to measure the same latency that occurs for headset orientation -// changes. -// DisplayScreenColor - The latency tester works by sensing the color of the pixels directly -// beneath it. The color of these pixels can be set by drawing a small -// quad at the end of the rendering stage. The quad should be small -// such that it doesn't significantly impact the rendering of the scene, -// but large enough to be 'seen' by the sensor. See the SDK -// documentation for more information. -// GetResultsString - Call this to get a string containing the most recent results. -// If the string has already been gotten then NULL will be returned. -// The string pointer will remain valid until the next time this -// method is called. -// - -class LatencyTest : public NewOverrideBase -{ -public: - LatencyTest(LatencyTestDevice* device = NULL); - ~LatencyTest(); - - // Set the Latency Tester device that we'll use to send commands to and receive - // notification messages from. - bool SetDevice(LatencyTestDevice* device); - - // Returns true if this LatencyTestUtil has a Latency Tester device. - bool HasDevice() const - { return Handler.IsHandlerInstalled(); } - - void ProcessInputs(); - bool DisplayScreenColor(Color& colorToDisplay); - const char* GetResultsString(); - - bool IsMeasuringNow() const { return (State != State_WaitingForButton); } - - // Begin test. Equivalent to pressing the button on the latency tester. - void BeginTest(); - -private: - LatencyTest* getThis() { return this; } - - enum LatencyTestMessageType - { - LatencyTest_None, - LatencyTest_Timer, - LatencyTest_ProcessInputs, - }; - - UInt32 getRandomComponent(UInt32 range); - void handleMessage(const Message& msg, LatencyTestMessageType latencyTestMessage = LatencyTest_None); - void reset(); - void setTimer(UInt32 timeMilliS); - void clearTimer(); - - class LatencyTestHandler : public MessageHandler - { - LatencyTest* pLatencyTestUtil; - public: - LatencyTestHandler(LatencyTest* latencyTester) : pLatencyTestUtil(latencyTester) { } - ~LatencyTestHandler(); - - virtual void OnMessage(const Message& msg); - }; - - bool areResultsComplete(); - void processResults(); - void updateForTimeouts(); - - Ptr<LatencyTestDevice> Device; - LatencyTestHandler Handler; - - enum TesterState - { - State_WaitingForButton, - State_WaitingForSettlePreCalibrationColorBlack, - State_WaitingForSettlePostCalibrationColorBlack, - State_WaitingForSettlePreCalibrationColorWhite, - State_WaitingForSettlePostCalibrationColorWhite, - State_WaitingToTakeMeasurement, - State_WaitingForTestStarted, - State_WaitingForColorDetected, - State_WaitingForSettlePostMeasurement - }; - TesterState State; - - bool HaveOldTime; - UInt32 OldTime; - UInt32 ActiveTimerMilliS; - - Color RenderColor; - - struct MeasurementResult : public ListNode<MeasurementResult>, public NewOverrideBase - { - MeasurementResult() - : DeviceMeasuredElapsedMilliS(0), - TimedOutWaitingForTestStarted(false), - TimedOutWaitingForColorDetected(false), - StartTestSeconds(0.0), - TestStartedSeconds(0.0) - {} - - Color TargetColor; - - UInt32 DeviceMeasuredElapsedMilliS; - - bool TimedOutWaitingForTestStarted; - bool TimedOutWaitingForColorDetected; - - double StartTestSeconds; - double TestStartedSeconds; - }; - - List<MeasurementResult> Results; - void clearMeasurementResults(); - - MeasurementResult* getActiveResult(); - - StringBuffer ResultsString; - String ReturnedResultString; -}; - -}} // namespace OVR::Util - -#endif // OVR_Util_LatencyTest_h diff --git a/LibOVR/Src/Util/Util_LatencyTest2.cpp b/LibOVR/Src/Util/Util_LatencyTest2.cpp deleted file mode 100644 index 6fc8b1f..0000000 --- a/LibOVR/Src/Util/Util_LatencyTest2.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/************************************************************************************ - -Filename : Util_LatencyTest2.cpp -Content : Wraps the lower level LatencyTester interface for DK2 and adds functionality. -Created : March 10, 2014 -Authors : Volga Aksoy - -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. - -Licensed under the Oculus VR Rift SDK License Version 3.1 (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.1 - -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_LatencyTest2.h" - -#include "../OVR_CAPI.h" -#include "../Kernel/OVR_Log.h" -#include "../Kernel/OVR_Timer.h" - - -namespace OVR { namespace Util { - -//------------------------------------------------------------------------------------- -// ***** LatencyTest2 - -LatencyTest2::LatencyTest2(SensorDevice* device) - : Handler(getThis()) - , TestActive(false) - , StartTiming(-1) - , LatencyMeasuredInSeconds(-1) - , LastPixelReadMsg(NULL) - , RenderColorValue(0) - , NumMsgsBeforeSettle(0) - , NumTestsSuccessful(0) -{ - if (device != NULL) - { - SetSensorDevice(device); - } -} - -LatencyTest2::~LatencyTest2() -{ - HmdDevice = NULL; - LatencyTesterDev = NULL; - - Handler.RemoveHandlerFromDevices(); -} - -bool LatencyTest2::SetSensorDevice(SensorDevice* device) -{ - Lock::Locker devLocker(&TesterLock); - - // Enable/Disable pixel read from HMD - if (device != HmdDevice) - { - Handler.RemoveHandlerFromDevices(); - - HmdDevice = device; - - if (HmdDevice != NULL) - { - HmdDevice->AddMessageHandler(&Handler); - } - } - - return true; -} - -bool LatencyTest2::SetDisplayDevice(LatencyTestDevice* device) -{ - Lock::Locker devLocker(&TesterLock); - - if (device != LatencyTesterDev) - { - LatencyTesterDev = device; - if (LatencyTesterDev != NULL) - { - // Set display to initial (3 dashes). - LatencyTestDisplay ltd(2, 0x40400040); - LatencyTesterDev->SetDisplay(ltd); - } - } - - return true; -} - -void LatencyTest2::BeginTest(double startTime) -{ - Lock::Locker devLocker(&TesterLock); - - if (!TestActive) - { - TestActive = true; - NumMsgsBeforeSettle = 0; - - // Go to next pixel value - //RenderColorValue = (RenderColorValue == 0) ? 255 : 0; - RenderColorValue = (RenderColorValue + LT2_ColorIncrement) % 256; - RawStartTiming = LastPixelReadMsg.RawSensorTime; - - if (startTime > 0.0) - StartTiming = startTime; - else - StartTiming = ovr_GetTimeInSeconds(); - - } -} - -void LatencyTest2::handleMessage(const MessagePixelRead& msg) -{ - Lock::Locker devLocker(&TesterLock); - - // Hold onto the last message as we will use this when we start a new test - LastPixelReadMsg = msg; - - // If color readback index is valid, store it in the lock-less queue. - int readbackIndex = 0; - if (FrameTimeRecord::ColorToReadbackIndex(&readbackIndex, msg.PixelReadValue)) - { - RecentFrameSet.AddValue(readbackIndex, msg.FrameTimeSeconds); - LockessRecords.SetState(RecentFrameSet); - } - - NumMsgsBeforeSettle++; - - if (TestActive) - { - int pixelValueDiff = RenderColorValue - LastPixelReadMsg.PixelReadValue; - int rawTimeDiff = LastPixelReadMsg.RawFrameTime - RawStartTiming; - - if (pixelValueDiff < LT2_PixelTestThreshold && pixelValueDiff > -LT2_PixelTestThreshold) - { - TestActive = false; - - LatencyMeasuredInSeconds = LastPixelReadMsg.FrameTimeSeconds - StartTiming; - RawLatencyMeasured = rawTimeDiff; - //LatencyMeasuredInSeconds = RawLatencyMeasured / 1000000.0; - - if(LatencyTesterDev && (NumTestsSuccessful % 5) == 0) - { - int displayNum = (int)(RawLatencyMeasured / 100.0); - //int displayNum = NumMsgsBeforeSettle; - //int displayNum = (int)(LatencyMeasuredInSeconds * 1000.0); - LatencyTestDisplay ltd(1, displayNum); - LatencyTesterDev->SetDisplay(ltd); - } - - NumTestsSuccessful++; - } - else if (TestActive && (rawTimeDiff / 1000) > LT2_TimeoutWaitingForColorDetected) - { - TestActive = false; - LatencyMeasuredInSeconds = -1; - } - } -} - -LatencyTest2::PixelReadHandler::~PixelReadHandler() -{ - RemoveHandlerFromDevices(); -} - -void LatencyTest2::PixelReadHandler::OnMessage(const Message& msg) -{ - if(msg.Type == Message_PixelRead) - pLatencyTestUtil->handleMessage(static_cast<const MessagePixelRead&>(msg)); -} - -bool LatencyTest2::DisplayScreenColor(Color& colorToDisplay) -{ - Lock::Locker devLocker(&TesterLock); - colorToDisplay = Color(RenderColorValue, RenderColorValue, RenderColorValue, 255); - - return TestActive; -} - -}} // namespace OVR::Util diff --git a/LibOVR/Src/Util/Util_LatencyTest2.h b/LibOVR/Src/Util/Util_LatencyTest2.h deleted file mode 100644 index 61e8477..0000000 --- a/LibOVR/Src/Util/Util_LatencyTest2.h +++ /dev/null @@ -1,238 +0,0 @@ -/************************************************************************************ - -PublicHeader: OVR.h -Filename : Util_LatencyTest2.h -Content : Wraps the lower level LatencyTester interface for DK2 and adds functionality. -Created : March 10, 2014 -Authors : Volga Aksoy - -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. - -Licensed under the Oculus VR Rift SDK License Version 3.1 (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.1 - -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_LatencyTest2_h -#define OVR_Util_LatencyTest2_h - -#include "../OVR_Device.h" - -#include "../Kernel/OVR_String.h" -#include "../Kernel/OVR_List.h" -#include "../Kernel/OVR_Lockless.h" - -namespace OVR { namespace Util { - - -enum { - LT2_ColorIncrement = 32, - LT2_PixelTestThreshold = LT2_ColorIncrement / 3, - LT2_IncrementCount = 256 / LT2_ColorIncrement, - LT2_TimeoutWaitingForColorDetected = 1000 // 1 second -}; - -//------------------------------------------------------------------------------------- - -// Describes frame scanout time used for latency testing. -struct FrameTimeRecord -{ - int ReadbackIndex; - double TimeSeconds; - - // Utility functions to convert color to readBack indices and back. - // The purpose of ReadbackIndex is to allow direct comparison by value. - - static bool ColorToReadbackIndex(int *readbackIndex, unsigned char color) - { - int compareColor = color - LT2_ColorIncrement/2; - int index = color / LT2_ColorIncrement; // Use color without subtraction due to rounding. - int delta = compareColor - index * LT2_ColorIncrement; - - if ((delta < LT2_PixelTestThreshold) && (delta > -LT2_PixelTestThreshold)) - { - *readbackIndex = index; - return true; - } - return false; - } - - static unsigned char ReadbackIndexToColor(int readbackIndex) - { - OVR_ASSERT(readbackIndex < LT2_IncrementCount); - return (unsigned char)(readbackIndex * LT2_ColorIncrement + LT2_ColorIncrement/2); - } -}; - -// FrameTimeRecordSet is a container holding multiple consecutive frame timing records -// returned from the lock-less state. Used by FrameTimeManager. - -struct FrameTimeRecordSet -{ - enum { - RecordCount = 4, - RecordMask = RecordCount - 1 - }; - FrameTimeRecord Records[RecordCount]; - int NextWriteIndex; - - FrameTimeRecordSet() - { - NextWriteIndex = 0; - memset(this, 0, sizeof(FrameTimeRecordSet)); - } - - void AddValue(int readValue, double timeSeconds) - { - Records[NextWriteIndex].ReadbackIndex = readValue; - Records[NextWriteIndex].TimeSeconds = timeSeconds; - NextWriteIndex ++; - if (NextWriteIndex == RecordCount) - NextWriteIndex = 0; - } - // Matching should be done starting from NextWrite index - // until wrap-around - - const FrameTimeRecord& operator [] (int i) const - { - return Records[(NextWriteIndex + i) & RecordMask]; - } - - const FrameTimeRecord& GetMostRecentFrame() - { - return Records[(NextWriteIndex - 1) & RecordMask]; - } - - // Advances I to absolute color index - bool FindReadbackIndex(int* i, int readbackIndex) const - { - for (; *i < RecordCount; (*i)++) - { - if ((*this)[*i].ReadbackIndex == readbackIndex) - return true; - } - return false; - } - - bool IsAllZeroes() const - { - for (int i = 0; i < RecordCount; i++) - if (Records[i].ReadbackIndex != 0) - return false; - return true; - } -}; - - -//------------------------------------------------------------------------------------- -// ***** LatencyTest2 -// -// LatencyTest2 utility class wraps the low level SensorDevice and manages the scheduling -// of a latency test. A single test is composed of a series of individual latency measurements -// which are used to derive min, max, and an average latency value. -// -// Developers are required to call the following methods: -// SetDevice - Sets the SensorDevice to be used for the tests. -// ProcessInputs - This should be called at the same place in the code where the game engine -// reads the headset orientation from LibOVR (typically done by calling -// 'GetOrientation' on the SensorFusion object). Calling this at the right time -// enables us to measure the same latency that occurs for headset orientation -// changes. -// DisplayScreenColor - The latency tester works by sensing the color of the pixels directly -// beneath it. The color of these pixels can be set by drawing a small -// quad at the end of the rendering stage. The quad should be small -// such that it doesn't significantly impact the rendering of the scene, -// but large enough to be 'seen' by the sensor. See the SDK -// documentation for more information. -// GetResultsString - Call this to get a string containing the most recent results. -// If the string has already been gotten then NULL will be returned. -// The string pointer will remain valid until the next time this -// method is called. -// - -class LatencyTest2 : public NewOverrideBase -{ -public: - LatencyTest2(SensorDevice* device = NULL); - ~LatencyTest2(); - - // Set the Latency Tester device that we'll use to send commands to and receive - // notification messages from. - bool SetSensorDevice(SensorDevice* device); - bool SetDisplayDevice(LatencyTestDevice* device); - - // Returns true if this LatencyTestUtil has a Latency Tester device. - bool HasDisplayDevice() const { return LatencyTesterDev.GetPtr() != NULL; } - bool HasDevice() const { return Handler.IsHandlerInstalled(); } - - bool DisplayScreenColor(Color& colorToDisplay); - //const char* GetResultsString(); - - // Begin test. Equivalent to pressing the button on the latency tester. - void BeginTest(double startTime = -1.0f); - bool IsMeasuringNow() const { return TestActive; } - double GetMeasuredLatency() const { return LatencyMeasuredInSeconds; } - -// - FrameTimeRecordSet GetLocklessState() { return LockessRecords.GetState(); } - -private: - LatencyTest2* getThis() { return this; } - - enum LatencyTestMessageType - { - LatencyTest_None, - LatencyTest_Timer, - LatencyTest_ProcessInputs, - }; - - void handleMessage(const MessagePixelRead& msg); - - class PixelReadHandler : public MessageHandler - { - LatencyTest2* pLatencyTestUtil; - public: - PixelReadHandler(LatencyTest2* latencyTester) : pLatencyTestUtil(latencyTester) { } - ~PixelReadHandler(); - - virtual void OnMessage(const Message& msg); - }; - PixelReadHandler Handler; - - Ptr<SensorDevice> HmdDevice; - Ptr<LatencyTestDevice> LatencyTesterDev; - - Lock TesterLock; - bool TestActive; - unsigned char RenderColorValue; - MessagePixelRead LastPixelReadMsg; - double StartTiming; - unsigned int RawStartTiming; - UInt32 RawLatencyMeasured; - double LatencyMeasuredInSeconds; - int NumMsgsBeforeSettle; - unsigned int NumTestsSuccessful; - - // MA: - // Frames are added here, then copied into lockess state - FrameTimeRecordSet RecentFrameSet; - LocklessUpdater<FrameTimeRecordSet> LockessRecords; -}; - - - -}} // namespace OVR::Util - -#endif // OVR_Util_LatencyTest2_h diff --git a/LibOVR/Src/Util/Util_LatencyTest2Reader.cpp b/LibOVR/Src/Util/Util_LatencyTest2Reader.cpp new file mode 100644 index 0000000..e34bf19 --- /dev/null +++ b/LibOVR/Src/Util/Util_LatencyTest2Reader.cpp @@ -0,0 +1,118 @@ +/************************************************************************************ + +Filename : Util_LatencyTest2Reader.cpp +Content : Shared functionality for the DK2 latency tester +Created : July 8, 2014 +Authors : Volga Aksoy, 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_LatencyTest2Reader.h" + +namespace OVR { namespace Util { + + +//// FrameTimeRecord + +bool FrameTimeRecord::ColorToReadbackIndex(int *readbackIndex, unsigned char color) +{ + int compareColor = color - LT2_ColorIncrement/2; + int index = color / LT2_ColorIncrement; // Use color without subtraction due to rounding. + int delta = compareColor - index * LT2_ColorIncrement; + + if ((delta < LT2_PixelTestThreshold) && (delta > -LT2_PixelTestThreshold)) + { + *readbackIndex = index; + return true; + } + return false; +} + +unsigned char FrameTimeRecord::ReadbackIndexToColor(int readbackIndex) +{ + OVR_ASSERT(readbackIndex < LT2_IncrementCount); + return (unsigned char)(readbackIndex * LT2_ColorIncrement + LT2_ColorIncrement/2); +} + + +//// FrameTimeRecordSet + +FrameTimeRecordSet::FrameTimeRecordSet() +{ + NextWriteIndex = 0; + memset(this, 0, sizeof(FrameTimeRecordSet)); +} + +void FrameTimeRecordSet::AddValue(int readValue, double timeSeconds) +{ + Records[NextWriteIndex].ReadbackIndex = readValue; + Records[NextWriteIndex].TimeSeconds = timeSeconds; + NextWriteIndex++; + if (NextWriteIndex == RecordCount) + NextWriteIndex = 0; +} +// Matching should be done starting from NextWrite index +// until wrap-around + +const FrameTimeRecord& FrameTimeRecordSet::operator [] (int i) const +{ + return Records[(NextWriteIndex + i) & RecordMask]; +} + +const FrameTimeRecord& FrameTimeRecordSet::GetMostRecentFrame() +{ + return Records[(NextWriteIndex - 1) & RecordMask]; +} + +// Advances I to absolute color index +bool FrameTimeRecordSet::FindReadbackIndex(int* i, int readbackIndex) const +{ + for (; *i < RecordCount; (*i)++) + { + if ((*this)[*i].ReadbackIndex == readbackIndex) + return true; + } + return false; +} + +bool FrameTimeRecordSet::IsAllZeroes() const +{ + for (int i = 0; i < RecordCount; i++) + if (Records[i].ReadbackIndex != 0) + return false; + return true; +} + + +//// RecordStateReader + +void RecordStateReader::GetRecordSet(FrameTimeRecordSet& recordset) +{ + if(!Updater) + { + return; + } + + recordset = Updater->SharedLatencyTestState.GetState(); + return; +} + + +}} // namespace OVR::Util diff --git a/LibOVR/Src/Util/Util_LatencyTest2Reader.h b/LibOVR/Src/Util/Util_LatencyTest2Reader.h new file mode 100644 index 0000000..1863e62 --- /dev/null +++ b/LibOVR/Src/Util/Util_LatencyTest2Reader.h @@ -0,0 +1,63 @@ +/************************************************************************************ + +Filename : Util_LatencyTest2Reader.h +Content : Shared functionality for the DK2 latency tester +Created : July 8, 2014 +Authors : Volga Aksoy, 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_LatencyTest2Reader_h +#define OVR_Util_LatencyTest2Reader_h + +#include "../Tracking/Tracking_SensorState.h" +#include "Util_LatencyTest2State.h" + +namespace OVR { namespace Util { + + +//----------------------------------------------------------------------------- +// RecordStateReader + +// User interface to retrieve pose from the sensor fusion subsystem +class RecordStateReader : public NewOverrideBase +{ +protected: + const Tracking::CombinedSharedStateUpdater* Updater; + +public: + RecordStateReader() + : Updater(NULL) + { + } + + // Initialize the updater + void SetUpdater(const Tracking::CombinedSharedStateUpdater *updater) + { + Updater = updater; + } + + void GetRecordSet(FrameTimeRecordSet& recordset); +}; + + +}} // namespace OVR::Util + +#endif // OVR_Util_LatencyTest2Reader_h diff --git a/LibOVR/Src/Util/Util_LatencyTest2State.h b/LibOVR/Src/Util/Util_LatencyTest2State.h new file mode 100644 index 0000000..0b4ffd6 --- /dev/null +++ b/LibOVR/Src/Util/Util_LatencyTest2State.h @@ -0,0 +1,96 @@ +/************************************************************************************ + +Filename : Util_LatencyTest2Reader.h +Content : Shared functionality for the DK2 latency tester +Created : July 8, 2014 +Authors : Volga Aksoy, 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_LatencyTest2_State_h +#define OVR_Util_LatencyTest2_State_h + +#include "../Kernel/OVR_Lockless.h" + +namespace OVR { namespace Util { + + +enum LatencyTester2Constants +{ + LT2_ColorIncrement = 32, + LT2_PixelTestThreshold = LT2_ColorIncrement / 3, + LT2_IncrementCount = 256 / LT2_ColorIncrement, + LT2_TimeoutWaitingForColorDetected = 1000 // 1 second +}; + + +//------------------------------------------------------------------------------------- +// FrameTimeRecord + +// Describes frame scan-out time used for latency testing. +struct FrameTimeRecord +{ + int ReadbackIndex; + double TimeSeconds; + + // Utility functions to convert color to readBack indices and back. + // The purpose of ReadbackIndex is to allow direct comparison by value. + + static bool ColorToReadbackIndex(int *readbackIndex, unsigned char color); + static unsigned char ReadbackIndexToColor(int readbackIndex); +}; + + +//----------------------------------------------------------------------------- +// FrameTimeRecordSet + +// FrameTimeRecordSet is a container holding multiple consecutive frame timing records +// returned from the lock-less state. Used by FrameTimeManager. +struct FrameTimeRecordSet +{ + enum { + RecordCount = 4, + RecordMask = RecordCount - 1 + }; + FrameTimeRecord Records[RecordCount]; + int NextWriteIndex; + + FrameTimeRecordSet(); + + void AddValue(int readValue, double timeSeconds); + // Matching should be done starting from NextWrite index + // until wrap-around + + const FrameTimeRecord& operator [] (int i) const; + + const FrameTimeRecord& GetMostRecentFrame(); + + // Advances I to absolute color index + bool FindReadbackIndex(int* i, int readbackIndex) const; + + bool IsAllZeroes() const; +}; + +typedef LocklessUpdater<FrameTimeRecordSet, FrameTimeRecordSet> LockessRecordUpdater; + + +}} // namespace OVR::Util + +#endif // OVR_Util_LatencyTest2_State_h diff --git a/LibOVR/Src/Util/Util_Render_Stereo.cpp b/LibOVR/Src/Util/Util_Render_Stereo.cpp index e84381e..aa82b35 100644 --- a/LibOVR/Src/Util/Util_Render_Stereo.cpp +++ b/LibOVR/Src/Util/Util_Render_Stereo.cpp @@ -5,18 +5,18 @@ Content : Stereo rendering configuration implementation Created : October 22, 2012 Authors : Michael Antonov, Andrew Reisse, Tom Forsyth -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (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 +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.1 +http://www.oculusvr.com/licenses/LICENSE-3.2 -Unless required by applicable law or agreed to in writing, the Oculus VR SDK +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 @@ -25,10 +25,11 @@ limitations under the License. *************************************************************************************/ #include "Util_Render_Stereo.h" -#include "../OVR_SensorFusion.h" namespace OVR { namespace Util { namespace Render { +using namespace OVR::Tracking; + //----------------------------------------------------------------------------------- // **** Useful debug functions. @@ -37,21 +38,21 @@ char const* GetDebugNameEyeCupType ( EyeCupType eyeCupType ) { switch ( eyeCupType ) { - case EyeCup_DK1A: return "DK1 A"; break; - case EyeCup_DK1B: return "DK1 B"; break; - case EyeCup_DK1C: return "DK1 C"; break; - case EyeCup_DKHD2A: return "DKHD2 A"; break; - case EyeCup_OrangeA: return "Orange A"; break; - case EyeCup_RedA: return "Red A"; break; - case EyeCup_PinkA: return "Pink A"; break; - case EyeCup_BlueA: return "Blue A"; break; - case EyeCup_Delilah1A: return "Delilah 1 A"; break; - case EyeCup_Delilah2A: return "Delilah 2 A"; break; - case EyeCup_JamesA: return "James A"; break; - case EyeCup_SunMandalaA: return "Sun Mandala A"; break; - case EyeCup_DK2A: return "DK2 A"; break; - case EyeCup_LAST: return "LAST"; break; - default: OVR_ASSERT ( false ); return "Error"; break; + case EyeCup_DK1A: return "DK1 A"; + case EyeCup_DK1B: return "DK1 B"; + case EyeCup_DK1C: return "DK1 C"; + case EyeCup_DKHD2A: return "DKHD2 A"; + case EyeCup_OrangeA: return "Orange A"; + case EyeCup_RedA: return "Red A"; + case EyeCup_PinkA: return "Pink A"; + case EyeCup_BlueA: return "Blue A"; + case EyeCup_Delilah1A: return "Delilah 1 A"; + case EyeCup_Delilah2A: return "Delilah 2 A"; + case EyeCup_JamesA: return "James A"; + case EyeCup_SunMandalaA: return "Sun Mandala A"; + case EyeCup_DK2A: return "DK2 A"; + case EyeCup_LAST: return "LAST"; + default: OVR_ASSERT ( false ); return "Error"; } } @@ -59,17 +60,17 @@ char const* GetDebugNameHmdType ( HmdTypeEnum hmdType ) { switch ( hmdType ) { - case HmdType_None: return "None"; break; - case HmdType_DK1: return "DK1"; break; - case HmdType_DKProto: return "DK1 prototype"; break; - case HmdType_DKHDProto: return "DK HD prototype 1"; break; - case HmdType_DKHDProto566Mi: return "DK HD prototype 566 Mi"; break; - case HmdType_DKHD2Proto: return "DK HD prototype 585"; break; - case HmdType_CrystalCoveProto: return "Crystal Cove"; break; - case HmdType_DK2: return "DK2"; break; - case HmdType_Unknown: return "Unknown"; break; - case HmdType_LAST: return "LAST"; break; - default: OVR_ASSERT ( false ); return "Error"; break; + case HmdType_None: return "None"; + case HmdType_DK1: return "DK1"; + case HmdType_DKProto: return "DK1 prototype"; + case HmdType_DKHDProto: return "DK HD prototype 1"; + case HmdType_DKHDProto566Mi: return "DK HD prototype 566 Mi"; + case HmdType_DKHD2Proto: return "DK HD prototype 585"; + case HmdType_CrystalCoveProto: return "Crystal Cove"; + case HmdType_DK2: return "DK2"; + case HmdType_Unknown: return "Unknown"; + case HmdType_LAST: return "LAST"; + default: OVR_ASSERT ( false ); return "Error"; } } @@ -80,7 +81,7 @@ char const* GetDebugNameHmdType ( HmdTypeEnum hmdType ) struct DistortionAndFov { DistortionRenderDesc Distortion; - FovPort Fov; + FovPort Fov; }; static DistortionAndFov CalculateDistortionAndFovInternal ( StereoEye eyeType, HmdRenderInfo const &hmd, @@ -198,14 +199,14 @@ static StereoEyeParams CalculateStereoEyeParamsInternal ( StereoEye eyeType, Hmd // this is the mapping of actual physical eye FOV (and our eyes do not zoom!) // to screen space. ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov ( fov ); - + // The size of the final FB, which is fixed and determined by the physical size of the device display. Recti distortedViewport = GetFramebufferViewport ( eyeType, hmd ); Vector3f virtualCameraOffset = CalculateEyeVirtualCameraOffset(hmd, eyeType, bMonoRenderingMode); StereoEyeParams result; result.Eye = eyeType; - result.ViewAdjust = Matrix4f::Translation(virtualCameraOffset); + result.HmdToEyeViewOffset = Matrix4f::Translation(virtualCameraOffset); result.Distortion = distortion; result.DistortionViewport = distortedViewport; result.Fov = fov; @@ -372,6 +373,8 @@ StereoConfig::StereoConfig(StereoMode mode) Hmd.ResolutionInPixels = Sizei(1280, 800); Hmd.ScreenSizeInMeters = Sizef(0.1498f, 0.0936f); Hmd.ScreenGapSizeInMeters = 0.0f; + Hmd.PelOffsetR = Vector2f ( 0.0f, 0.0f ); + Hmd.PelOffsetB = Vector2f ( 0.0f, 0.0f ); Hmd.CenterFromTopInMeters = 0.0468f; Hmd.LensSeparationInMeters = 0.0635f; Hmd.LensDiameterInMeters = 0.035f; @@ -442,7 +445,7 @@ const StereoEyeParamsWithOrtho& StereoConfig::GetEyeRenderParams(StereoEye eye) UpdateComputedState(); } - static const UByte eyeParamIndices[3] = { 0, 0, 1 }; + static const uint8_t eyeParamIndices[3] = { 0, 0, 1 }; OVR_ASSERT(eye < sizeof(eyeParamIndices)); return EyeRenderParams[eyeParamIndices[eye]]; @@ -544,8 +547,10 @@ void StereoConfig::UpdateComputedState() eyeTypes[1] = StereoEye_Right; break; - default: - OVR_ASSERT( false ); break; + default: + numEyes = 0; + OVR_ASSERT( false ); + break; } // If either of these fire, you've probably forgotten to call SetRendertargetSize() @@ -787,13 +792,106 @@ static const int DMA_NumTrisPerEye = (DMA_GridSize)*(DMA_GridSize)*2; -void DistortionMeshDestroy ( DistortionMeshVertexData *pVertices, UInt16 *pTriangleMeshIndices ) +DistortionMeshVertexData DistortionMeshMakeVertex ( Vector2f screenNDC, + bool rightEye, + const HmdRenderInfo &hmdRenderInfo, + const DistortionRenderDesc &distortion, const ScaleAndOffset2D &eyeToSourceNDC ) +{ + DistortionMeshVertexData result; + + float xOffset = 0.0f; + if (rightEye) + { + xOffset = 1.0f; + } + + Vector2f tanEyeAnglesR, tanEyeAnglesG, tanEyeAnglesB; + TransformScreenNDCToTanFovSpaceChroma ( &tanEyeAnglesR, &tanEyeAnglesG, &tanEyeAnglesB, + distortion, screenNDC ); + + result.TanEyeAnglesR = tanEyeAnglesR; + result.TanEyeAnglesG = tanEyeAnglesG; + result.TanEyeAnglesB = tanEyeAnglesB; + + HmdShutterTypeEnum shutterType = hmdRenderInfo.Shutter.Type; + switch ( shutterType ) + { + case HmdShutter_Global: + result.TimewarpLerp = 0.0f; + break; + case HmdShutter_RollingLeftToRight: + // Retrace is left to right - left eye goes 0.0 -> 0.5, then right goes 0.5 -> 1.0 + result.TimewarpLerp = screenNDC.x * 0.25f + 0.25f; + if (rightEye) + { + result.TimewarpLerp += 0.5f; + } + break; + case HmdShutter_RollingRightToLeft: + // Retrace is right to left - right eye goes 0.0 -> 0.5, then left goes 0.5 -> 1.0 + result.TimewarpLerp = 0.75f - screenNDC.x * 0.25f; + if (rightEye) + { + result.TimewarpLerp -= 0.5f; + } + break; + case HmdShutter_RollingTopToBottom: + // Retrace is top to bottom on both eyes at the same time. + result.TimewarpLerp = screenNDC.y * 0.5f + 0.5f; + break; + default: OVR_ASSERT ( false ); break; + } + + // When does the fade-to-black edge start? Chosen heuristically. + float fadeOutBorderFractionTexture = 0.1f; + float fadeOutBorderFractionTextureInnerEdge = 0.1f; + float fadeOutBorderFractionScreen = 0.1f; + float fadeOutFloor = 0.6f; // the floor controls how much black is in the fade region + + if (hmdRenderInfo.HmdType == HmdType_DK1) + { + fadeOutBorderFractionTexture = 0.3f; + fadeOutBorderFractionTextureInnerEdge = 0.075f; + fadeOutBorderFractionScreen = 0.075f; + fadeOutFloor = 0.25f; + } + + // Fade out at texture edges. + // The furthest out will be the blue channel, because of chromatic aberration (true of any standard lens) + Vector2f sourceTexCoordBlueNDC = TransformTanFovSpaceToRendertargetNDC ( eyeToSourceNDC, tanEyeAnglesB ); + if (rightEye) + { + // The inner edge of the eye texture is usually much more magnified, because it's right against the middle of the screen, not the FOV edge. + // So we want a different scaling factor for that. This code flips the texture NDC so that +1.0 is the inner edge + sourceTexCoordBlueNDC.x = -sourceTexCoordBlueNDC.x; + } + float edgeFadeIn = ( 1.0f / fadeOutBorderFractionTextureInnerEdge ) * ( 1.0f - sourceTexCoordBlueNDC.x ) ; // Inner + edgeFadeIn = Alg::Min ( edgeFadeIn, ( 1.0f / fadeOutBorderFractionTexture ) * ( 1.0f + sourceTexCoordBlueNDC.x ) ); // Outer + edgeFadeIn = Alg::Min ( edgeFadeIn, ( 1.0f / fadeOutBorderFractionTexture ) * ( 1.0f - sourceTexCoordBlueNDC.y ) ); // Upper + edgeFadeIn = Alg::Min ( edgeFadeIn, ( 1.0f / fadeOutBorderFractionTexture ) * ( 1.0f + sourceTexCoordBlueNDC.y ) ); // Lower + + // Also fade out at screen edges. Since this is in pixel space, no need to do inner specially. + float edgeFadeInScreen = ( 1.0f / fadeOutBorderFractionScreen ) * + ( 1.0f - Alg::Max ( Alg::Abs ( screenNDC.x ), Alg::Abs ( screenNDC.y ) ) ); + edgeFadeIn = Alg::Min ( edgeFadeInScreen, edgeFadeIn ) + fadeOutFloor; + + // Note - this is NOT clamped negatively. + // For rendering methods that interpolate over a coarse grid, we need the values to go negative for correct intersection with zero. + result.Shade = Alg::Min ( edgeFadeIn, 1.0f ); + result.ScreenPosNDC.x = 0.5f * screenNDC.x - 0.5f + xOffset; + result.ScreenPosNDC.y = -screenNDC.y; + + return result; +} + + +void DistortionMeshDestroy ( DistortionMeshVertexData *pVertices, uint16_t *pTriangleMeshIndices ) { OVR_FREE ( pVertices ); OVR_FREE ( pTriangleMeshIndices ); } -void DistortionMeshCreate ( DistortionMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices, +void DistortionMeshCreate ( DistortionMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices, int *pNumVertices, int *pNumTriangles, const StereoEyeParams &stereoParams, const HmdRenderInfo &hmdRenderInfo ) { @@ -804,17 +902,17 @@ void DistortionMeshCreate ( DistortionMeshVertexData **ppVertices, UInt16 **ppTr // Generate mesh into allocated data and return result. DistortionMeshCreate(ppVertices, ppTriangleListIndices, &vertexCount, &triangleCount, rightEye, hmdRenderInfo, stereoParams.Distortion, stereoParams.EyeToSourceNDC); - + *pNumVertices = vertexCount; *pNumTriangles = triangleCount; } // Generate distortion mesh for a eye. -void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices, +void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices, int *pNumVertices, int *pNumTriangles, bool rightEye, - const HmdRenderInfo &hmdRenderInfo, + const HmdRenderInfo &hmdRenderInfo, const DistortionRenderDesc &distortion, const ScaleAndOffset2D &eyeToSourceNDC ) { *pNumVertices = DMA_NumVertsPerEye; @@ -822,7 +920,7 @@ void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTri *ppVertices = (DistortionMeshVertexData*) OVR_ALLOC( sizeof(DistortionMeshVertexData) * (*pNumVertices) ); - *ppTriangleListIndices = (UInt16*) OVR_ALLOC( sizeof(UInt16) * (*pNumTriangles) * 3 ); + *ppTriangleListIndices = (uint16_t*) OVR_ALLOC( sizeof(uint16_t) * (*pNumTriangles) * 3 ); if (!*ppVertices || !*ppTriangleListIndices) { @@ -841,20 +939,9 @@ void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTri return; } - // When does the fade-to-black edge start? Chosen heuristically. - const float fadeOutBorderFraction = 0.075f; - - - // Populate vertex buffer info - float xOffset = 0.0f; - float uOffset = 0.0f; - OVR_UNUSED(uOffset); - if (rightEye) - { - xOffset = 1.0f; - uOffset = 0.5f; - } + + // Populate vertex buffer info // First pass - build up raw vertex data. DistortionMeshVertexData* pcurVert = *ppVertices; @@ -870,72 +957,23 @@ void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTri sourceCoordNDC.y = 2.0f * ( (float)y / (float)DMA_GridSize ) - 1.0f; Vector2f tanEyeAngle = TransformRendertargetNDCToTanFovSpace ( eyeToSourceNDC, sourceCoordNDC ); - // This is the function that does the really heavy lifting. + // Find a corresponding screen position. + // Note - this function does not have to be precise - we're just trying to match the mesh tessellation + // with the shape of the distortion to minimise the number of trianlges needed. Vector2f screenNDC = TransformTanFovSpaceToScreenNDC ( distortion, tanEyeAngle, false ); - - // We then need RGB UVs. Since chromatic aberration is generated from screen coords, not - // directly from texture NDCs, we can't just use tanEyeAngle, we need to go the long way round. - Vector2f tanEyeAnglesR, tanEyeAnglesG, tanEyeAnglesB; - TransformScreenNDCToTanFovSpaceChroma ( &tanEyeAnglesR, &tanEyeAnglesG, &tanEyeAnglesB, - distortion, screenNDC ); - - pcurVert->TanEyeAnglesR = tanEyeAnglesR; - pcurVert->TanEyeAnglesG = tanEyeAnglesG; - pcurVert->TanEyeAnglesB = tanEyeAnglesB; - - - HmdShutterTypeEnum shutterType = hmdRenderInfo.Shutter.Type; - switch ( shutterType ) - { - case HmdShutter_Global: - pcurVert->TimewarpLerp = 0.0f; - break; - case HmdShutter_RollingLeftToRight: - // Retrace is left to right - left eye goes 0.0 -> 0.5, then right goes 0.5 -> 1.0 - pcurVert->TimewarpLerp = screenNDC.x * 0.25f + 0.25f; - if (rightEye) - { - pcurVert->TimewarpLerp += 0.5f; - } - break; - case HmdShutter_RollingRightToLeft: - // Retrace is right to left - right eye goes 0.0 -> 0.5, then left goes 0.5 -> 1.0 - pcurVert->TimewarpLerp = 0.75f - screenNDC.x * 0.25f; - if (rightEye) - { - pcurVert->TimewarpLerp -= 0.5f; - } - break; - case HmdShutter_RollingTopToBottom: - // Retrace is top to bottom on both eyes at the same time. - pcurVert->TimewarpLerp = screenNDC.y * 0.5f + 0.5f; - break; - default: OVR_ASSERT ( false ); break; - } - - // Fade out at texture edges. - float edgeFadeIn = ( 1.0f / fadeOutBorderFraction ) * - ( 1.0f - Alg::Max ( Alg::Abs ( sourceCoordNDC.x ), Alg::Abs ( sourceCoordNDC.y ) ) ); - // Also fade out at screen edges. - float edgeFadeInScreen = ( 2.0f / fadeOutBorderFraction ) * - ( 1.0f - Alg::Max ( Alg::Abs ( screenNDC.x ), Alg::Abs ( screenNDC.y ) ) ); - edgeFadeIn = Alg::Min ( edgeFadeInScreen, edgeFadeIn ); - - // Don't let verts overlap to the other eye. + // ...but don't let verts overlap to the other eye. screenNDC.x = Alg::Max ( -1.0f, Alg::Min ( screenNDC.x, 1.0f ) ); screenNDC.y = Alg::Max ( -1.0f, Alg::Min ( screenNDC.y, 1.0f ) ); - pcurVert->Shade = Alg::Max ( 0.0f, Alg::Min ( edgeFadeIn, 1.0f ) ); - pcurVert->ScreenPosNDC.x = 0.5f * screenNDC.x - 0.5f + xOffset; - pcurVert->ScreenPosNDC.y = -screenNDC.y; - + // From those screen positions, generate the vertex. + *pcurVert = DistortionMeshMakeVertex ( screenNDC, rightEye, hmdRenderInfo, distortion, eyeToSourceNDC ); pcurVert++; } } - // Populate index buffer info - UInt16 *pcurIndex = *ppTriangleListIndices; + // Populate index buffer info + uint16_t *pcurIndex = *ppTriangleListIndices; for ( int triNum = 0; triNum < DMA_GridSize * DMA_GridSize; triNum++ ) { @@ -982,23 +1020,23 @@ void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTri // so linear interpolation works better & we can use fewer tris. if ( ( x < DMA_GridSize/2 ) != ( y < DMA_GridSize/2 ) ) // != is logical XOR { - *pcurIndex++ = (UInt16)FirstVertex; - *pcurIndex++ = (UInt16)FirstVertex+1; - *pcurIndex++ = (UInt16)FirstVertex+(DMA_GridSize+1)+1; + *pcurIndex++ = (uint16_t)FirstVertex; + *pcurIndex++ = (uint16_t)FirstVertex+1; + *pcurIndex++ = (uint16_t)FirstVertex+(DMA_GridSize+1)+1; - *pcurIndex++ = (UInt16)FirstVertex+(DMA_GridSize+1)+1; - *pcurIndex++ = (UInt16)FirstVertex+(DMA_GridSize+1); - *pcurIndex++ = (UInt16)FirstVertex; + *pcurIndex++ = (uint16_t)FirstVertex+(DMA_GridSize+1)+1; + *pcurIndex++ = (uint16_t)FirstVertex+(DMA_GridSize+1); + *pcurIndex++ = (uint16_t)FirstVertex; } else { - *pcurIndex++ = (UInt16)FirstVertex; - *pcurIndex++ = (UInt16)FirstVertex+1; - *pcurIndex++ = (UInt16)FirstVertex+(DMA_GridSize+1); + *pcurIndex++ = (uint16_t)FirstVertex; + *pcurIndex++ = (uint16_t)FirstVertex+1; + *pcurIndex++ = (uint16_t)FirstVertex+(DMA_GridSize+1); - *pcurIndex++ = (UInt16)FirstVertex+1; - *pcurIndex++ = (UInt16)FirstVertex+(DMA_GridSize+1)+1; - *pcurIndex++ = (UInt16)FirstVertex+(DMA_GridSize+1); + *pcurIndex++ = (uint16_t)FirstVertex+1; + *pcurIndex++ = (uint16_t)FirstVertex+(DMA_GridSize+1)+1; + *pcurIndex++ = (uint16_t)FirstVertex+(DMA_GridSize+1); } } } @@ -1013,13 +1051,13 @@ static const int HMA_NumVertsPerEye = (HMA_GridSize+1)*(HMA_GridSize+1); static const int HMA_NumTrisPerEye = (HMA_GridSize)*(HMA_GridSize)*2; -void HeightmapMeshDestroy ( HeightmapMeshVertexData *pVertices, UInt16 *pTriangleMeshIndices ) +void HeightmapMeshDestroy ( HeightmapMeshVertexData *pVertices, uint16_t *pTriangleMeshIndices ) { OVR_FREE ( pVertices ); OVR_FREE ( pTriangleMeshIndices ); } -void HeightmapMeshCreate ( HeightmapMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices, +void HeightmapMeshCreate ( HeightmapMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices, int *pNumVertices, int *pNumTriangles, const StereoEyeParams &stereoParams, const HmdRenderInfo &hmdRenderInfo ) { @@ -1037,7 +1075,7 @@ void HeightmapMeshCreate ( HeightmapMeshVertexData **ppVertices, UInt16 **ppTria // Generate heightmap mesh for one eye. -void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices, +void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices, int *pNumVertices, int *pNumTriangles, bool rightEye, const HmdRenderInfo &hmdRenderInfo, const ScaleAndOffset2D &eyeToSourceNDC ) @@ -1046,7 +1084,7 @@ void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, UInt16 **ppTrian *pNumTriangles = HMA_NumTrisPerEye; *ppVertices = (HeightmapMeshVertexData*) OVR_ALLOC( sizeof(HeightmapMeshVertexData) * (*pNumVertices) ); - *ppTriangleListIndices = (UInt16*) OVR_ALLOC( sizeof(UInt16) * (*pNumTriangles) * 3 ); + *ppTriangleListIndices = (uint16_t*) OVR_ALLOC( sizeof(uint16_t) * (*pNumTriangles) * 3 ); if (!*ppVertices || !*ppTriangleListIndices) { @@ -1066,14 +1104,7 @@ void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, UInt16 **ppTrian } // Populate vertex buffer info - float xOffset = 0.0f; - float uOffset = 0.0f; - - if (rightEye) - { - xOffset = 1.0f; - uOffset = 0.5f; - } + // float xOffset = (rightEye ? 1.0f : 0.0f); Currently disabled because its usage is disabled below. // First pass - build up raw vertex data. HeightmapMeshVertexData* pcurVert = *ppVertices; @@ -1087,7 +1118,7 @@ void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, UInt16 **ppTrian sourceCoordNDC.x = 2.0f * ( (float)x / (float)HMA_GridSize ) - 1.0f; sourceCoordNDC.y = 2.0f * ( (float)y / (float)HMA_GridSize ) - 1.0f; Vector2f tanEyeAngle = TransformRendertargetNDCToTanFovSpace ( eyeToSourceNDC, sourceCoordNDC ); - + pcurVert->TanEyeAngles = tanEyeAngle; HmdShutterTypeEnum shutterType = hmdRenderInfo.Shutter.Type; @@ -1132,8 +1163,8 @@ void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, UInt16 **ppTrian } - // Populate index buffer info - UInt16 *pcurIndex = *ppTriangleListIndices; + // Populate index buffer info + uint16_t *pcurIndex = *ppTriangleListIndices; for ( int triNum = 0; triNum < HMA_GridSize * HMA_GridSize; triNum++ ) { @@ -1180,23 +1211,23 @@ void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, UInt16 **ppTrian // so linear interpolation works better & we can use fewer tris. if ( ( x < HMA_GridSize/2 ) != ( y < HMA_GridSize/2 ) ) // != is logical XOR { - *pcurIndex++ = (UInt16)FirstVertex; - *pcurIndex++ = (UInt16)FirstVertex+1; - *pcurIndex++ = (UInt16)FirstVertex+(HMA_GridSize+1)+1; + *pcurIndex++ = (uint16_t)FirstVertex; + *pcurIndex++ = (uint16_t)FirstVertex+1; + *pcurIndex++ = (uint16_t)FirstVertex+(HMA_GridSize+1)+1; - *pcurIndex++ = (UInt16)FirstVertex+(HMA_GridSize+1)+1; - *pcurIndex++ = (UInt16)FirstVertex+(HMA_GridSize+1); - *pcurIndex++ = (UInt16)FirstVertex; + *pcurIndex++ = (uint16_t)FirstVertex+(HMA_GridSize+1)+1; + *pcurIndex++ = (uint16_t)FirstVertex+(HMA_GridSize+1); + *pcurIndex++ = (uint16_t)FirstVertex; } else { - *pcurIndex++ = (UInt16)FirstVertex; - *pcurIndex++ = (UInt16)FirstVertex+1; - *pcurIndex++ = (UInt16)FirstVertex+(HMA_GridSize+1); + *pcurIndex++ = (uint16_t)FirstVertex; + *pcurIndex++ = (uint16_t)FirstVertex+1; + *pcurIndex++ = (uint16_t)FirstVertex+(HMA_GridSize+1); - *pcurIndex++ = (UInt16)FirstVertex+1; - *pcurIndex++ = (UInt16)FirstVertex+(HMA_GridSize+1)+1; - *pcurIndex++ = (UInt16)FirstVertex+(HMA_GridSize+1); + *pcurIndex++ = (uint16_t)FirstVertex+1; + *pcurIndex++ = (uint16_t)FirstVertex+(HMA_GridSize+1)+1; + *pcurIndex++ = (uint16_t)FirstVertex+(HMA_GridSize+1); } } } @@ -1272,10 +1303,10 @@ PredictionValues PredictionGetDeviceValues ( const HmdRenderInfo &hmdRenderInfo, return result; } -Matrix4f TimewarpComputePoseDelta ( Matrix4f const &renderedViewFromWorld, Matrix4f const &predictedViewFromWorld, Matrix4f const&eyeViewAdjust ) +Matrix4f TimewarpComputePoseDelta ( Matrix4f const &renderedViewFromWorld, Matrix4f const &predictedViewFromWorld, Matrix4f const&hmdToEyeViewOffset ) { - Matrix4f worldFromPredictedView = (eyeViewAdjust * predictedViewFromWorld).InvertedHomogeneousTransform(); - Matrix4f matRenderFromNowStart = (eyeViewAdjust * renderedViewFromWorld) * worldFromPredictedView; + Matrix4f worldFromPredictedView = (hmdToEyeViewOffset * predictedViewFromWorld).InvertedHomogeneousTransform(); + Matrix4f matRenderFromNowStart = (hmdToEyeViewOffset * renderedViewFromWorld) * worldFromPredictedView; // The sensor-predicted orientations have: X=right, Y=up, Z=backwards. // The vectors inside the mesh are in NDC to keep the shader simple: X=right, Y=down, Z=forwards. @@ -1306,22 +1337,35 @@ Matrix4f TimewarpComputePoseDelta ( Matrix4f const &renderedViewFromWorld, Matri return matRenderFromNowStart; } -Matrix4f TimewarpComputePoseDeltaPosition ( Matrix4f const &renderedViewFromWorld, Matrix4f const &predictedViewFromWorld, Matrix4f const&eyeViewAdjust ) +Matrix4f TimewarpComputePoseDeltaPosition ( Matrix4f const &renderedViewFromWorld, Matrix4f const &predictedViewFromWorld, Matrix4f const&hmdToEyeViewOffset ) { - Matrix4f worldFromPredictedView = (eyeViewAdjust * predictedViewFromWorld).InvertedHomogeneousTransform(); - Matrix4f matRenderXform = (eyeViewAdjust * renderedViewFromWorld) * worldFromPredictedView; + Matrix4f worldFromPredictedView = (hmdToEyeViewOffset * predictedViewFromWorld).InvertedHomogeneousTransform(); + Matrix4f matRenderXform = (hmdToEyeViewOffset * renderedViewFromWorld) * worldFromPredictedView; return matRenderXform.Inverted(); } TimewarpMachine::TimewarpMachine() -{ + : VsyncEnabled(false), + RenderInfo(), + CurrentPredictionValues(), + DistortionTimeCount(0), + DistortionTimeCurrentStart(0.0), + //DistortionTimes[], + DistortionTimeAverage(0.f), + //EyeRenderPoses[], + LastFramePresentFlushTime(0.0), + PresentFlushToPresentFlushSeconds(0.f), + NextFramePresentFlushTime(0.0) +{ + #if defined(OVR_BUILD_DEBUG) + memset(DistortionTimes, 0, sizeof(DistortionTimes)); + #endif + for ( int i = 0; i < 2; i++ ) { - EyeRenderPoses[i] = Transformf(); + EyeRenderPoses[i] = Posef(); } - DistortionTimeCount = 0; - VsyncEnabled = false; } void TimewarpMachine::Reset(HmdRenderInfo& renderInfo, bool vsyncEnabled, double timeNow) @@ -1338,21 +1382,36 @@ void TimewarpMachine::Reset(HmdRenderInfo& renderInfo, bool vsyncEnabled, double void TimewarpMachine::AfterPresentAndFlush(double timeNow) { + AfterPresentWithoutFlush(); + AfterPresentFinishes ( timeNow ); +} + +void TimewarpMachine::AfterPresentWithoutFlush() +{ + // We've only issued the Present - it hasn't actually finished (i.e. appeared) + // But we need to estimate when the next Present will appear, so extrapolate from previous data. + NextFramePresentFlushTime = LastFramePresentFlushTime + 2.0 * (double)PresentFlushToPresentFlushSeconds; +} + +void TimewarpMachine::AfterPresentFinishes(double timeNow) +{ + // The present has now actually happened. PresentFlushToPresentFlushSeconds = (float)(timeNow - LastFramePresentFlushTime); LastFramePresentFlushTime = timeNow; NextFramePresentFlushTime = timeNow + (double)PresentFlushToPresentFlushSeconds; } + + double TimewarpMachine::GetViewRenderPredictionTime() { // Note that PredictionGetDeviceValues() did all the vsync-dependent thinking for us. return NextFramePresentFlushTime + CurrentPredictionValues.PresentFlushToRenderedScene; } -Transformf TimewarpMachine::GetViewRenderPredictionPose(SensorFusion &sfusion) +bool TimewarpMachine::GetViewRenderPredictionPose(SensorStateReader* reader, Posef& pose) { - double predictionTime = GetViewRenderPredictionTime(); - return sfusion.GetPoseAtTime(predictionTime); + return reader->GetPoseAtTime(GetViewRenderPredictionTime(), pose); } double TimewarpMachine::GetVisiblePixelTimeStart() @@ -1365,31 +1424,43 @@ double TimewarpMachine::GetVisiblePixelTimeEnd() // Note that PredictionGetDeviceValues() did all the vsync-dependent thinking for us. return NextFramePresentFlushTime + CurrentPredictionValues.PresentFlushToTimewarpEnd; } -Transformf TimewarpMachine::GetPredictedVisiblePixelPoseStart(SensorFusion &sfusion) +bool TimewarpMachine::GetPredictedVisiblePixelPoseStart(SensorStateReader* reader, Posef& pose) { - double predictionTime = GetVisiblePixelTimeStart(); - return sfusion.GetPoseAtTime(predictionTime); + return reader->GetPoseAtTime(GetVisiblePixelTimeStart(), pose); } -Transformf TimewarpMachine::GetPredictedVisiblePixelPoseEnd (SensorFusion &sfusion) +bool TimewarpMachine::GetPredictedVisiblePixelPoseEnd(SensorStateReader* reader, Posef& pose) { - double predictionTime = GetVisiblePixelTimeEnd(); - return sfusion.GetPoseAtTime(predictionTime); + return reader->GetPoseAtTime(GetVisiblePixelTimeEnd(), pose); } -Matrix4f TimewarpMachine::GetTimewarpDeltaStart(SensorFusion &sfusion, Transformf const &renderedPose) +bool TimewarpMachine::GetTimewarpDeltaStart(SensorStateReader* reader, Posef const &renderedPose, Matrix4f& transform) { - Transformf visiblePose = GetPredictedVisiblePixelPoseStart ( sfusion ); + Posef visiblePose; + if (!GetPredictedVisiblePixelPoseStart(reader, visiblePose)) + { + return false; + } + Matrix4f visibleMatrix(visiblePose); Matrix4f renderedMatrix(renderedPose); Matrix4f identity; // doesn't matter for orientation-only timewarp - return TimewarpComputePoseDelta ( renderedMatrix, visibleMatrix, identity ); + transform = TimewarpComputePoseDelta ( renderedMatrix, visibleMatrix, identity ); + + return true; } -Matrix4f TimewarpMachine::GetTimewarpDeltaEnd (SensorFusion &sfusion, Transformf const &renderedPose) +bool TimewarpMachine::GetTimewarpDeltaEnd(SensorStateReader* reader, Posef const &renderedPose, Matrix4f& transform) { - Transformf visiblePose = GetPredictedVisiblePixelPoseEnd ( sfusion ); + Posef visiblePose; + if (!GetPredictedVisiblePixelPoseEnd(reader, visiblePose)) + { + return false; + } + Matrix4f visibleMatrix(visiblePose); Matrix4f renderedMatrix(renderedPose); Matrix4f identity; // doesn't matter for orientation-only timewarp - return TimewarpComputePoseDelta ( renderedMatrix, visibleMatrix, identity ); + transform = TimewarpComputePoseDelta ( renderedMatrix, visibleMatrix, identity ); + + return true; } @@ -1402,19 +1473,30 @@ double TimewarpMachine::JustInTime_GetDistortionWaitUntilTime() return LastFramePresentFlushTime; } - const float fudgeFactor = 0.002f; // Found heuristically - 1ms is too short because of timing granularity - may need further tweaking! - float howLongBeforePresent = DistortionTimeAverage + fudgeFactor; + // Note - 1-2ms fudge factor (because Windows timer granularity etc) is NOT added here, + // because otherwise you end up adding multiple fudge factors! + // So it's left for the calling app to add just one fudge factor. + + float howLongBeforePresent = DistortionTimeAverage; // Subtlety here. Technically, the correct time is NextFramePresentFlushTime - howLongBeforePresent. // However, if the app drops a frame, this then perpetuates it, // i.e. if the display is running at 60fps, but the last frame was slow, // (e.g. because of swapping or whatever), then NextFramePresentFlushTime is - // 33ms in the future, not 16ms. Since this function supplies the + // 33ms in the future, not 16ms. Since this function supplies the // time to wait until, the app will indeed wait until 32ms, so the framerate // drops to 30fps and never comes back up! // So we return the *ideal* framerate, not the *actual* framerate. return LastFramePresentFlushTime + (float)( CurrentPredictionValues.PresentFlushToPresentFlush - howLongBeforePresent ); } +double TimewarpMachine::JustInTime_AverageDistortionTime() +{ + if ( JustInTime_NeedDistortionTimeMeasurement() ) + { + return 0.0; + } + return DistortionTimeAverage; +} bool TimewarpMachine::JustInTime_NeedDistortionTimeMeasurement() const { diff --git a/LibOVR/Src/Util/Util_Render_Stereo.h b/LibOVR/Src/Util/Util_Render_Stereo.h index 326059e..2ac863c 100644 --- a/LibOVR/Src/Util/Util_Render_Stereo.h +++ b/LibOVR/Src/Util/Util_Render_Stereo.h @@ -1,21 +1,20 @@ /************************************************************************************ -PublicHeader: OVR.h Filename : Util_Render_Stereo.h Content : Sample stereo rendering configuration classes. Created : October 22, 2012 Authors : Michael Antonov, Tom Forsyth -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +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.1 +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, @@ -29,13 +28,9 @@ limitations under the License. #define OVR_Util_Render_Stereo_h #include "../OVR_Stereo.h" +#include "../Tracking/Tracking_SensorStateReader.h" - -namespace OVR { - -class SensorFusion; - -namespace Util { namespace Render { +namespace OVR { namespace Util { namespace Render { @@ -333,20 +328,25 @@ struct DistortionMeshVertexData Vector2f TanEyeAnglesB; }; +// If you just want a single point on the screen transformed. +DistortionMeshVertexData DistortionMeshMakeVertex ( Vector2f screenNDC, + bool rightEye, + const HmdRenderInfo &hmdRenderInfo, + const DistortionRenderDesc &distortion, const ScaleAndOffset2D &eyeToSourceNDC ); -void DistortionMeshCreate ( DistortionMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices, +void DistortionMeshCreate ( DistortionMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices, int *pNumVertices, int *pNumTriangles, const StereoEyeParams &stereoParams, const HmdRenderInfo &hmdRenderInfo ); -// Generate distortion mesh for a eye. This version requires less data then stereoParms, supporting -// dynamic change in render target viewport. -void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices, +// Generate distortion mesh for a eye. +// This version requires less data then stereoParms, supporting dynamic change in render target viewport. +void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices, int *pNumVertices, int *pNumTriangles, bool rightEye, const HmdRenderInfo &hmdRenderInfo, const DistortionRenderDesc &distortion, const ScaleAndOffset2D &eyeToSourceNDC ); -void DistortionMeshDestroy ( DistortionMeshVertexData *pVertices, UInt16 *pTriangleMeshIndices ); +void DistortionMeshDestroy ( DistortionMeshVertexData *pVertices, uint16_t *pTriangleMeshIndices ); //----------------------------------------------------------------------------------- @@ -368,17 +368,17 @@ struct HeightmapMeshVertexData }; -void HeightmapMeshCreate ( HeightmapMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices, +void HeightmapMeshCreate ( HeightmapMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices, int *pNumVertices, int *pNumTriangles, const StereoEyeParams &stereoParams, const HmdRenderInfo &hmdRenderInfo ); // Generate heightmap mesh for a eye. This version requires less data then stereoParms, supporting // dynamic change in render target viewport. -void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices, +void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices, int *pNumVertices, int *pNumTriangles, bool rightEye, const HmdRenderInfo &hmdRenderInfo, const ScaleAndOffset2D &eyeToSourceNDC ); -void HeightmapMeshDestroy ( HeightmapMeshVertexData *pVertices, UInt16 *pTriangleMeshIndices ); +void HeightmapMeshDestroy ( HeightmapMeshVertexData *pVertices, uint16_t *pTriangleMeshIndices ); @@ -411,8 +411,8 @@ PredictionValues PredictionGetDeviceValues ( const HmdRenderInfo &hmdRenderInfo, // (which may have been computed later on, and thus is more accurate), and this // will return the matrix to pass to the timewarp distortion shader. // TODO: deal with different handedness? -Matrix4f TimewarpComputePoseDelta ( Matrix4f const &renderedViewFromWorld, Matrix4f const &predictedViewFromWorld, Matrix4f const&eyeViewAdjust ); -Matrix4f TimewarpComputePoseDeltaPosition ( Matrix4f const &renderedViewFromWorld, Matrix4f const &predictedViewFromWorld, Matrix4f const&eyeViewAdjust ); +Matrix4f TimewarpComputePoseDelta ( Matrix4f const &renderedViewFromWorld, Matrix4f const &predictedViewFromWorld, Matrix4f const&hmdToEyeViewOffset ); +Matrix4f TimewarpComputePoseDeltaPosition ( Matrix4f const &renderedViewFromWorld, Matrix4f const &predictedViewFromWorld, Matrix4f const&hmdToEyeViewOffset ); @@ -429,12 +429,16 @@ public: // The only reliable time in most engines is directly after the frame-present and GPU flush-and-wait. // This call should be done right after that to give this system the timing info it needs. void AfterPresentAndFlush(double timeNow); + // But some engines queue up the frame-present and only later find out when it actually happened. + // They should call these two at those times. + void AfterPresentWithoutFlush(); + void AfterPresentFinishes(double timeNow); // The "average" time the rendered frame will show up, // and the predicted pose of the HMD at that time. // You usually only need to call one of these functions. double GetViewRenderPredictionTime(); - Transformf GetViewRenderPredictionPose(SensorFusion &sfusion); + bool GetViewRenderPredictionPose(Tracking::SensorStateReader* reader, Posef& transform); // Timewarp prediction functions. You usually only need to call one of these three sets of functions. @@ -443,14 +447,13 @@ public: double GetVisiblePixelTimeStart(); double GetVisiblePixelTimeEnd(); // Predicted poses of the HMD at those first and last pixels. - Transformf GetPredictedVisiblePixelPoseStart(SensorFusion &sfusion); - Transformf GetPredictedVisiblePixelPoseEnd (SensorFusion &sfusion); + bool GetPredictedVisiblePixelPoseStart(Tracking::SensorStateReader* reader, Posef& transform); + bool GetPredictedVisiblePixelPoseEnd(Tracking::SensorStateReader* reader, Posef& transform); // The delta matrices to feed to the timewarp distortion code, // given the pose that was used for rendering. // (usually the one returned by GetViewRenderPredictionPose() earlier) - Matrix4f GetTimewarpDeltaStart(SensorFusion &sfusion, Transformf const &renderedPose); - Matrix4f GetTimewarpDeltaEnd (SensorFusion &sfusion, Transformf const &renderedPose); - + bool GetTimewarpDeltaStart(Tracking::SensorStateReader* reader, Posef const &renderedPose, Matrix4f& transform); + bool GetTimewarpDeltaEnd(Tracking::SensorStateReader* reader, Posef const &renderedPose, Matrix4f& transform); // Just-In-Time distortion aims to delay the second sensor reading & distortion // until the very last moment to improve prediction. However, it is a little scary, @@ -465,26 +468,25 @@ public: bool JustInTime_NeedDistortionTimeMeasurement() const; void JustInTime_BeforeDistortionTimeMeasurement(double timeNow); void JustInTime_AfterDistortionTimeMeasurement(double timeNow); - + double JustInTime_AverageDistortionTime(); // Just for profiling - use JustInTime_GetDistortionWaitUntilTime() for functionality. private: - bool VsyncEnabled; HmdRenderInfo RenderInfo; PredictionValues CurrentPredictionValues; - enum { NumDistortionTimes = 10 }; + enum { NumDistortionTimes = 100 }; int DistortionTimeCount; double DistortionTimeCurrentStart; float DistortionTimes[NumDistortionTimes]; float DistortionTimeAverage; // Pose at which last time the eye was rendered. - Transformf EyeRenderPoses[2]; + Posef EyeRenderPoses[2]; // Absolute time of the last present+flush double LastFramePresentFlushTime; - // Seconds between presentflushes + // Seconds between present+flushes float PresentFlushToPresentFlushSeconds; // Predicted absolute time of the next present+flush double NextFramePresentFlushTime; diff --git a/LibOVR/Src/Util/Util_SystemGUI.cpp b/LibOVR/Src/Util/Util_SystemGUI.cpp new file mode 100644 index 0000000..76eb890 --- /dev/null +++ b/LibOVR/Src/Util/Util_SystemGUI.cpp @@ -0,0 +1,190 @@ +/************************************************************************************ + +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" +#include <stdio.h> + +#if defined(OVR_OS_MS) + #include <Windows.h> +#endif + + +namespace OVR { namespace Util { + + +#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; + } + + return FALSE; + } + }; + + + char dialogTemplateMemory[1024]; + memset(dialogTemplateMemory, 0, sizeof(dialogTemplateMemory)); + DLGTEMPLATE* pDlg = (LPDLGTEMPLATE)dialogTemplateMemory; + + 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 = 600; // To do: Clip this against screen bounds. + const int kDialogHeight = ((textLineCount > 100) ? 400 : ((textLineCount > 25) ? 300 : 200)); + + // 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/LibOVR/Src/Util/Util_SystemGUI.h b/LibOVR/Src/Util/Util_SystemGUI.h new file mode 100644 index 0000000..c6b8d6f --- /dev/null +++ b/LibOVR/Src/Util/Util_SystemGUI.h @@ -0,0 +1,39 @@ +/************************************************************************************ + +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); + + +} } // namespace OVR::Util + + +#endif diff --git a/LibOVR/Src/Util/Util_SystemGUI_OSX.mm b/LibOVR/Src/Util/Util_SystemGUI_OSX.mm new file mode 100644 index 0000000..cbfd057 --- /dev/null +++ b/LibOVR/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/LibOVR/Src/Util/Util_SystemInfo.cpp b/LibOVR/Src/Util/Util_SystemInfo.cpp new file mode 100644 index 0000000..0fca243 --- /dev/null +++ b/LibOVR/Src/Util/Util_SystemInfo.cpp @@ -0,0 +1,289 @@ +/************************************************************************************ + +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" + +/* +// 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(GetModuleHandle(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++; + } +} +#else + +// used for driver files + +String GetFileVersionString(String /*filePath*/) +{ + return String(); +} + +String GetSystemFileVersionString(String /*filePath*/) +{ + return String(); +} + +String GetDisplayDriverVersion() +{ + return String(); +} + +String GetCameraDriverVersion() +{ + return String(); +} + +#ifdef OVR_OS_MAC + //use objective c source +#else + +//todo linux, this requires searching /var/ files +void GetGraphicsCardList(OVR::Array< OVR::String > &gpus) +{ + gpus.Clear(); +} +String OSVersionAsString() +{ + return String(); +} +#endif //OVR_OS_MAC +#endif // WIN32 + +} } // namespace OVR { namespace Util { diff --git a/LibOVR/Src/Util/Util_SystemInfo.h b/LibOVR/Src/Util/Util_SystemInfo.h new file mode 100644 index 0000000..b150560 --- /dev/null +++ b/LibOVR/Src/Util/Util_SystemInfo.h @@ -0,0 +1,51 @@ +/************************************************************************************ + +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(int* numcores = NULL); + +} } // namespace OVR { namespace Util { + +#endif // OVR_Util_SystemInfo_h diff --git a/LibOVR/Src/Util/Util_SystemInfo_OSX.mm b/LibOVR/Src/Util/Util_SystemInfo_OSX.mm new file mode 100644 index 0000000..46799fb --- /dev/null +++ b/LibOVR/Src/Util/Util_SystemInfo_OSX.mm @@ -0,0 +1,106 @@ + /************************************************************************************
+
+ 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);
+ }
+}
+
+} } // namespace OVR { namespace Util {
+
|