OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkDebuggerGUI.h" | 8 #include "SkDebuggerGUI.h" |
9 #include "SkForceLinking.h" | 9 #include "SkForceLinking.h" |
10 #include "SkGraphics.h" | 10 #include "SkGraphics.h" |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 fListWidget.update(); | 148 fListWidget.update(); |
149 } | 149 } |
150 | 150 |
151 void SkDebuggerGUI::showDeletes() { | 151 void SkDebuggerGUI::showDeletes() { |
152 fDeletesActivated = !fDeletesActivated; | 152 fDeletesActivated = !fDeletesActivated; |
153 for (int row = 0; row < fListWidget.count(); row++) { | 153 for (int row = 0; row < fListWidget.count(); row++) { |
154 QListWidgetItem *item = fListWidget.item(row); | 154 QListWidgetItem *item = fListWidget.item(row); |
155 item->setHidden(fDebugger.isCommandVisible(row) && fDeletesActivated); | 155 item->setHidden(fDebugger.isCommandVisible(row) && fDeletesActivated); |
156 } | 156 } |
157 } | 157 } |
158 | |
159 // The timed picture playback just steps through every operation timing | |
160 // each one individually. Note that each picture should be replayed multiple | |
161 // times (via calls to 'draw') before each command's time is accessed via 'time'
. | |
162 class SkTimedPicturePlayback : public SkPicturePlayback { | |
163 public: | |
164 | |
165 SkTimedPicturePlayback(const SkPicture* picture, const SkTDArray<bool>& dele
tedCommands) | |
166 : INHERITED(picture) | |
167 , fSkipCommands(deletedCommands) | |
168 , fTot(0.0) | |
169 , fCurCommand(0) { | |
170 fTimes.setCount(deletedCommands.count()); | |
171 fTypeTimes.setCount(LAST_DRAWTYPE_ENUM+1); | |
172 this->resetTimes(); | |
173 } | |
174 | |
175 virtual void draw(SkCanvas* canvas, SkDrawPictureCallback* callback) SK_OVER
RIDE { | |
176 AutoResetOpID aroi(this); | |
177 SkASSERT(0 == fCurOffset); | |
178 | |
179 SkReader32 reader(fPictureData->opData()->bytes(), fPictureData->opData(
)->size()); | |
180 | |
181 // Record this, so we can concat w/ it if we encounter a setMatrix() | |
182 SkMatrix initialMatrix = canvas->getTotalMatrix(); | |
183 | |
184 SkAutoCanvasRestore acr(canvas, false); | |
185 | |
186 int opIndex = -1; | |
187 | |
188 while (!reader.eof()) { | |
189 if (callback && callback->abortDrawing()) { | |
190 return; | |
191 } | |
192 | |
193 fCurOffset = reader.offset(); | |
194 uint32_t size; | |
195 DrawType op = ReadOpAndSize(&reader, &size); | |
196 if (NOOP == op) { | |
197 // NOOPs are to be ignored - do not propagate them any further | |
198 reader.setOffset(fCurOffset + size); | |
199 continue; | |
200 } | |
201 | |
202 opIndex++; | |
203 | |
204 if (this->preDraw(opIndex, op)) { | |
205 // This operation is disabled in the debugger's GUI | |
206 reader.setOffset(fCurOffset + size); | |
207 continue; | |
208 } | |
209 | |
210 this->handleOp(&reader, op, size, canvas, initialMatrix); | |
211 | |
212 this->postDraw(opIndex); | |
213 } | |
214 } | |
215 | |
216 void resetTimes() { | |
217 for (int i = 0; i < fTimes.count(); ++i) { | |
218 fTimes[i] = 0.0; | |
219 } | |
220 for (int i = 0; i < fTypeTimes.count(); ++i) { | |
221 fTypeTimes[i] = 0.0f; | |
222 } | |
223 fTot = 0.0; | |
224 } | |
225 | |
226 int count() const { return fTimes.count(); } | |
227 | |
228 // Return the fraction of the total time consumed by the index-th operation | |
229 double time(int index) const { return fTimes[index] / fTot; } | |
230 | |
231 const SkTDArray<double>* typeTimes() const { return &fTypeTimes; } | |
232 | |
233 double totTime() const { return fTot; } | |
234 | |
235 protected: | |
236 SysTimer fTimer; | |
237 SkTDArray<bool> fSkipCommands; // has the command been deleted in the GUI? | |
238 SkTDArray<double> fTimes; // sum of time consumed for each command | |
239 SkTDArray<double> fTypeTimes; // sum of time consumed for each type of comma
nd (e.g., drawPath) | |
240 double fTot; // total of all times in 'fTimes' | |
241 | |
242 int fCurType; | |
243 int fCurCommand; // the current command being executed/timed | |
244 | |
245 bool preDraw(int opIndex, int type) { | |
246 fCurCommand = opIndex; | |
247 | |
248 if (fSkipCommands[fCurCommand]) { | |
249 return true; | |
250 } | |
251 | |
252 fCurType = type; | |
253 // The SkDebugCanvas doesn't recognize these types. This class needs to | |
254 // convert or else we'll wind up with a mismatch between the type counts | |
255 // the debugger displays and the profile times. | |
256 if (DRAW_POS_TEXT_TOP_BOTTOM == type) { | |
257 fCurType = DRAW_POS_TEXT; | |
258 } else if (DRAW_POS_TEXT_H_TOP_BOTTOM == type) { | |
259 fCurType = DRAW_POS_TEXT_H; | |
260 } | |
261 | |
262 #if defined(SK_BUILD_FOR_WIN32) | |
263 // CPU timer doesn't work well on Windows | |
264 fTimer.startWall(); | |
265 #else | |
266 fTimer.startCpu(); | |
267 #endif | |
268 | |
269 return false; | |
270 } | |
271 | |
272 void postDraw(int opIndex) { | |
273 #if defined(SK_BUILD_FOR_WIN32) | |
274 // CPU timer doesn't work well on Windows | |
275 double time = fTimer.endWall(); | |
276 #else | |
277 double time = fTimer.endCpu(); | |
278 #endif | |
279 | |
280 SkASSERT(opIndex == fCurCommand); | |
281 SkASSERT(fCurType <= LAST_DRAWTYPE_ENUM); | |
282 | |
283 fTimes[fCurCommand] += time; | |
284 fTypeTimes[fCurType] += time; | |
285 fTot += time; | |
286 } | |
287 | |
288 private: | |
289 typedef SkPicturePlayback INHERITED; | |
290 }; | |
291 | |
292 #if 0 | |
293 // Wrap SkPicture to allow installation of an SkTimedPicturePlayback object | |
294 class SkTimedPicture : public SkPicture { | |
295 public: | |
296 static SkTimedPicture* CreateTimedPicture(SkStream* stream, | |
297 SkPicture::InstallPixelRefProc pro
c, | |
298 const SkTDArray<bool>& deletedComm
ands) { | |
299 SkPictInfo info; | |
300 if (!InternalOnly_StreamIsSKP(stream, &info)) { | |
301 return NULL; | |
302 } | |
303 | |
304 // Check to see if there is a playback to recreate. | |
305 if (stream->readBool()) { | |
306 SkTimedPicturePlayback* playback = SkTimedPicturePlayback::CreateFro
mStream( | |
307 stream, | |
308 info, proc, | |
309 deletedCommands)
; | |
310 if (NULL == playback) { | |
311 return NULL; | |
312 } | |
313 | |
314 return SkNEW_ARGS(SkTimedPicture, (playback, info.fWidth, info.fHeig
ht)); | |
315 } | |
316 | |
317 return NULL; | |
318 } | |
319 | |
320 void resetTimes() { ((SkTimedPicturePlayback*) fData.get())->resetTimes(); } | |
321 | |
322 int count() const { return ((SkTimedPicturePlayback*) fData.get())->count();
} | |
323 | |
324 // return the fraction of the total time this command consumed | |
325 double time(int index) const { return ((SkTimedPicturePlayback*) fData.get()
)->time(index); } | |
326 | |
327 const SkTDArray<double>* typeTimes() const { return ((SkTimedPicturePlayback
*) fData.get())->typeTimes(); } | |
328 | |
329 double totTime() const { return ((SkTimedPicturePlayback*) fData.get())->tot
Time(); } | |
330 | |
331 private: | |
332 // disallow default ctor b.c. we don't have a good way to setup the fData pt
r | |
333 SkTimedPicture(); | |
334 // Private ctor only used by CreateTimedPicture, which has created the playb
ack. | |
335 SkTimedPicture(SkTimedPicturePlayback* playback, int width, int height) | |
336 : INHERITED(playback, width, height) {} | |
337 // disallow the copy ctor - enabling would require copying code from SkPictu
re | |
338 SkTimedPicture(const SkTimedPicture& src); | |
339 | |
340 typedef SkPicture INHERITED; | |
341 }; | |
342 #endif | |
343 | |
344 // This is a simplification of PictureBenchmark's run with the addition of | 158 // This is a simplification of PictureBenchmark's run with the addition of |
345 // clearing of the times after the first pass (in resetTimes) | 159 // clearing of the times after the first pass (in resetTimes) |
346 void SkDebuggerGUI::run(const SkPicture* pict, | 160 void SkDebuggerGUI::run(const SkPicture* pict, |
347 sk_tools::PictureRenderer* renderer, | 161 sk_tools::PictureRenderer* renderer, |
348 int repeats) { | 162 int repeats) { |
349 SkASSERT(pict); | 163 SkASSERT(pict); |
350 if (NULL == pict) { | 164 if (NULL == pict) { |
351 return; | 165 return; |
352 } | 166 } |
353 | 167 |
354 SkASSERT(renderer != NULL); | 168 SkASSERT(renderer != NULL); |
355 if (NULL == renderer) { | 169 if (NULL == renderer) { |
356 return; | 170 return; |
357 } | 171 } |
358 | 172 |
359 renderer->init(pict, NULL, NULL, NULL, false, false); | 173 renderer->init(pict, NULL, NULL, NULL, false, false); |
360 | 174 |
361 renderer->setup(); | 175 renderer->setup(); |
362 renderer->render(); | 176 renderer->render(); |
363 renderer->resetState(true); // flush, swapBuffers and Finish | 177 renderer->resetState(true); // flush, swapBuffers and Finish |
364 | 178 |
365 #if 0 | |
366 // We throw this away the first batch of times to remove first time effects
(such as paging in this program) | |
367 pict->resetTimes(); | |
368 #endif | |
369 | |
370 for (int i = 0; i < repeats; ++i) { | 179 for (int i = 0; i < repeats; ++i) { |
371 renderer->setup(); | 180 renderer->setup(); |
372 renderer->render(); | 181 renderer->render(); |
373 renderer->resetState(false); // flush & swapBuffers, but don't Finish | 182 renderer->resetState(false); // flush & swapBuffers, but don't Finish |
374 } | 183 } |
375 renderer->resetState(true); // flush, swapBuffers and Finish | 184 renderer->resetState(true); // flush, swapBuffers and Finish |
376 | 185 |
377 renderer->end(); | 186 renderer->end(); |
378 } | 187 } |
379 | 188 |
(...skipping 12 matching lines...) Expand all Loading... |
392 inputStream.setPath(fFileName.c_str()); | 201 inputStream.setPath(fFileName.c_str()); |
393 if (!inputStream.isValid()) { | 202 if (!inputStream.isValid()) { |
394 return; | 203 return; |
395 } | 204 } |
396 | 205 |
397 SkAutoTUnref<SkPicture> picture(SkPicture::CreateFromStream(&inputStream, | 206 SkAutoTUnref<SkPicture> picture(SkPicture::CreateFromStream(&inputStream, |
398 &SkImageDecoder::DecodeMemory)); // , fS
kipCommands)); | 207 &SkImageDecoder::DecodeMemory)); // , fS
kipCommands)); |
399 if (NULL == picture.get()) { | 208 if (NULL == picture.get()) { |
400 return; | 209 return; |
401 } | 210 } |
402 | |
403 | |
404 #if 0 | |
405 | |
406 // For now this #if allows switching between tiled and simple rendering | |
407 // modes. Eventually this will be accomplished via the GUI | |
408 #if 0 | |
409 // With the current batch of SysTimers, profiling in tiled mode | |
410 // gets swamped by the timing overhead: | |
411 // | |
412 // tile mode simple mode | |
413 // debugger 64.2ms 12.8ms | |
414 // bench_pictures 16.9ms 12.4ms | |
415 // | |
416 // This is b.c. in tiled mode each command is called many more times | |
417 // but typically does less work on each invocation (due to clipping) | |
418 sk_tools::TiledPictureRenderer* renderer = NULL; | |
419 | |
420 renderer = SkNEW(sk_tools::TiledPictureRenderer); | |
421 renderer->setTileWidth(256); | |
422 renderer->setTileHeight(256); | |
423 #else | |
424 sk_tools::SimplePictureRenderer* renderer = NULL; | |
425 | |
426 renderer = SkNEW(sk_tools::SimplePictureRenderer); | |
427 | |
428 #if SK_SUPPORT_GPU | |
429 if (fSettingsWidget.isGLActive()) { | |
430 renderer->setDeviceType(sk_tools::PictureRenderer::kGPU_DeviceType); | |
431 renderer->setSampleCount(fSettingsWidget.getGLSampleCount()); | |
432 } | |
433 #endif | |
434 | |
435 #endif | |
436 | |
437 static const int kNumRepeats = 10; | |
438 | |
439 run(picture.get(), renderer, kNumRepeats); | |
440 | |
441 SkASSERT(picture->count() == fListWidget.count()); | |
442 | |
443 // extract the individual command times from the SkTimedPlaybackPicture | |
444 for (int i = 0; i < picture->count(); ++i) { | |
445 double temp = picture->time(i); | |
446 | |
447 QListWidgetItem* item = fListWidget.item(i); | |
448 | |
449 item->setData(Qt::UserRole + 4, 100.0*temp); | |
450 } | |
451 | |
452 setupOverviewText(picture->typeTimes(), picture->totTime(), kNumRepeats); | |
453 setupClipStackText(); | |
454 | |
455 #endif | |
456 } | 211 } |
457 | 212 |
458 void SkDebuggerGUI::actionCancel() { | 213 void SkDebuggerGUI::actionCancel() { |
459 for (int row = 0; row < fListWidget.count(); row++) { | 214 for (int row = 0; row < fListWidget.count(); row++) { |
460 fListWidget.item(row)->setHidden(false); | 215 fListWidget.item(row)->setHidden(false); |
461 } | 216 } |
462 } | 217 } |
463 | 218 |
464 void SkDebuggerGUI::actionClearBreakpoints() { | 219 void SkDebuggerGUI::actionClearBreakpoints() { |
465 for (int row = 0; row < fListWidget.count(); row++) { | 220 for (int row = 0; row < fListWidget.count(); row++) { |
(...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1107 } | 862 } |
1108 | 863 |
1109 // NOTE(chudy): Makes first item unselectable. | 864 // NOTE(chudy): Makes first item unselectable. |
1110 QStandardItemModel* model = qobject_cast<QStandardItemModel*>( | 865 QStandardItemModel* model = qobject_cast<QStandardItemModel*>( |
1111 fFilter.model()); | 866 fFilter.model()); |
1112 QModelIndex firstIndex = model->index(0, fFilter.modelColumn(), | 867 QModelIndex firstIndex = model->index(0, fFilter.modelColumn(), |
1113 fFilter.rootModelIndex()); | 868 fFilter.rootModelIndex()); |
1114 QStandardItem* firstItem = model->itemFromIndex(firstIndex); | 869 QStandardItem* firstItem = model->itemFromIndex(firstIndex); |
1115 firstItem->setSelectable(false); | 870 firstItem->setSelectable(false); |
1116 } | 871 } |
OLD | NEW |