Chromium Code Reviews| Index: tools/VisualBench/VisualInteractiveModule.cpp |
| diff --git a/tools/VisualBench/VisualInteractiveModule.cpp b/tools/VisualBench/VisualInteractiveModule.cpp |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..553c9686284b73c7e68afd20624b02f093bb8a03 |
| --- /dev/null |
| +++ b/tools/VisualBench/VisualInteractiveModule.cpp |
| @@ -0,0 +1,231 @@ |
| +/* |
| + * Copyright 2015 Google Inc. |
| + * |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the LICENSE file. |
| + * |
| + */ |
| + |
| +#include "VisualInteractiveModule.h" |
| + |
| +#include "ProcStats.h" |
| +#include "SkApplication.h" |
| +#include "SkCanvas.h" |
| +#include "SkCommandLineFlags.h" |
| +#include "SkForceLinking.h" |
| +#include "SkGraphics.h" |
| +#include "SkGr.h" |
| +#include "SkImageDecoder.h" |
| +#include "SkOSFile.h" |
| +#include "SkStream.h" |
| +#include "Stats.h" |
| +#include "gl/GrGLInterface.h" |
| + |
| +__SK_FORCE_IMAGE_DECODER_LINKING; |
| + |
| +static const int kGpuFrameLag = 5; |
| +static const int kFrames = 5; |
| +static const double kLoopMs = 5; |
| + |
| +VisualInteractiveModule::VisualInteractiveModule(VisualBench* owner) |
| + : fCurrentFrame(0) |
| + , fLoops(1) |
| + , fState(kPreWarmLoops_State) |
| + , fCurrentMeasurement(0) |
| + , fBenchmark(nullptr) |
| + , fOwner(SkRef(owner)) { |
| + fBenchmarkStream.reset(new VisualBenchmarkStream); |
| + |
| + memset(fMeasurements, 0, sizeof(fMeasurements)); |
| +} |
| + |
| +inline void VisualInteractiveModule::renderFrame(SkCanvas* canvas) { |
| + fBenchmark->draw(fLoops, canvas); |
| + this->drawStats(canvas); |
| + canvas->flush(); |
| + fOwner->present(); |
| +} |
| + |
| +void VisualInteractiveModule::drawStats(SkCanvas* canvas) { |
| + const float kPixelPerMs = 2.0f; |
| + const int kDisplayWidth = 130; |
| + const int kDisplayHeight = 100; |
| + const int kPadding = 10; |
| + |
| + SkISize canvasSize = canvas->getDeviceSize(); |
| + SkRect rect = SkRect::MakeXYWH(SkIntToScalar(canvasSize.fWidth - kDisplayWidth - kPadding), |
| + SkIntToScalar(kPadding), |
| + SkIntToScalar(kDisplayWidth), SkIntToScalar(kDisplayHeight)); |
| + SkPaint paint; |
| + canvas->clipRect(rect); |
| + paint.setColor(SK_ColorBLACK); |
| + canvas->drawRect(rect, paint); |
| + // draw the 16ms line |
| + paint.setColor(SK_ColorLTGRAY); |
| + canvas->drawLine(rect.fLeft, rect.fBottom - 16.f*kPixelPerMs, |
|
joshualitt
2015/09/14 14:07:45
I wonder if we want to make this 1000/60 'exactly.
jvanverth1
2015/09/14 16:21:38
Done.
|
| + rect.fRight, rect.fBottom - 16.f*kPixelPerMs, paint); |
| + paint.setColor(SK_ColorRED); |
| + paint.setStyle(SkPaint::kStroke_Style); |
| + canvas->drawRect(rect, paint); |
| + |
| + int x = SkScalarTruncToInt(rect.fLeft) + 3; |
|
joshualitt
2015/09/14 14:07:45
Is this some kind of padding?
jvanverth1
2015/09/14 16:21:38
Done.
|
| + const int xStep = 2; |
| + const int startY = SkScalarTruncToInt(rect.fBottom); |
| + int i = fCurrentMeasurement; |
| + do { |
| + int endY = startY - (int)(fMeasurements[i] * kPixelPerMs + 0.5); |
|
joshualitt
2015/09/14 14:07:45
0.5?
jvanverth1
2015/09/14 16:21:38
Added comment
|
| + canvas->drawLine(SkIntToScalar(x), SkIntToScalar(startY), |
| + SkIntToScalar(x), SkIntToScalar(endY), paint); |
| + i++; |
| + i &= (kMeasurementCount - 1); // fast mod |
| + x += xStep; |
| + } while (i != fCurrentMeasurement); |
| + |
| +} |
| + |
| +bool VisualInteractiveModule::advanceRecordIfNecessary(SkCanvas* canvas) { |
| + if (fBenchmark) { |
| + return true; |
| + } |
| + |
| + fBenchmark.reset(fBenchmarkStream->next()); |
| + if (!fBenchmark) { |
| + return false; |
| + } |
| + |
| + // clear both buffers |
| + canvas->clear(0xffffffff); |
| + canvas->flush(); |
| + fOwner->present(); |
| + canvas->clear(0xffffffff); |
|
joshualitt
2015/09/14 14:07:45
Hmm, might be nice to have a static function on Vi
jvanverth1
2015/09/14 16:21:38
How do I know what the buffer setup is?
|
| + |
| + fBenchmark->preDraw(); |
| + |
| + return true; |
| +} |
| + |
| +void VisualInteractiveModule::draw(SkCanvas* canvas) { |
| + if (!this->advanceRecordIfNecessary(canvas)) { |
| + SkDebugf("Exiting VisualBench successfully\n"); |
| + fOwner->closeWindow(); |
| + 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); |
| + break; |
| + } |
| + case kPreTiming_State: { |
| + fBenchmark->perCanvasPreDraw(canvas); |
| + fCurrentFrame = 0; |
| + fTimer.start(); |
| + fState = kTiming_State; |
| + // fall to next state |
| + } |
| + case kTiming_State: { |
| + this->timing(canvas); |
| + break; |
| + } |
| + case kAdvance_State: { |
| + this->postDraw(canvas); |
| + this->nextState(kPreWarmLoopsPerCanvasPreDraw_State); |
| + break; |
| + } |
| + } |
| +} |
| + |
| +inline void VisualInteractiveModule::nextState(State nextState) { |
| + fState = nextState; |
| +} |
| + |
| +void VisualInteractiveModule::perCanvasPreDraw(SkCanvas* canvas, State nextState) { |
| + fBenchmark->perCanvasPreDraw(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) { |
|
joshualitt
2015/09/14 14:07:45
it'd be nice to figure out how to share this code,
jvanverth1
2015/09/14 16:21:38
Acknowledged.
|
| + 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->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); |
| + } |
| + |
| + return true; |
| +} |