| Index: tools/VisualBench/VisualInteractiveModule.cpp
 | 
| diff --git a/tools/VisualBench/VisualInteractiveModule.cpp b/tools/VisualBench/VisualInteractiveModule.cpp
 | 
| index af922a92bf10352cc422da9abbea92e15904847e..f41bcaebab2e03cdad83df75516a0684e81f7ebc 100755
 | 
| --- a/tools/VisualBench/VisualInteractiveModule.cpp
 | 
| +++ b/tools/VisualBench/VisualInteractiveModule.cpp
 | 
| @@ -23,16 +23,10 @@
 | 
|  
 | 
|  __SK_FORCE_IMAGE_DECODER_LINKING;
 | 
|  
 | 
| -static const int kGpuFrameLag = 5;
 | 
| -static const int kFrames = 5;
 | 
| -static const double kLoopMs = 5;
 | 
| -
 | 
|  VisualInteractiveModule::VisualInteractiveModule(VisualBench* owner)
 | 
|      : fCurrentMeasurement(0)
 | 
| -    , fCurrentFrame(0)
 | 
| -    , fLoops(1)
 | 
| -    , fState(kPreWarmLoops_State)
 | 
|      , fBenchmark(nullptr)
 | 
| +    , fAdvance(false)
 | 
|      , fOwner(SkRef(owner)) {
 | 
|      fBenchmarkStream.reset(new VisualBenchmarkStream);
 | 
|  
 | 
| @@ -40,7 +34,7 @@ VisualInteractiveModule::VisualInteractiveModule(VisualBench* owner)
 | 
|  }
 | 
|  
 | 
