Skip to content
This repository was archived by the owner on Sep 10, 2022. It is now read-only.

Commit bb9f5eb

Browse files
committed
Support for the Oculus Latency Tester. Tested only on Mac so far.
1 parent 80e0a07 commit bb9f5eb

File tree

9 files changed

+298
-3
lines changed

9 files changed

+298
-3
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
[submodule "third_party/gyp"]
55
path = third_party/gyp
66
url = https://chromium.googlesource.com/external/gyp.git
7+
[submodule "third_party/LibOVR"]
8+
path = third_party/LibOVR
9+
url = git@github.com:jdarpinian/LibOVR.git

html/hardware-latency-test.html

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<!DOCTYPE html>
2+
<meta charset="utf-8">
3+
<meta http-equiv="x-ua-compatible" content="IE=edge">
4+
<title>Web Latency Benchmark</title>
5+
<link rel="stylesheet" href="latency-benchmark.css">
6+
7+
<h1>Web Latency Test: End-To-End</h1>
8+
This test requires specialized hardware: an <a href="https://www.oculusvr.com/order/latency-tester/">Oculus Latency Tester</a> device. Point it at the square below and press 'T' to start the test.
9+
<p>
10+
<canvas id="testCanvas" width="300" height="300" style="border: 10px solid gray"></canvas>
11+
12+
<p>
13+
<label><input type="checkbox" id="cpuLoad"/> add CPU load</label><br/>
14+
15+
<div id="results">
16+
17+
<script src="keep-server-alive.js"></script>
18+
<script>
19+
var cpuLoad = document.getElementById('cpuLoad');
20+
var testCanvas = document.getElementById('testCanvas');
21+
var gl = testCanvas.getContext('webgl') || testCanvas.getContext('experimental-webgl');
22+
var color = [0, 0, 0];
23+
24+
window.onkeydown = function(e) {
25+
if (e.keyCode == 66) {
26+
// 'B' for black.
27+
color = [0, 0, 0];
28+
}
29+
if (e.keyCode == 87) {
30+
// 'W' for white.
31+
color = [1, 1, 1];
32+
}
33+
if (e.keyCode == 84) {
34+
// 'T' for test.
35+
startTest();
36+
}
37+
};
38+
39+
function draw() {
40+
requestAnimationFrame(draw);
41+
gl.clearColor(color[0], color[1], color[2], 1);
42+
gl.clear(gl.COLOR_BUFFER_BIT);
43+
if (cpuLoad.checked) {
44+
var startTime = Date.now();
45+
while(Date.now() - startTime < 14);
46+
}
47+
}
48+
draw();
49+
50+
function startTest() {
51+
var request = new XMLHttpRequest();
52+
request.open('GET', 'http://localhost:5578/oculusLatencyTester', true);
53+
request.onreadystatechange = function() {
54+
if (request.readyState == 4) {
55+
if (request.status == 200) {
56+
alert(request.response);
57+
} else if (request.status == 500) {
58+
alert(request.response);
59+
} else {
60+
alert('unknown');
61+
}
62+
}
63+
};
64+
request.send();
65+
}
66+
</script>

