oculus1

view libovr/Src/Util/Util_LatencyTest.cpp @ 1:e2f9e4603129

added LibOVR and started a simple vr wrapper.
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 14 Sep 2013 16:14:59 +0300
parents
children b069a5c27388
line source
1 /************************************************************************************
3 Filename : Util_LatencyTest.cpp
4 Content : Wraps the lower level LatencyTester interface and adds functionality.
5 Created : February 14, 2013
6 Authors : Lee Cooper
8 Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
10 Use of this software is subject to the terms of the Oculus license
11 agreement provided at the time of installation or download, or which
12 otherwise accompanies this software in either electronic or hard copy form.
14 *************************************************************************************/
16 #include "Util_LatencyTest.h"
18 #include "../Kernel/OVR_Log.h"
19 #include "../Kernel/OVR_Timer.h"
21 namespace OVR { namespace Util {
23 static const UInt32 TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION = 16*10;
24 static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION = 16*10;
25 static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT = 16*5;
26 static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS = 16*5;
27 static const UInt32 DEFAULT_NUMBER_OF_SAMPLES = 10; // For both color 1->2 and color 2->1 transitions.
28 static const UInt32 INITIAL_SAMPLES_TO_IGNORE = 4;
29 static const UInt32 TIMEOUT_WAITING_FOR_TEST_STARTED = 1000;
30 static const UInt32 TIMEOUT_WAITING_FOR_COLOR_DETECTED = 4000;
31 static const Color CALIBRATE_BLACK(0, 0, 0);
32 static const Color CALIBRATE_WHITE(255, 255, 255);
33 static const Color COLOR1(0, 0, 0);
34 static const Color COLOR2(255, 255, 255);
35 static const Color SENSOR_DETECT_THRESHOLD(128, 255, 255);
36 static const float BIG_FLOAT = 1000000.0f;
37 static const float SMALL_FLOAT = -1000000.0f;
39 //-------------------------------------------------------------------------------------
40 // ***** LatencyTest
42 LatencyTest::LatencyTest(LatencyTestDevice* device)
43 : Handler(getThis())
44 {
45 if (device != NULL)
46 {
47 SetDevice(device);
48 }
50 reset();
52 srand(Timer::GetTicksMs());
53 }
55 LatencyTest::~LatencyTest()
56 {
57 clearMeasurementResults();
58 }
60 bool LatencyTest::SetDevice(LatencyTestDevice* device)
61 {
63 if (device != Device)
64 {
65 if (device != NULL)
66 {
67 if (device->GetMessageHandler() != NULL)
68 {
69 OVR_DEBUG_LOG(
70 ("LatencyTest::AttachToDevice failed - device %p already has handler", device));
71 return false;
72 }
73 }
75 if (Device != NULL)
76 {
77 Device->SetMessageHandler(0);
78 }
79 Device = device;
81 if (Device != NULL)
82 {
83 Device->SetMessageHandler(&Handler);
85 // Set trigger threshold.
86 LatencyTestConfiguration configuration(SENSOR_DETECT_THRESHOLD, false); // No samples streaming.
87 Device->SetConfiguration(configuration, true);
89 // Set display to intial (3 dashes).
90 LatencyTestDisplay ltd(2, 0x40400040);
91 Device->SetDisplay(ltd);
92 }
93 }
95 return true;
96 }
98 UInt32 LatencyTest::getRandomComponent(UInt32 range)
99 {
100 UInt32 val = rand() % range;
101 return val;
102 }
104 void LatencyTest::BeginTest()
105 {
106 if (State == State_WaitingForButton)
107 {
108 // Set color to black and wait a while.
109 RenderColor = CALIBRATE_BLACK;
111 State = State_WaitingForSettlePreCalibrationColorBlack;
112 OVR_DEBUG_LOG(("State_WaitingForButton -> State_WaitingForSettlePreCalibrationColorBlack."));
114 setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION);
115 }
116 }
118 void LatencyTest::handleMessage(const Message& msg, LatencyTestMessageType latencyTestMessage)
119 {
120 // For debugging.
121 /* if (msg.Type == Message_LatencyTestSamples)
122 {
123 MessageLatencyTestSamples* pSamples = (MessageLatencyTestSamples*) &msg;
125 if (pSamples->Samples.GetSize() > 0)
126 {
127 // Just show the first one for now.
128 Color c = pSamples->Samples[0];
129 OVR_DEBUG_LOG(("%d %d %d", c.R, c.G, c.B));
130 }
131 return;
132 }
133 */
135 if (latencyTestMessage == LatencyTest_Timer)
136 {
137 if (!Device)
138 {
139 reset();
140 return;
141 }
143 if (State == State_WaitingForSettlePreCalibrationColorBlack)
144 {
145 // Send calibrate message to device and wait a while.
146 Device->SetCalibrate(CALIBRATE_BLACK);
148 State = State_WaitingForSettlePostCalibrationColorBlack;
149 OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorBlack -> State_WaitingForSettlePostCalibrationColorBlack."));
151 setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION);
152 }
153 else if (State == State_WaitingForSettlePostCalibrationColorBlack)
154 {
155 // Change color to white and wait a while.
156 RenderColor = CALIBRATE_WHITE;
158 State = State_WaitingForSettlePreCalibrationColorWhite;
159 OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorBlack -> State_WaitingForSettlePreCalibrationColorWhite."));
161 setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION);
162 }
163 else if (State == State_WaitingForSettlePreCalibrationColorWhite)
164 {
165 // Send calibrate message to device and wait a while.
166 Device->SetCalibrate(CALIBRATE_WHITE);
168 State = State_WaitingForSettlePostCalibrationColorWhite;
169 OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorWhite -> State_WaitingForSettlePostCalibrationColorWhite."));
171 setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION);
172 }
173 else if (State == State_WaitingForSettlePostCalibrationColorWhite)
174 {
175 // Calibration is done. Switch to color 1 and wait for it to settle.
176 RenderColor = COLOR1;
178 State = State_WaitingForSettlePostMeasurement;
179 OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorWhite -> State_WaitingForSettlePostMeasurement."));
181 UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
182 setTimer(waitTime);
183 }
184 else if (State == State_WaitingForSettlePostMeasurement)
185 {
186 // Prepare for next measurement.
188 // Create a new result object.
189 MeasurementResult* pResult = new MeasurementResult();
190 Results.PushBack(pResult);
192 State = State_WaitingToTakeMeasurement;
193 OVR_DEBUG_LOG(("State_WaitingForSettlePostMeasurement -> State_WaitingToTakeMeasurement."));
194 }
195 else if (State == State_WaitingForTestStarted)
196 {
197 // We timed out waiting for 'TestStarted'. Abandon this measurement and setup for the next.
198 getActiveResult()->TimedOutWaitingForTestStarted = true;
200 State = State_WaitingForSettlePostMeasurement;
201 OVR_DEBUG_LOG(("** Timed out waiting for 'TestStarted'."));
202 OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForSettlePostMeasurement."));
204 UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
205 setTimer(waitTime);
206 }
207 else if (State == State_WaitingForColorDetected)
208 {
209 // We timed out waiting for 'ColorDetected'. Abandon this measurement and setup for the next.
210 getActiveResult()->TimedOutWaitingForColorDetected = true;
212 State = State_WaitingForSettlePostMeasurement;
213 OVR_DEBUG_LOG(("** Timed out waiting for 'ColorDetected'."));
214 OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement."));
216 UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
217 setTimer(waitTime);
218 }
219 }
220 else if (latencyTestMessage == LatencyTest_ProcessInputs)
221 {
222 if (State == State_WaitingToTakeMeasurement)
223 {
224 if (!Device)
225 {
226 reset();
227 return;
228 }
230 // Send 'StartTest' feature report with opposite target color.
231 if (RenderColor == COLOR1)
232 {
233 RenderColor = COLOR2;
234 }
235 else
236 {
237 RenderColor = COLOR1;
238 }
240 getActiveResult()->TargetColor = RenderColor;
242 // Record time so we can determine usb roundtrip time.
243 getActiveResult()->StartTestTicksMicroS = Timer::GetTicks();
245 Device->SetStartTest(RenderColor);
247 State = State_WaitingForTestStarted;
248 OVR_DEBUG_LOG(("State_WaitingToTakeMeasurement -> State_WaitingForTestStarted."));
250 setTimer(TIMEOUT_WAITING_FOR_TEST_STARTED);
252 LatencyTestDisplay ltd(2, 0x40090040);
253 Device->SetDisplay(ltd);
254 }
255 }
256 else if (msg.Type == Message_LatencyTestButton)
257 {
258 BeginTest();
259 }
260 else if (msg.Type == Message_LatencyTestStarted)
261 {
262 if (State == State_WaitingForTestStarted)
263 {
264 clearTimer();
266 // Record time so we can determine usb roundtrip time.
267 getActiveResult()->TestStartedTicksMicroS = Timer::GetTicks();
269 State = State_WaitingForColorDetected;
270 OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForColorDetected."));
272 setTimer(TIMEOUT_WAITING_FOR_COLOR_DETECTED);
273 }
274 }
275 else if (msg.Type == Message_LatencyTestColorDetected)
276 {
277 if (State == State_WaitingForColorDetected)
278 {
279 // Record time to detect color.
280 MessageLatencyTestColorDetected* pDetected = (MessageLatencyTestColorDetected*) &msg;
281 UInt16 elapsedTime = pDetected->Elapsed;
282 OVR_DEBUG_LOG(("Time to 'ColorDetected' = %d", elapsedTime));
284 getActiveResult()->DeviceMeasuredElapsedMilliS = elapsedTime;
286 if (areResultsComplete())
287 {
288 // We're done.
289 processResults();
290 reset();
291 }
292 else
293 {
294 // Run another measurement.
295 State = State_WaitingForSettlePostMeasurement;
296 OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement."));
298 UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
299 setTimer(waitTime);
301 LatencyTestDisplay ltd(2, 0x40400040);
302 Device->SetDisplay(ltd);
303 }
304 }
305 }
306 else if (msg.Type == Message_DeviceRemoved)
307 {
308 reset();
309 }
310 }
312 LatencyTest::MeasurementResult* LatencyTest::getActiveResult()
313 {
314 OVR_ASSERT(!Results.IsEmpty());
315 return Results.GetLast();
316 }
318 void LatencyTest::setTimer(UInt32 timeMilliS)
319 {
320 ActiveTimerMilliS = timeMilliS;
321 }
323 void LatencyTest::clearTimer()
324 {
325 ActiveTimerMilliS = 0;
326 }
328 void LatencyTest::reset()
329 {
330 clearMeasurementResults();
331 State = State_WaitingForButton;
333 HaveOldTime = false;
334 ActiveTimerMilliS = 0;
335 }
337 void LatencyTest::clearMeasurementResults()
338 {
339 while(!Results.IsEmpty())
340 {
341 MeasurementResult* pElem = Results.GetFirst();
342 pElem->RemoveNode();
343 delete pElem;
344 }
345 }
347 LatencyTest::LatencyTestHandler::~LatencyTestHandler()
348 {
349 RemoveHandlerFromDevices();
350 }
352 void LatencyTest::LatencyTestHandler::OnMessage(const Message& msg)
353 {
354 pLatencyTestUtil->handleMessage(msg);
355 }
357 void LatencyTest::ProcessInputs()
358 {
359 updateForTimeouts();
360 handleMessage(Message(), LatencyTest_ProcessInputs);
361 }
363 bool LatencyTest::DisplayScreenColor(Color& colorToDisplay)
364 {
365 updateForTimeouts();
367 if (State == State_WaitingForButton)
368 {
369 return false;
370 }
372 colorToDisplay = RenderColor;
373 return true;
374 }
376 const char* LatencyTest::GetResultsString()
377 {
378 if (!ResultsString.IsEmpty() && ReturnedResultString != ResultsString.ToCStr())
379 {
380 ReturnedResultString = ResultsString;
381 return ReturnedResultString.ToCStr();
382 }
384 return NULL;
385 }
387 bool LatencyTest::areResultsComplete()
388 {
389 UInt32 initialMeasurements = 0;
391 UInt32 measurements1to2 = 0;
392 UInt32 measurements2to1 = 0;
394 MeasurementResult* pCurr = Results.GetFirst();
395 while(true)
396 {
397 // Process.
398 if (!pCurr->TimedOutWaitingForTestStarted &&
399 !pCurr->TimedOutWaitingForColorDetected)
400 {
401 initialMeasurements++;
403 if (initialMeasurements > INITIAL_SAMPLES_TO_IGNORE)
404 {
405 if (pCurr->TargetColor == COLOR2)
406 {
407 measurements1to2++;
408 }
409 else
410 {
411 measurements2to1++;
412 }
413 }
414 }
416 if (Results.IsLast(pCurr))
417 {
418 break;
419 }
420 pCurr = Results.GetNext(pCurr);
421 }
423 if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES &&
424 measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES)
425 {
426 return true;
427 }
429 return false;
430 }
432 void LatencyTest::processResults()
433 {
435 UInt32 minTime1To2 = UINT_MAX;
436 UInt32 maxTime1To2 = 0;
437 float averageTime1To2 = 0.0f;
438 UInt32 minTime2To1 = UINT_MAX;
439 UInt32 maxTime2To1 = 0;
440 float averageTime2To1 = 0.0f;
442 float minUSBTripMilliS = BIG_FLOAT;
443 float maxUSBTripMilliS = SMALL_FLOAT;
444 float averageUSBTripMilliS = 0.0f;
445 UInt32 countUSBTripTime = 0;
447 UInt32 measurementsCount = 0;
448 UInt32 measurements1to2 = 0;
449 UInt32 measurements2to1 = 0;
451 MeasurementResult* pCurr = Results.GetFirst();
452 UInt32 count = 0;
453 while(true)
454 {
455 count++;
457 if (!pCurr->TimedOutWaitingForTestStarted &&
458 !pCurr->TimedOutWaitingForColorDetected)
459 {
460 measurementsCount++;
462 if (measurementsCount > INITIAL_SAMPLES_TO_IGNORE)
463 {
464 if (pCurr->TargetColor == COLOR2)
465 {
466 measurements1to2++;
468 if (measurements1to2 <= DEFAULT_NUMBER_OF_SAMPLES)
469 {
470 UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS;
472 minTime1To2 = Alg::Min(elapsed, minTime1To2);
473 maxTime1To2 = Alg::Max(elapsed, maxTime1To2);
475 averageTime1To2 += (float) elapsed;
476 }
477 }
478 else
479 {
480 measurements2to1++;
482 if (measurements2to1 <= DEFAULT_NUMBER_OF_SAMPLES)
483 {
484 UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS;
486 minTime2To1 = Alg::Min(elapsed, minTime2To1);
487 maxTime2To1 = Alg::Max(elapsed, maxTime2To1);
489 averageTime2To1 += (float) elapsed;
490 }
491 }
493 float usbRountripElapsedMilliS = 0.001f * (float) (pCurr->TestStartedTicksMicroS - pCurr->StartTestTicksMicroS);
494 minUSBTripMilliS = Alg::Min(usbRountripElapsedMilliS, minUSBTripMilliS);
495 maxUSBTripMilliS = Alg::Max(usbRountripElapsedMilliS, maxUSBTripMilliS);
496 averageUSBTripMilliS += usbRountripElapsedMilliS;
497 countUSBTripTime++;
498 }
499 }
501 if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES &&
502 measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES)
503 {
504 break;
505 }
507 if (Results.IsLast(pCurr))
508 {
509 break;
510 }
511 pCurr = Results.GetNext(pCurr);
512 }
514 averageTime1To2 /= (float) DEFAULT_NUMBER_OF_SAMPLES;
515 averageTime2To1 /= (float) DEFAULT_NUMBER_OF_SAMPLES;
517 averageUSBTripMilliS /= countUSBTripTime;
519 float finalResult = 0.5f * (averageTime1To2 + averageTime2To1);
520 finalResult += averageUSBTripMilliS;
522 ResultsString.Clear();
523 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]",
524 finalResult,
525 minTime1To2, averageTime1To2, maxTime1To2,
526 minTime2To1, averageTime2To1, maxTime2To1,
527 minUSBTripMilliS, averageUSBTripMilliS, maxUSBTripMilliS,
528 DEFAULT_NUMBER_OF_SAMPLES*2, count - measurementsCount);
530 // Display result on latency tester display.
531 LatencyTestDisplay ltd(1, (int)finalResult);
532 Device->SetDisplay(ltd);
533 }
535 void LatencyTest::updateForTimeouts()
536 {
537 if (!HaveOldTime)
538 {
539 HaveOldTime = true;
540 OldTime = Timer::GetTicksMs();
541 return;
542 }
544 UInt32 newTime = Timer::GetTicksMs();
545 UInt32 elapsedMilliS = newTime - OldTime;
546 if (newTime < OldTime)
547 {
548 elapsedMilliS = OldTime - newTime;
549 elapsedMilliS = UINT_MAX - elapsedMilliS;
550 }
551 OldTime = newTime;
553 elapsedMilliS = Alg::Min(elapsedMilliS, (UInt32) 100); // Clamp at 100mS in case we're not being called very often.
556 if (ActiveTimerMilliS == 0)
557 {
558 return;
559 }
561 if (elapsedMilliS >= ActiveTimerMilliS)
562 {
563 ActiveTimerMilliS = 0;
564 handleMessage(Message(), LatencyTest_Timer);
565 return;
566 }
568 ActiveTimerMilliS -= elapsedMilliS;
569 }
571 }} // namespace OVR::Util