Chromium Code Reviews| 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 "SkGraphics.h" | 9 #include "SkGraphics.h" |
| 10 #include "SkImageDecoder.h" | 10 #include "SkImageDecoder.h" |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 137 && fDeletesActivated); | 137 && fDeletesActivated); |
| 138 } | 138 } |
| 139 } | 139 } |
| 140 | 140 |
| 141 // The timed picture playback uses the SkPicturePlayback's profiling stubs | 141 // The timed picture playback uses the SkPicturePlayback's profiling stubs |
| 142 // to time individual commands. The offsets are needed to map SkPicture | 142 // to time individual commands. The offsets are needed to map SkPicture |
| 143 // offsets to individual commands. | 143 // offsets to individual commands. |
| 144 class SkTimedPicturePlayback : public SkPicturePlayback { | 144 class SkTimedPicturePlayback : public SkPicturePlayback { |
| 145 public: | 145 public: |
| 146 SkTimedPicturePlayback(SkStream* stream, const SkPictInfo& info, | 146 SkTimedPicturePlayback(SkStream* stream, const SkPictInfo& info, |
| 147 SkPicture::InstallPixelRefProc proc, const SkTDArray< size_t>& offsets, | 147 SkPicture::InstallPixelRefProc proc, |
| 148 const SkTDArray<bool>& deletedCommands) | 148 const SkTDArray<bool>& deletedCommands) |
| 149 : INHERITED(stream, info, proc) | 149 : INHERITED(stream, info, proc) |
| 150 , fOffsets(offsets) | |
| 151 , fSkipCommands(deletedCommands) | 150 , fSkipCommands(deletedCommands) |
| 152 , fTot(0.0) | 151 , fTot(0.0) |
| 153 , fCurCommand(0) { | 152 , fCurCommand(0) { |
| 154 fTimes.setCount(fOffsets.count()); | 153 fTimes.setCount(deletedCommands.count()); |
| 155 fTypeTimes.setCount(LAST_DRAWTYPE_ENUM+1); | 154 fTypeTimes.setCount(LAST_DRAWTYPE_ENUM+1); |
| 156 this->resetTimes(); | 155 this->resetTimes(); |
| 157 } | 156 } |
| 158 | 157 |
| 159 void resetTimes() { | 158 void resetTimes() { |
| 160 for (int i = 0; i < fOffsets.count(); ++i) { | 159 for (int i = 0; i < fTimes.count(); ++i) { |
| 161 fTimes[i] = 0.0; | 160 fTimes[i] = 0.0; |
| 162 } | 161 } |
| 163 for (int i = 0; i < fTypeTimes.count(); ++i) { | 162 for (int i = 0; i < fTypeTimes.count(); ++i) { |
| 164 fTypeTimes[i] = 0.0f; | 163 fTypeTimes[i] = 0.0f; |
| 165 } | 164 } |
| 166 fTot = 0.0; | 165 fTot = 0.0; |
| 167 } | 166 } |
| 168 | 167 |
| 169 int count() const { return fTimes.count(); } | 168 int count() const { return fTimes.count(); } |
| 170 | 169 |
| 171 double time(int index) const { return fTimes[index] / fTot; } | 170 double time(int index) const { return fTimes[index] / fTot; } |
| 172 | 171 |
| 173 const SkTDArray<double>* typeTimes() const { return &fTypeTimes; } | 172 const SkTDArray<double>* typeTimes() const { return &fTypeTimes; } |
| 174 | 173 |
| 175 double totTime() const { return fTot; } | 174 double totTime() const { return fTot; } |
| 176 | 175 |
| 177 protected: | 176 protected: |
| 178 BenchSysTimer fTimer; | 177 BenchSysTimer fTimer; |
| 179 SkTDArray<size_t> fOffsets; // offset in the SkPicture for each command | |
| 180 SkTDArray<bool> fSkipCommands; // has the command been deleted in the GUI? | 178 SkTDArray<bool> fSkipCommands; // has the command been deleted in the GUI? |
| 181 SkTDArray<double> fTimes; // sum of time consumed for each command | 179 SkTDArray<double> fTimes; // sum of time consumed for each command |
| 182 SkTDArray<double> fTypeTimes; // sum of time consumed for each type of comma nd (e.g., drawPath) | 180 SkTDArray<double> fTypeTimes; // sum of time consumed for each type of comma nd (e.g., drawPath) |
| 183 double fTot; // total of all times in 'fTimes' | 181 double fTot; // total of all times in 'fTimes' |
| 184 size_t fCurOffset; | 182 size_t fCurOffset; |
|
scroggo
2013/05/22 14:11:07
Is this still being used?
robertphillips
2013/05/22 18:51:28
Nope - deleted.
| |
| 185 int fCurType; | 183 int fCurType; |
| 186 int fCurCommand; // the current command being executed/timed | 184 int fCurCommand; // the current command being executed/timed |
| 187 | 185 |
| 188 virtual size_t preDraw(size_t offset, int type) { | 186 virtual bool preDraw(int opNum, int type) { |
|
scroggo
2013/05/22 14:11:07
SK_OVERRIDE.
Also, should these be inside #ifdef
robertphillips
2013/05/22 18:51:28
Done.
| |
| 189 // This search isn't as bad as it seems. In normal playback mode, the | 187 fCurCommand = opNum; |
| 190 // base class steps through the commands in order and can only skip ahea d | 188 |
| 191 // a bit on a clip. This class is only used during profiling so we | 189 if (fSkipCommands[fCurCommand]) { |
| 192 // don't have to worry about forward/backward scrubbing through commands . | 190 return true; |
| 193 for (int i = 0; offset != fOffsets[fCurCommand]; ++i) { | |
| 194 fCurCommand = (fCurCommand+1) % fOffsets.count(); | |
| 195 SkASSERT(i <= fOffsets.count()); // should always find the offset in the list | |
| 196 } | 191 } |
| 197 | 192 |
| 198 if (fSkipCommands[fCurCommand]) { | |
| 199 while (fCurCommand < fSkipCommands.count() && fSkipCommands[fCurComm and]) { | |
| 200 ++fCurCommand; | |
| 201 } | |
| 202 if (fCurCommand == fSkipCommands.count()) { | |
| 203 // Signal SkPicturePlayback to stop playing back | |
| 204 return SK_MaxU32; | |
| 205 } | |
| 206 return fOffsets[fCurCommand]; | |
| 207 } | |
| 208 | |
| 209 fCurOffset = offset; | |
| 210 fCurType = type; | 193 fCurType = type; |
| 211 // The SkDebugCanvas doesn't recognize these types. This class needs to | 194 // The SkDebugCanvas doesn't recognize these types. This class needs to |
| 212 // convert or else we'll wind up with a mismatch between the type counts | 195 // convert or else we'll wind up with a mismatch between the type counts |
| 213 // the debugger displays and the profile times. | 196 // the debugger displays and the profile times. |
| 214 if (DRAW_POS_TEXT_TOP_BOTTOM == type) { | 197 if (DRAW_POS_TEXT_TOP_BOTTOM == type) { |
| 215 fCurType = DRAW_POS_TEXT; | 198 fCurType = DRAW_POS_TEXT; |
| 216 } else if (DRAW_POS_TEXT_H_TOP_BOTTOM == type) { | 199 } else if (DRAW_POS_TEXT_H_TOP_BOTTOM == type) { |
| 217 fCurType = DRAW_POS_TEXT_H; | 200 fCurType = DRAW_POS_TEXT_H; |
| 218 } | 201 } |
| 219 | 202 |
| 220 #if defined(SK_BUILD_FOR_WIN32) | 203 #if defined(SK_BUILD_FOR_WIN32) |
| 221 // CPU timer doesn't work well on Windows | 204 // CPU timer doesn't work well on Windows |
| 222 fTimer.startWall(); | 205 fTimer.startWall(); |
| 223 #else | 206 #else |
| 224 fTimer.startCpu(); | 207 fTimer.startCpu(); |
| 225 #endif | 208 #endif |
| 226 | 209 |
| 227 return 0; | 210 return false; |
| 228 } | 211 } |
| 229 | 212 |
| 230 virtual void postDraw(size_t offset) { | 213 virtual void postDraw(int opNum) { |
|
scroggo
2013/05/22 14:11:07
SK_OVERRIDE
robertphillips
2013/05/22 18:51:28
Done.
| |
| 231 #if defined(SK_BUILD_FOR_WIN32) | 214 #if defined(SK_BUILD_FOR_WIN32) |
| 232 // CPU timer doesn't work well on Windows | 215 // CPU timer doesn't work well on Windows |
| 233 double time = fTimer.endWall(); | 216 double time = fTimer.endWall(); |
| 234 #else | 217 #else |
| 235 double time = fTimer.endCpu(); | 218 double time = fTimer.endCpu(); |
| 236 #endif | 219 #endif |
| 237 | 220 |
| 238 SkASSERT(offset == fCurOffset); | 221 SkASSERT(opNum == fCurCommand); |
| 239 SkASSERT(fCurType <= LAST_DRAWTYPE_ENUM); | 222 SkASSERT(fCurType <= LAST_DRAWTYPE_ENUM); |
| 240 | 223 |
| 241 fTimes[fCurCommand] += time; | 224 fTimes[fCurCommand] += time; |
| 242 fTypeTimes[fCurType] += time; | 225 fTypeTimes[fCurType] += time; |
| 243 fTot += time; | 226 fTot += time; |
| 244 } | 227 } |
| 245 | 228 |
| 246 private: | 229 private: |
| 247 typedef SkPicturePlayback INHERITED; | 230 typedef SkPicturePlayback INHERITED; |
| 248 }; | 231 }; |
| 249 | 232 |
| 250 // Wrap SkPicture to allow installation of an SkTimedPicturePlayback object | 233 // Wrap SkPicture to allow installation of an SkTimedPicturePlayback object |
| 251 class SkTimedPicture : public SkPicture { | 234 class SkTimedPicture : public SkPicture { |
| 252 public: | 235 public: |
| 253 explicit SkTimedPicture(SkStream* stream, bool* success, SkPicture::InstallP ixelRefProc proc, | 236 explicit SkTimedPicture(SkStream* stream, bool* success, SkPicture::InstallP ixelRefProc proc, |
| 254 const SkTDArray<size_t>& offsets, | |
| 255 const SkTDArray<bool>& deletedCommands) { | 237 const SkTDArray<bool>& deletedCommands) { |
| 256 if (success) { | 238 if (success) { |
| 257 *success = false; | 239 *success = false; |
| 258 } | 240 } |
| 259 fRecord = NULL; | 241 fRecord = NULL; |
| 260 fPlayback = NULL; | 242 fPlayback = NULL; |
| 261 fWidth = fHeight = 0; | 243 fWidth = fHeight = 0; |
| 262 | 244 |
| 263 SkPictInfo info; | 245 SkPictInfo info; |
| 264 | 246 |
| 265 if (!stream->read(&info, sizeof(info))) { | 247 if (!stream->read(&info, sizeof(info))) { |
| 266 return; | 248 return; |
| 267 } | 249 } |
| 268 if (SkPicture::PICTURE_VERSION != info.fVersion) { | 250 if (SkPicture::PICTURE_VERSION != info.fVersion) { |
| 269 return; | 251 return; |
| 270 } | 252 } |
| 271 | 253 |
| 272 if (stream->readBool()) { | 254 if (stream->readBool()) { |
| 273 fPlayback = SkNEW_ARGS(SkTimedPicturePlayback, | 255 fPlayback = SkNEW_ARGS(SkTimedPicturePlayback, |
| 274 (stream, info, proc, offsets, deletedCommands )); | 256 (stream, info, proc, deletedCommands)); |
| 275 } | 257 } |
| 276 | 258 |
| 277 // do this at the end, so that they will be zero if we hit an error. | 259 // do this at the end, so that they will be zero if we hit an error. |
| 278 fWidth = info.fWidth; | 260 fWidth = info.fWidth; |
| 279 fHeight = info.fHeight; | 261 fHeight = info.fHeight; |
| 280 if (success) { | 262 if (success) { |
| 281 *success = true; | 263 *success = true; |
| 282 } | 264 } |
| 283 } | 265 } |
| 284 | 266 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 347 | 329 |
| 348 SkFILEStream inputStream; | 330 SkFILEStream inputStream; |
| 349 | 331 |
| 350 inputStream.setPath(fFileName.c_str()); | 332 inputStream.setPath(fFileName.c_str()); |
| 351 if (!inputStream.isValid()) { | 333 if (!inputStream.isValid()) { |
| 352 return; | 334 return; |
| 353 } | 335 } |
| 354 | 336 |
| 355 bool success = false; | 337 bool success = false; |
| 356 SkTimedPicture picture(&inputStream, &success, &SkImageDecoder::DecodeMemory , | 338 SkTimedPicture picture(&inputStream, &success, &SkImageDecoder::DecodeMemory , |
| 357 fOffsets, fSkipCommands); | 339 fSkipCommands); |
| 358 if (!success) { | 340 if (!success) { |
| 359 return; | 341 return; |
| 360 } | 342 } |
| 361 | 343 |
| 362 // For now this #if allows switching between tiled and simple rendering | 344 // For now this #if allows switching between tiled and simple rendering |
| 363 // modes. Eventually this will be accomplished via the GUI | 345 // modes. Eventually this will be accomplished via the GUI |
| 364 #if 0 | 346 #if 0 |
| 365 // With the current batch of SysTimers, profiling in tiled mode | 347 // With the current batch of SysTimers, profiling in tiled mode |
| 366 // gets swamped by the timing overhead: | 348 // gets swamped by the timing overhead: |
| 367 // | 349 // |
| (...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 907 QDir dir(path); | 889 QDir dir(path); |
| 908 QRegExp r(".skp"); | 890 QRegExp r(".skp"); |
| 909 fDirectoryWidget.clear(); | 891 fDirectoryWidget.clear(); |
| 910 const QStringList files = dir.entryList(); | 892 const QStringList files = dir.entryList(); |
| 911 foreach (QString f, files) { | 893 foreach (QString f, files) { |
| 912 if (f.contains(r)) | 894 if (f.contains(r)) |
| 913 fDirectoryWidget.addItem(f); | 895 fDirectoryWidget.addItem(f); |
| 914 } | 896 } |
| 915 } | 897 } |
| 916 | 898 |
| 917 // SkOffsetPicturePlayback records the offset of each command in the picture. | |
| 918 // These are needed by the profiling system. | |
| 919 class SkOffsetPicturePlayback : public SkPicturePlayback { | |
| 920 public: | |
| 921 SkOffsetPicturePlayback(SkStream* stream, const SkPictInfo& info, | |
| 922 SkPicture::InstallPixelRefProc proc) | |
| 923 : INHERITED(stream, info, proc) { | |
| 924 } | |
| 925 | |
| 926 const SkTDArray<size_t>& offsets() const { return fOffsets; } | |
| 927 | |
| 928 protected: | |
| 929 SkTDArray<size_t> fOffsets; | |
| 930 | |
| 931 virtual size_t preDraw(size_t offset, int type) { | |
| 932 *fOffsets.append() = offset; | |
| 933 return 0; | |
| 934 } | |
| 935 | |
| 936 private: | |
| 937 typedef SkPicturePlayback INHERITED; | |
| 938 }; | |
| 939 | |
| 940 // Picture to wrap an SkOffsetPicturePlayback. | |
| 941 class SkOffsetPicture : public SkPicture { | |
| 942 public: | |
| 943 SkOffsetPicture(SkStream* stream, bool* success, SkPicture::InstallPixelRefP roc proc) { | |
| 944 if (success) { | |
| 945 *success = false; | |
| 946 } | |
| 947 fRecord = NULL; | |
| 948 fPlayback = NULL; | |
| 949 fWidth = fHeight = 0; | |
| 950 | |
| 951 SkPictInfo info; | |
| 952 | |
| 953 if (!stream->read(&info, sizeof(info))) { | |
| 954 return; | |
| 955 } | |
| 956 if (PICTURE_VERSION != info.fVersion) { | |
| 957 return; | |
| 958 } | |
| 959 | |
| 960 if (stream->readBool()) { | |
| 961 fPlayback = SkNEW_ARGS(SkOffsetPicturePlayback, (stream, info, proc) ); | |
| 962 } | |
| 963 | |
| 964 // do this at the end, so that they will be zero if we hit an error. | |
| 965 fWidth = info.fWidth; | |
| 966 fHeight = info.fHeight; | |
| 967 if (success) { | |
| 968 *success = true; | |
| 969 } | |
| 970 } | |
| 971 | |
| 972 const SkTDArray<size_t>& offsets() const { | |
| 973 return ((SkOffsetPicturePlayback*) fPlayback)->offsets(); | |
| 974 } | |
| 975 | |
| 976 private: | |
| 977 // disallow default ctor b.c. we don't have a good way to setup the fPlaybac k ptr | |
| 978 SkOffsetPicture(); | |
| 979 // disallow the copy ctor - enabling would require copying code from SkPictu re | |
| 980 SkOffsetPicture(const SkOffsetPicture& src); | |
| 981 | |
| 982 typedef SkPicture INHERITED; | |
| 983 }; | |
| 984 | |
| 985 | |
| 986 | |
| 987 void SkDebuggerGUI::loadPicture(const SkString& fileName) { | 899 void SkDebuggerGUI::loadPicture(const SkString& fileName) { |
| 988 fFileName = fileName; | 900 fFileName = fileName; |
| 989 fLoading = true; | 901 fLoading = true; |
| 990 SkStream* stream = SkNEW_ARGS(SkFILEStream, (fileName.c_str())); | 902 SkStream* stream = SkNEW_ARGS(SkFILEStream, (fileName.c_str())); |
| 991 | 903 |
| 992 bool success = false; | 904 bool success = false; |
| 993 | 905 |
| 994 SkOffsetPicture* picture = SkNEW_ARGS(SkOffsetPicture, | 906 SkPicture* picture = SkNEW_ARGS(SkPicture, |
| 995 (stream, &success, &SkImageDecoder::De codeMemory)); | 907 (stream, &success, &SkImageDecoder::DecodeMe mory)); |
| 996 | 908 |
| 997 if (!success) { | 909 if (!success) { |
| 998 QMessageBox::critical(this, "Error loading file", "Couldn't read file, s orry."); | 910 QMessageBox::critical(this, "Error loading file", "Couldn't read file, s orry."); |
| 999 SkSafeUnref(stream); | 911 SkSafeUnref(stream); |
| 1000 return; | 912 return; |
| 1001 } | 913 } |
| 1002 | 914 |
| 1003 fCanvasWidget.resetWidgetTransform(); | 915 fCanvasWidget.resetWidgetTransform(); |
| 1004 fDebugger.loadPicture(picture); | 916 fDebugger.loadPicture(picture); |
| 1005 | 917 |
| 1006 fOffsets = picture->offsets(); | 918 // Will this automatically clear out due to nature of refcnt? |
| 919 SkTArray<SkString>* commands = fDebugger.getDrawCommandsAsStrings(); | |
|
djsollen
2013/05/22 14:35:37
if you just want the count use fDebugger.getSize()
robertphillips
2013/05/22 18:51:28
Done-ish. I'm now using getSize and have moved the
scroggo
2013/05/22 19:06:13
Agreed. Can you put commands into an SkAutoTDelete
| |
| 1007 | 920 |
| 1008 fSkipCommands.setCount(fOffsets.count()); | 921 fSkipCommands.setCount(commands->count()); |
| 1009 for (int i = 0; i < fOffsets.count(); ++i) { | 922 for (int i = 0; i < fSkipCommands.count(); ++i) { |
| 1010 fSkipCommands[i] = false; | 923 fSkipCommands[i] = false; |
| 1011 } | 924 } |
| 1012 | 925 |
| 1013 SkSafeUnref(stream); | 926 SkSafeUnref(stream); |
| 1014 SkSafeUnref(picture); | 927 SkSafeUnref(picture); |
| 1015 | 928 |
| 1016 // Will this automatically clear out due to nature of refcnt? | 929 fActionProfile.setDisabled(false); |
| 1017 SkTArray<SkString>* commands = fDebugger.getDrawCommandsAsStrings(); | |
| 1018 | |
| 1019 // If SkPicturePlayback is compiled w/o SK_PICTURE_PROFILING_STUBS | |
| 1020 // the offset count will always be zero | |
| 1021 SkASSERT(0 == fOffsets.count() || commands->count() == fOffsets.count()); | |
| 1022 if (commands->count() == fOffsets.count()) { | |
| 1023 fActionProfile.setDisabled(false); | |
| 1024 } | |
| 1025 | 930 |
| 1026 /* fDebugCanvas is reinitialized every load picture. Need it to retain value | 931 /* fDebugCanvas is reinitialized every load picture. Need it to retain value |
| 1027 * of the visibility filter. | 932 * of the visibility filter. |
| 1028 * TODO(chudy): This should be deprecated since fDebugger is not | 933 * TODO(chudy): This should be deprecated since fDebugger is not |
| 1029 * recreated. | 934 * recreated. |
| 1030 * */ | 935 * */ |
| 1031 fDebugger.highlightCurrentCommand(fSettingsWidget.getVisibilityButton()->isC hecked()); | 936 fDebugger.highlightCurrentCommand(fSettingsWidget.getVisibilityButton()->isC hecked()); |
| 1032 | 937 |
| 1033 setupListWidget(commands); | 938 setupListWidget(commands); |
| 1034 setupComboBox(commands); | 939 setupComboBox(commands); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1093 } | 998 } |
| 1094 | 999 |
| 1095 // NOTE(chudy): Makes first item unselectable. | 1000 // NOTE(chudy): Makes first item unselectable. |
| 1096 QStandardItemModel* model = qobject_cast<QStandardItemModel*>( | 1001 QStandardItemModel* model = qobject_cast<QStandardItemModel*>( |
| 1097 fFilter.model()); | 1002 fFilter.model()); |
| 1098 QModelIndex firstIndex = model->index(0, fFilter.modelColumn(), | 1003 QModelIndex firstIndex = model->index(0, fFilter.modelColumn(), |
| 1099 fFilter.rootModelIndex()); | 1004 fFilter.rootModelIndex()); |
| 1100 QStandardItem* firstItem = model->itemFromIndex(firstIndex); | 1005 QStandardItem* firstItem = model->itemFromIndex(firstIndex); |
| 1101 firstItem->setSelectable(false); | 1006 firstItem->setSelectable(false); |
| 1102 } | 1007 } |
| OLD | NEW |