latency-benchmark.gyp

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
'src/latency-benchmark.h',
99
'src/screenscraper.h',
1010
'src/server.c',
11+
'src/oculus.cpp',
12+
'src/oculus.h',
1113
'<(INTERMEDIATE_DIR)/packaged-html-files.c',
1214
],
1315
'dependencies': [
1416
'mongoose',
17+
'libovr',
1518
],
1619
'actions': [
1720
{
@@ -22,6 +25,7 @@
2225
'html/compatibility.js',
2326
'html/draw-pattern.js',
2427
'html/gradient.png',
28+
'html/hardware-latency-test.html',
2529
'html/index.html',
2630
'html/keep-server-alive.js',
2731
'html/latency-benchmark.css',
@@ -59,6 +63,7 @@
5963
'libraries': [
6064
'$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
6165
'$(SDKROOT)/System/Library/Frameworks/CoreVideo.framework',
66+
'$(SDKROOT)/System/Library/Frameworks/IOKit.framework',
6267
'$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
6368
],
6469
},
@@ -78,6 +83,121 @@
7883
'third_party/mongoose/mongoose.h',
7984
],
8085
},
86+
{
87+
'target_name': 'libovr',
88+
'type': 'static_library',
89+
'sources': [
90+
'third_party/LibOVR/Include/OVR.h',
91+
'third_party/LibOVR/Include/OVRVersion.h',
92+
'third_party/LibOVR/Src/Kernel/OVR_Alg.cpp',
93+
'third_party/LibOVR/Src/Kernel/OVR_Alg.h',
94+
'third_party/LibOVR/Src/Kernel/OVR_Allocator.cpp',
95+
'third_party/LibOVR/Src/Kernel/OVR_Allocator.h',
96+
'third_party/LibOVR/Src/Kernel/OVR_Array.h',
97+
'third_party/LibOVR/Src/Kernel/OVR_Atomic.cpp',
98+
'third_party/LibOVR/Src/Kernel/OVR_Atomic.h',
99+
'third_party/LibOVR/Src/Kernel/OVR_Color.h',
100+
'third_party/LibOVR/Src/Kernel/OVR_ContainerAllocator.h',
101+
'third_party/LibOVR/Src/Kernel/OVR_File.cpp',
102+
'third_party/LibOVR/Src/Kernel/OVR_File.h',
103+
'third_party/LibOVR/Src/Kernel/OVR_FileFILE.cpp',
104+
'third_party/LibOVR/Src/Kernel/OVR_Hash.h',
105+
'third_party/LibOVR/Src/Kernel/OVR_KeyCodes.h',
106+
'third_party/LibOVR/Src/Kernel/OVR_List.h',
107+
'third_party/LibOVR/Src/Kernel/OVR_Log.cpp',
108+
'third_party/LibOVR/Src/Kernel/OVR_Log.h',
109+
'third_party/LibOVR/Src/Kernel/OVR_Math.cpp',
110+
'third_party/LibOVR/Src/Kernel/OVR_Math.h',
111+
'third_party/LibOVR/Src/Kernel/OVR_RefCount.cpp',
112+
'third_party/LibOVR/Src/Kernel/OVR_RefCount.h',
113+
'third_party/LibOVR/Src/Kernel/OVR_Std.cpp',
114+
'third_party/LibOVR/Src/Kernel/OVR_Std.h',
115+
'third_party/LibOVR/Src/Kernel/OVR_String.cpp',
116+
'third_party/LibOVR/Src/Kernel/OVR_String.h',
117+
'third_party/LibOVR/Src/Kernel/OVR_String_FormatUtil.cpp',
118+
'third_party/LibOVR/Src/Kernel/OVR_String_PathUtil.cpp',
119+
'third_party/LibOVR/Src/Kernel/OVR_StringHash.h',
120+
'third_party/LibOVR/Src/Kernel/OVR_SysFile.cpp',
121+
'third_party/LibOVR/Src/Kernel/OVR_SysFile.h',
122+
'third_party/LibOVR/Src/Kernel/OVR_System.cpp',
123+
'third_party/LibOVR/Src/Kernel/OVR_System.h',
124+
'third_party/LibOVR/Src/Kernel/OVR_Threads.h',
125+
'third_party/LibOVR/Src/Kernel/OVR_Timer.cpp',
126+
'third_party/LibOVR/Src/Kernel/OVR_Timer.h',
127+
'third_party/LibOVR/Src/Kernel/OVR_Types.h',
128+
'third_party/LibOVR/Src/Kernel/OVR_UTF8Util.cpp',
129+
'third_party/LibOVR/Src/Kernel/OVR_UTF8Util.h',
130+
'third_party/LibOVR/Src/OVR_Device.h',
131+
'third_party/LibOVR/Src/OVR_DeviceConstants.h',
132+
'third_party/LibOVR/Src/OVR_DeviceHandle.cpp',
133+
'third_party/LibOVR/Src/OVR_DeviceHandle.h',
134+
'third_party/LibOVR/Src/OVR_DeviceImpl.cpp',
135+
'third_party/LibOVR/Src/OVR_DeviceImpl.h',
136+
'third_party/LibOVR/Src/OVR_DeviceMessages.h',
137+
'third_party/LibOVR/Src/OVR_HIDDevice.h',
138+
'third_party/LibOVR/Src/OVR_HIDDeviceBase.h',
139+
'third_party/LibOVR/Src/OVR_HIDDeviceImpl.h',
140+
'third_party/LibOVR/Src/OVR_JSON.cpp',
141+
'third_party/LibOVR/Src/OVR_JSON.h',
142+
'third_party/LibOVR/Src/OVR_LatencyTestImpl.cpp',
143+
'third_party/LibOVR/Src/OVR_LatencyTestImpl.h',
144+
'third_party/LibOVR/Src/OVR_Profile.cpp',
145+
'third_party/LibOVR/Src/OVR_Profile.h',
146+
'third_party/LibOVR/Src/OVR_SensorFilter.cpp',
147+
'third_party/LibOVR/Src/OVR_SensorFilter.h',
148+
'third_party/LibOVR/Src/OVR_SensorFusion.cpp',
149+
'third_party/LibOVR/Src/OVR_SensorFusion.h',
150+
'third_party/LibOVR/Src/OVR_SensorImpl.cpp',
151+
'third_party/LibOVR/Src/OVR_SensorImpl.h',
152+
'third_party/LibOVR/Src/OVR_ThreadCommandQueue.cpp',
153+
'third_party/LibOVR/Src/OVR_ThreadCommandQueue.h',
154+
'third_party/LibOVR/Src/Util/Util_LatencyTest.cpp',
155+
'third_party/LibOVR/Src/Util/Util_LatencyTest.h',
156+
'third_party/LibOVR/Src/Util/Util_Render_Stereo.cpp',
157+
'third_party/LibOVR/Src/Util/Util_Render_Stereo.h',
158+
],
159+
'conditions': [
160+
['OS=="linux"', {
161+
'sources': [
162+
'third_party/LibOVR/Src/OVR_Linux_DeviceManager.cpp',
163+
'third_party/LibOVR/Src/OVR_Linux_DeviceManager.h',
164+
'third_party/LibOVR/Src/OVR_Linux_HIDDevice.cpp',
165+
'third_party/LibOVR/Src/OVR_Linux_HIDDevice.h',
166+
'third_party/LibOVR/Src/OVR_Linux_HMDDevice.cpp',
167+
'third_party/LibOVR/Src/OVR_Linux_HMDDevice.h',
168+
'third_party/LibOVR/Src/OVR_Linux_SensorDevice.cpp',
169+
'third_party/LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp',
170+
],
171+
}],
172+
['OS=="win"', {
173+
'sources': [
174+
'third_party/LibOVR/Src/OVR_Win32_DeviceManager.cpp',
175+
'third_party/LibOVR/Src/OVR_Win32_DeviceManager.h',
176+
'third_party/LibOVR/Src/OVR_Win32_DeviceStatus.cpp',
177+
'third_party/LibOVR/Src/OVR_Win32_DeviceStatus.h',
178+
'third_party/LibOVR/Src/OVR_Win32_HIDDevice.cpp',
179+
'third_party/LibOVR/Src/OVR_Win32_HIDDevice.h',
180+
'third_party/LibOVR/Src/OVR_Win32_HMDDevice.cpp',
181+
'third_party/LibOVR/Src/OVR_Win32_HMDDevice.h',
182+
'third_party/LibOVR/Src/OVR_Win32_SensorDevice.cpp',
183+
'third_party/LibOVR/Src/OVR_Win32_SensorDevice.h',
184+
'third_party/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp',
185+
],
186+
}],
187+
['OS=="mac"', {
188+
'sources': [
189+
'third_party/LibOVR/Src/OVR_OSX_DeviceManager.cpp',
190+
'third_party/LibOVR/Src/OVR_OSX_DeviceManager.h',
191+
'third_party/LibOVR/Src/OVR_OSX_HIDDevice.cpp',
192+
'third_party/LibOVR/Src/OVR_OSX_HIDDevice.h',
193+
'third_party/LibOVR/Src/OVR_OSX_HMDDevice.cpp',
194+
'third_party/LibOVR/Src/OVR_OSX_HMDDevice.h',
195+
'third_party/LibOVR/Src/OVR_OSX_SensorDevice.cpp',
196+
'third_party/LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp',
197+
],
198+
}],
199+
],
200+
}
81201
],
82202