|  inline void VisualInteractiveModule::renderFrame(SkCanvas* canvas) {
 | 
| -    fBenchmark->draw(fLoops, canvas);
 | 
| +    fBenchmark->draw(fTSM.loops(), canvas);
 | 
|      this->drawStats(canvas);
 | 
|      canvas->flush();
 | 
|      fOwner->present();
 | 
| @@ -102,7 +96,8 @@ bool VisualInteractiveModule::advanceRecordIfNecessary(SkCanvas* canvas) {
 | 
|  
 | 
|      return true;
 | 
|  }
 | 
| -
 | 
| +#include "GrGpu.h"
 | 
| +#include "GrResourceCache.h"
 | 
|  void VisualInteractiveModule::draw(SkCanvas* canvas) {
 | 
|      if (!this->advanceRecordIfNecessary(canvas)) {
 | 
|          SkDebugf("Exiting VisualBench successfully\n");
 | 
| @@ -110,123 +105,34 @@ void VisualInteractiveModule::draw(SkCanvas* canvas) {
 | 
|          return;
 | 
|      }
 | 
|      this->renderFrame(canvas);
 | 
| -    switch (fState) {
 | 
| -        case kPreWarmLoopsPerCanvasPreDraw_State: {
 | 
| -            this->perCanvasPreDraw(canvas, kPreWarmLoops_State);
 | 
| -            break;
 | 
| -        }
 | 
| -        case kPreWarmLoops_State: {
 | 
| -            this->preWarm(kTuneLoops_State);
 | 
| -            break;
 | 
| -        }
 | 
| -        case kTuneLoops_State: {
 | 
| -            this->tuneLoops(canvas);
 | 
| +    TimingStateMachine::ParentEvents event = fTSM.nextFrame(canvas, fBenchmark);
 | 
| +    switch (event) {
 | 
| +        case TimingStateMachine::kReset_ParentEvents:
 | 
| +            fOwner->reset();
 | 
|              break;
 | 
| -        }
 | 
| -        case kPreTiming_State: {
 | 
| -            fBenchmark->perCanvasPreDraw(canvas);
 | 
| -            fBenchmark->preDraw(canvas);
 | 
| -            fCurrentFrame = 0;
 | 
| -            fTimer.start();
 | 
| -            fState = kTiming_State;
 | 
| -            // fall to next state
 | 
| -        }
 | 
| -        case kTiming_State: {
 | 
| -            this->timing(canvas);
 | 
| +        case TimingStateMachine::kTiming_ParentEvents:
 | 
|              break;
 | 
| -        }
 | 
| -        case kAdvance_State: {
 | 
| -            this->postDraw(canvas);
 | 
| -            this->nextState(kPreWarmLoopsPerCanvasPreDraw_State);
 | 
| +        case TimingStateMachine::kTimingFinished_ParentEvents:
 | 
| +            // Record measurements
 | 
| +            fMeasurements[fCurrentMeasurement++] = fTSM.lastMeasurement();
 | 
| +            fCurrentMeasurement &= (kMeasurementCount-1);  // fast mod
 | 
| +            SkASSERT(fCurrentMeasurement < kMeasurementCount);
 | 
| +            this->drawStats(canvas);
 | 
| +            if (fAdvance) {
 | 
| +                fAdvance = false;
 | 
| +                fTSM.nextBenchmark(canvas, fBenchmark);
 | 
| +                fBenchmark.reset(nullptr);
 | 
| +                fOwner->reset();
 | 
| +            } else {
 | 
| +                fTSM.nextSample();
 | 
| +            }
 | 
|              break;
 | 
| -        }
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -inline void VisualInteractiveModule::nextState(State nextState) {
 | 
| -    fState = nextState;
 | 
| -}
 | 
| -
 | 
| -void VisualInteractiveModule::perCanvasPreDraw(SkCanvas* canvas, State nextState) {
 | 
| -    fBenchmark->perCanvasPreDraw(canvas);
 | 
| -    fBenchmark->preDraw(canvas);
 | 
| -    fCurrentFrame = 0;
 | 
| -    this->nextState(nextState);
 | 
| -}
 | 
| -
 | 
| -void VisualInteractiveModule::preWarm(State nextState) {
 | 
| -    if (fCurrentFrame >= kGpuFrameLag) {
 | 
| -        // we currently time across all frames to make sure we capture all GPU work
 | 
| -        this->nextState(nextState);
 | 
| -        fCurrentFrame = 0;
 | 
| -        fTimer.start();
 | 
| -    } else {
 | 
| -        fCurrentFrame++;
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -inline double VisualInteractiveModule::elapsed() {
 | 
| -    fTimer.end();
 | 
| -    return fTimer.fWall;
 | 
| -}
 | 
| -
 | 
| -void VisualInteractiveModule::resetTimingState() {
 | 
| -    fCurrentFrame = 0;
 | 
| -    fTimer = WallTimer();
 | 
| -    fOwner->reset();
 | 
| -}
 | 
| -
 | 
| -void VisualInteractiveModule::scaleLoops(double elapsedMs) {
 | 
| -    // Scale back the number of loops
 | 
| -    fLoops = (int)ceil(fLoops * kLoopMs / elapsedMs);
 | 
| -}
 | 
| -
 | 
| -inline void VisualInteractiveModule::tuneLoops(SkCanvas* canvas) {
 | 
| -    if (1 << 30 == fLoops) {
 | 
| -        // We're about to wrap.  Something's wrong with the bench.
 | 
| -        SkDebugf("InnerLoops wrapped\n");
 | 
| -        fLoops = 0;
 | 
| -    } else {
 | 
| -        double elapsedMs = this->elapsed();
 | 
| -        if (elapsedMs > kLoopMs) {
 | 
| -            this->scaleLoops(elapsedMs);
 | 
| -            fBenchmark->perCanvasPostDraw(canvas);
 | 
| -            this->nextState(kPreTiming_State);
 | 
| -        } else {
 | 
| -            fLoops *= 2;
 | 
| -            this->nextState(kPreWarmLoops_State);
 | 
| -        }
 | 
| -        this->resetTimingState();
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -void VisualInteractiveModule::recordMeasurement() {
 | 
| -    double measurement = this->elapsed() / (kFrames * fLoops);
 | 
| -    fMeasurements[fCurrentMeasurement++] = measurement;
 | 
| -    fCurrentMeasurement &= (kMeasurementCount-1);  // fast mod
 | 
| -    SkASSERT(fCurrentMeasurement < kMeasurementCount);
 | 
| -}
 | 
| -
 | 
| -void VisualInteractiveModule::postDraw(SkCanvas* canvas) {
 | 
| -    fBenchmark->postDraw(canvas);
 | 
| -    fBenchmark->perCanvasPostDraw(canvas);
 | 
| -    fBenchmark.reset(nullptr);
 | 
| -    fLoops = 1;
 | 
| -}
 | 
| -
 | 
| -inline void VisualInteractiveModule::timing(SkCanvas* canvas) {
 | 
| -    if (fCurrentFrame >= kFrames) {
 | 
| -        this->recordMeasurement();
 | 
| -        fTimer.start();
 | 
| -        fCurrentFrame = 0;
 | 
| -    } else {
 | 
| -        fCurrentFrame++;
 | 
|      }
 | 
|  }
 | 
|  
 | 
|  bool VisualInteractiveModule::onHandleChar(SkUnichar c) {
 | 
|      if (' ' == c) {
 | 
| -        this->nextState(kAdvance_State);
 | 
| +        fAdvance = true;
 | 
|      }
 | 
|  
 | 
|      return true;
 | 
| 
 |