OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2015 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 * |
| 7 */ |
| 8 |
| 9 #include "VisualInteractiveModule.h" |
| 10 |
| 11 #include "ProcStats.h" |
| 12 #include "SkApplication.h" |
| 13 #include "SkCanvas.h" |
| 14 #include "SkCommandLineFlags.h" |
| 15 #include "SkForceLinking.h" |
| 16 #include "SkGraphics.h" |
| 17 #include "SkGr.h" |
| 18 #include "SkImageDecoder.h" |
| 19 #include "SkOSFile.h" |
| 20 #include "SkStream.h" |
| 21 #include "Stats.h" |
| 22 #include "gl/GrGLInterface.h" |
| 23 |
| 24 __SK_FORCE_IMAGE_DECODER_LINKING; |
| 25 |
| 26 static const int kGpuFrameLag = 5; |
| 27 static const int kFrames = 5; |
| 28 static const double kLoopMs = 5; |
| 29 |
| 30 VisualInteractiveModule::VisualInteractiveModule(VisualBench* owner) |
| 31 : fCurrentMeasurement(0) |
| 32 , fCurrentFrame(0) |
| 33 , fLoops(1) |
| 34 , fState(kPreWarmLoops_State) |
| 35 , fBenchmark(nullptr) |
| 36 , fOwner(SkRef(owner)) { |
| 37 fBenchmarkStream.reset(new VisualBenchmarkStream); |
| 38 |
| 39 memset(fMeasurements, 0, sizeof(fMeasurements)); |
| 40 } |
| 41 |
| 42 inline void VisualInteractiveModule::renderFrame(SkCanvas* canvas) { |
| 43 fBenchmark->draw(fLoops, canvas); |
| 44 this->drawStats(canvas); |
| 45 canvas->flush(); |
| 46 fOwner->present(); |
| 47 } |
| 48 |
| 49 void VisualInteractiveModule::drawStats(SkCanvas* canvas) { |
| 50 static const float kPixelPerMS = 2.0f; |
| 51 static const int kDisplayWidth = 130; |
| 52 static const int kDisplayHeight = 100; |
| 53 static const int kDisplayPadding = 10; |
| 54 static const int kGraphPadding = 3; |
| 55 static const float kBaseMS = 1000.f / 60.f; // ms/frame to hit 60 fps |
| 56 |
| 57 SkISize canvasSize = canvas->getDeviceSize(); |
| 58 SkRect rect = SkRect::MakeXYWH(SkIntToScalar(canvasSize.fWidth-kDisplayWidth
-kDisplayPadding), |
| 59 SkIntToScalar(kDisplayPadding), |
| 60 SkIntToScalar(kDisplayWidth), SkIntToScalar(k
DisplayHeight)); |
| 61 SkPaint paint; |
| 62 canvas->clipRect(rect); |
| 63 paint.setColor(SK_ColorBLACK); |
| 64 canvas->drawRect(rect, paint); |
| 65 // draw the 16ms line |
| 66 paint.setColor(SK_ColorLTGRAY); |
| 67 canvas->drawLine(rect.fLeft, rect.fBottom - kBaseMS*kPixelPerMS, |
| 68 rect.fRight, rect.fBottom - kBaseMS*kPixelPerMS, paint); |
| 69 paint.setColor(SK_ColorRED); |
| 70 paint.setStyle(SkPaint::kStroke_Style); |
| 71 canvas->drawRect(rect, paint); |
| 72 |
| 73 int x = SkScalarTruncToInt(rect.fLeft) + kGraphPadding; |
| 74 const int xStep = 2; |
| 75 const int startY = SkScalarTruncToInt(rect.fBottom); |
| 76 int i = fCurrentMeasurement; |
| 77 do { |
| 78 int endY = startY - (int)(fMeasurements[i] * kPixelPerMS + 0.5); // rou
nd to nearest value |
| 79 canvas->drawLine(SkIntToScalar(x), SkIntToScalar(startY), |
| 80 SkIntToScalar(x), SkIntToScalar(endY), paint); |
| 81 i++; |
| 82 i &= (kMeasurementCount - 1); // fast mod |
| 83 x += xStep; |
| 84 } while (i != fCurrentMeasurement); |
| 85 |
| 86 } |
| 87 |
| 88 bool VisualInteractiveModule::advanceRecordIfNecessary(SkCanvas* canvas) { |
| 89 if (fBenchmark) { |
| 90 return true; |
| 91 } |
| 92 |
| 93 fBenchmark.reset(fBenchmarkStream->next()); |
| 94 if (!fBenchmark) { |
| 95 return false; |
| 96 } |
| 97 |
| 98 // clear both buffers |
| 99 fOwner->clear(canvas, SK_ColorWHITE, 2); |
| 100 |
| 101 fBenchmark->preDraw(); |
| 102 |
| 103 return true; |
| 104 } |
| 105 |
| 106 void VisualInteractiveModule::draw(SkCanvas* canvas) { |
| 107 if (!this->advanceRecordIfNecessary(canvas)) { |
| 108 SkDebugf("Exiting VisualBench successfully\n"); |
| 109 fOwner->closeWindow(); |
| 110 return; |
| 111 } |
| 112 this->renderFrame(canvas); |
| 113 switch (fState) { |
| 114 case kPreWarmLoopsPerCanvasPreDraw_State: { |
| 115 this->perCanvasPreDraw(canvas, kPreWarmLoops_State); |
| 116 break; |
| 117 } |
| 118 case kPreWarmLoops_State: { |
| 119 this->preWarm(kTuneLoops_State); |
| 120 break; |
| 121 } |
| 122 case kTuneLoops_State: { |
| 123 this->tuneLoops(canvas); |
| 124 break; |
| 125 } |
| 126 case kPreTiming_State: { |
| 127 fBenchmark->perCanvasPreDraw(canvas); |
| 128 fCurrentFrame = 0; |
| 129 fTimer.start(); |
| 130 fState = kTiming_State; |
| 131 // fall to next state |
| 132 } |
| 133 case kTiming_State: { |
| 134 this->timing(canvas); |
| 135 break; |
| 136 } |
| 137 case kAdvance_State: { |
| 138 this->postDraw(canvas); |
| 139 this->nextState(kPreWarmLoopsPerCanvasPreDraw_State); |
| 140 break; |
| 141 } |
| 142 } |
| 143 } |
| 144 |
| 145 inline void VisualInteractiveModule::nextState(State nextState) { |
| 146 fState = nextState; |
| 147 } |
| 148 |
| 149 void VisualInteractiveModule::perCanvasPreDraw(SkCanvas* canvas, State nextState
) { |
| 150 fBenchmark->perCanvasPreDraw(canvas); |
| 151 fCurrentFrame = 0; |
| 152 this->nextState(nextState); |
| 153 } |
| 154 |
| 155 void VisualInteractiveModule::preWarm(State nextState) { |
| 156 if (fCurrentFrame >= kGpuFrameLag) { |
| 157 // we currently time across all frames to make sure we capture all GPU w
ork |
| 158 this->nextState(nextState); |
| 159 fCurrentFrame = 0; |
| 160 fTimer.start(); |
| 161 } else { |
| 162 fCurrentFrame++; |
| 163 } |
| 164 } |
| 165 |
| 166 inline double VisualInteractiveModule::elapsed() { |
| 167 fTimer.end(); |
| 168 return fTimer.fWall; |
| 169 } |
| 170 |
| 171 void VisualInteractiveModule::resetTimingState() { |
| 172 fCurrentFrame = 0; |
| 173 fTimer = WallTimer(); |
| 174 fOwner->reset(); |
| 175 } |
| 176 |
| 177 void VisualInteractiveModule::scaleLoops(double elapsedMs) { |
| 178 // Scale back the number of loops |
| 179 fLoops = (int)ceil(fLoops * kLoopMs / elapsedMs); |
| 180 } |
| 181 |
| 182 inline void VisualInteractiveModule::tuneLoops(SkCanvas* canvas) { |
| 183 if (1 << 30 == fLoops) { |
| 184 // We're about to wrap. Something's wrong with the bench. |
| 185 SkDebugf("InnerLoops wrapped\n"); |
| 186 fLoops = 0; |
| 187 } else { |
| 188 double elapsedMs = this->elapsed(); |
| 189 if (elapsedMs > kLoopMs) { |
| 190 this->scaleLoops(elapsedMs); |
| 191 fBenchmark->perCanvasPostDraw(canvas); |
| 192 this->nextState(kPreTiming_State); |
| 193 } else { |
| 194 fLoops *= 2; |
| 195 this->nextState(kPreWarmLoops_State); |
| 196 } |
| 197 this->resetTimingState(); |
| 198 } |
| 199 } |
| 200 |
| 201 void VisualInteractiveModule::recordMeasurement() { |
| 202 double measurement = this->elapsed() / (kFrames * fLoops); |
| 203 fMeasurements[fCurrentMeasurement++] = measurement; |
| 204 fCurrentMeasurement &= (kMeasurementCount-1); // fast mod |
| 205 SkASSERT(fCurrentMeasurement < kMeasurementCount); |
| 206 } |
| 207 |
| 208 void VisualInteractiveModule::postDraw(SkCanvas* canvas) { |
| 209 fBenchmark->perCanvasPostDraw(canvas); |
| 210 fBenchmark.reset(nullptr); |
| 211 fLoops = 1; |
| 212 } |
| 213 |
| 214 inline void VisualInteractiveModule::timing(SkCanvas* canvas) { |
| 215 if (fCurrentFrame >= kFrames) { |
| 216 this->recordMeasurement(); |
| 217 fTimer.start(); |
| 218 fCurrentFrame = 0; |
| 219 } else { |
| 220 fCurrentFrame++; |
| 221 } |
| 222 } |
| 223 |
| 224 bool VisualInteractiveModule::onHandleChar(SkUnichar c) { |
| 225 if (' ' == c) { |
| 226 this->nextState(kAdvance_State); |
| 227 } |
| 228 |
| 229 return true; |
| 230 } |
OLD | NEW |