83203
'target_defaults': {

src/mac/screenscraper.m

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,20 @@ void free_screenshot(screenshot *shot) {
105105
free(shot);
106106
}
107107

108-
bool send_keystroke_z() {
109-
CGEventRef down = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, true);
110-
CGEventRef up = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, false);
108+
bool send_keystroke(int keyCode) {
109+
CGEventRef down = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)keyCode, true);
110+
CGEventRef up = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)keyCode, false);
111111
CGEventPost(kCGHIDEventTap, down);
112112
CGEventPost(kCGHIDEventTap, up);
113113
CFRelease(down);
114114
CFRelease(up);
115115
return true;
116116
}
117117

118+
bool send_keystroke_z() { send_keystroke(6); }
119+
bool send_keystroke_b() { send_keystroke(11); }
120+
bool send_keystroke_w() { send_keystroke(13); }
121+
118122
bool send_scroll_down(x, y) {
119123
CGFloat devicePixelRatio =
120124
[[[NSScreen screens] objectAtIndex:0] backingScaleFactor];

src/oculus.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include "../third_party/LibOVR/Include/OVR.h"
2+
extern "C" {
3+
#include "screenscraper.h"
4+
#include "oculus.h"
5+
}
6+
7+
extern "C" bool run_hardware_latency_test(const char **result) {
8+
assert(result);
9+
*result = "Unknown error";
10+
// Initialize the Oculus library and connect to the latency tester device.
11+
OVR::System::Init();
12+
OVR::DeviceManager *manager = OVR::DeviceManager::Create();
13+
OVR::LatencyTestDevice *latency_device = manager->EnumerateDevices<OVR::LatencyTestDevice>().CreateDevice();
14+
manager->Release();
15+
// Check that the latency tester is plugged in.
16+
if (!latency_device) {
17+
*result = "Oculus latency tester not found.";
18+
return false;
19+
}
20+
OVR::Util::LatencyTest latency_util;
21+
latency_util.SetDevice(latency_device);
22+
latency_device->Release();
23+
// Main test loop.
24+
latency_util.BeginTest();
25+
int displayed_color = -1;
26+
while (true) {
27+
latency_util.ProcessInputs();
28+
OVR::Color color;
29+
latency_util.DisplayScreenColor(color);
30+
if (color.R != displayed_color) {
31+
if (color.R == 255 && color.G == 255 && color.B == 255) {
32+
// Display white.
33+
send_keystroke_w();
34+
} else if (color.R == 0 && color.G == 0 && color.B == 0) {
35+
// Display black.
36+
send_keystroke_b();
37+
} else {
38+
// We can only display white or black.
39+
latency_util.SetDevice(NULL);
40+
*result = "Unexpected color requested by latency tester.";
41+
return false;
42+
}
43+
displayed_color = color.R;
44+
}
45+
const char *oculusResults = latency_util.GetResultsString();
46+
if (oculusResults != NULL) {
47+
// Success!
48+
*result = oculusResults;
49+
latency_util.SetDevice(NULL);
50+
return true;
51+
}
52+
usleep(1000);
53+
// TODO: timeout
54+
}
55+
// TODO: try this
56+
//OVR::System::Destroy();
57+
}

src/oculus.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2013 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef WLB_OCULUS_H_
18+
#define WLB_OCULUS_H_
19+
20+
bool run_hardware_latency_test(const char **result_or_error);
21+
22+
#endif // WLB_OCULUS_H_

src/screenscraper.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ void free_screenshot(screenshot *screenshot);
6060
// Sends key down and key up events to the foreground window for the 'z' key.
6161
// Returns true on success, false on failure.
6262
bool send_keystroke_z();
63+
bool send_keystroke_b();
64+
bool send_keystroke_w();
65+
6366
// Warps the mouse to the given point and sends a mousewheel scroll down event.
6467
// Returns true on success, false on failure.
6568
bool send_scroll_down(int x, int y);

src/server.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "screenscraper.h"
2525
#include "latency-benchmark.h"
2626
#include "../third_party/mongoose/mongoose.h"
27+
#include "oculus.h"
2728

2829
// Serve files from the ./html directory.
2930
static const char * const document_root = "html";
@@ -187,6 +188,24 @@ static int mongoose_begin_request_callback(struct mg_connection *connection) {
187188
report_latency(connection, test_pattern);
188189
close_native_reference_window();
189190
return 1;
191+
} else if (strcmp(request_info->uri, "/oculusLatencyTester") == 0) {
192+
const char *result_or_error = "Unknown error";
193+
if (run_hardware_latency_test(&result_or_error)) {
194+
debug_log("hardware latency test succeeded");
195+
mg_printf(connection, "HTTP/1.1 200 OK\r\n"
196+
"Access-Control-Allow-Origin: *\r\n"
197+
"Cache-Control: no-cache\r\n"
198+
"Content-Type: text/plain\r\n\r\n"
199+
"%s", result_or_error);
200+
} else {
201+
debug_log("hardware latency test failed");
202+
mg_printf(connection, "HTTP/1.1 500 Internal Server Error\r\n"
203+
"Access-Control-Allow-Origin: *\r\n"
204+
"Cache-Control: no-cache\r\n"
205+
"Content-Type: text/plain\r\n\r\n"
206+
"%s", result_or_error);
207+
}
208+
return 1;
190209
} else {
191210
#ifdef NDEBUG
192211
// In release mode, we embed the test files in the executable and serve

third_party/LibOVR

Submodule LibOVR added at 8817d38

0 commit comments

Comments
 (0)