| 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; | |
| 185 int fCurType; | 182 int fCurType; |
| 186 int fCurCommand; // the current command being executed/timed | 183 int fCurCommand; // the current command being executed/timed |
| 187 | 184 |
| 188 virtual size_t preDraw(size_t offset, int type) { | 185 #ifdef SK_DEVELOPER |
| 189 // This search isn't as bad as it seems. In normal playback mode, the | 186 virtual bool preDraw(int opIndex, int type) SK_OVERRIDE { |
| 190 // base class steps through the commands in order and can only skip ahea
d | 187 fCurCommand = opIndex; |
| 191 // a bit on a clip. This class is only used during profiling so we | 188 |
| 192 // don't have to worry about forward/backward scrubbing through commands
. | 189 if (fSkipCommands[fCurCommand]) { |
| 193 for (int i = 0; offset != fOffsets[fCurCommand]; ++i) { | 190 return true; |
| 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 opIndex) SK_OVERRIDE { |
| 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(opIndex == 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 } |
| 228 #endif |
| 245 | 229 |
| 246 private: | 230 private: |
| 247 typedef SkPicturePlayback INHERITED; | 231 typedef SkPicturePlayback INHERITED; |
| 248 }; | 232 }; |
| 249 | 233 |
| 250 // Wrap SkPicture to allow installation of an SkTimedPicturePlayback object | 234 // Wrap SkPicture to allow installation of an SkTimedPicturePlayback object |
| 251 class SkTimedPicture : public SkPicture { | 235 class SkTimedPicture : public SkPicture { |
| 252 public: | 236 public: |
| 253 explicit SkTimedPicture(SkStream* stream, bool* success, SkPicture::InstallP
ixelRefProc proc, | 237 explicit SkTimedPicture(SkStream* stream, bool* success, SkPicture::InstallP
ixelRefProc proc, |
| 254 const SkTDArray<size_t>& offsets, | |
| 255 const SkTDArray<bool>& deletedCommands) { | 238 const SkTDArray<bool>& deletedCommands) { |
| 256 if (success) { | 239 if (success) { |
| 257 *success = false; | 240 *success = false; |
| 258 } | 241 } |
| 259 fRecord = NULL; | 242 fRecord = NULL; |
| 260 fPlayback = NULL; | 243 fPlayback = NULL; |
| 261 fWidth = fHeight = 0; | 244 fWidth = fHeight = 0; |
| 262 | 245 |
| 263 SkPictInfo info; | 246 SkPictInfo info; |
| 264 | 247 |
| 265 if (!stream->read(&info, sizeof(info))) { | 248 if (!stream->read(&info, sizeof(info))) { |
| 266 return; | 249 return; |
| 267 } | 250 } |
| 268 if (SkPicture::PICTURE_VERSION != info.fVersion) { | 251 if (SkPicture::PICTURE_VERSION != info.fVersion) { |
| 269 return; | 252 return; |
| 270 } | 253 } |
| 271 | 254 |
| 272 if (stream->readBool()) { | 255 if (stream->readBool()) { |
| 273 fPlayback = SkNEW_ARGS(SkTimedPicturePlayback, | 256 fPlayback = SkNEW_ARGS(SkTimedPicturePlayback, |
| 274 (stream, info, proc, offsets, deletedCommands
)); | 257 (stream, info, proc, deletedCommands)); |
| 275 } | 258 } |
| 276 | 259 |
| 277 // do this at the end, so that they will be zero if we hit an error. | 260 // do this at the end, so that they will be zero if we hit an error. |
| 278 fWidth = info.fWidth; | 261 fWidth = info.fWidth; |
| 279 fHeight = info.fHeight; | 262 fHeight = info.fHeight; |
| 280 if (success) { | 263 if (success) { |
| 281 *success = true; | 264 *success = true; |
| 282 } | 265 } |
| 283 } | 266 } |
| 284 | 267 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 | 330 |
| 348 SkFILEStream inputStream; | 331 SkFILEStream inputStream; |
| 349 | 332 |
| 350 inputStream.setPath(fFileName.c_str()); | 333 inputStream.setPath(fFileName.c_str()); |
| 351 if (!inputStream.isValid()) { | 334 if (!inputStream.isValid()) { |
| 352 return; | 335 return; |
| 353 } | 336 } |
| 354 | 337 |
| 355 bool success = false; | 338 bool success = false; |
| 356 SkTimedPicture picture(&inputStream, &success, &SkImageDecoder::DecodeMemory
, | 339 SkTimedPicture picture(&inputStream, &success, &SkImageDecoder::DecodeMemory
, |
| 357 fOffsets, fSkipCommands); | 340 fSkipCommands); |
| 358 if (!success) { | 341 if (!success) { |
| 359 return; | 342 return; |
| 360 } | 343 } |
| 361 | 344 |
| 362 // For now this #if allows switching between tiled and simple rendering | 345 // For now this #if allows switching between tiled and simple rendering |
| 363 // modes. Eventually this will be accomplished via the GUI | 346 // modes. Eventually this will be accomplished via the GUI |
| 364 #if 0 | 347 #if 0 |
| 365 // With the current batch of SysTimers, profiling in tiled mode | 348 // With the current batch of SysTimers, profiling in tiled mode |
| 366 // gets swamped by the timing overhead: | 349 // gets swamped by the timing overhead: |
| 367 // | 350 // |
| (...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 907 QDir dir(path); | 890 QDir dir(path); |
| 908 QRegExp r(".skp"); | 891 QRegExp r(".skp"); |
| 909 fDirectoryWidget.clear(); | 892 fDirectoryWidget.clear(); |
| 910 const QStringList files = dir.entryList(); | 893 const QStringList files = dir.entryList(); |
| 911 foreach (QString f, files) { | 894 foreach (QString f, files) { |
| 912 if (f.contains(r)) | 895 if (f.contains(r)) |
| 913 fDirectoryWidget.addItem(f); | 896 fDirectoryWidget.addItem(f); |
| 914 } | 897 } |
| 915 } | 898 } |
| 916 | 899 |
| 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) { | 900 void SkDebuggerGUI::loadPicture(const SkString& fileName) { |
| 988 fFileName = fileName; | 901 fFileName = fileName; |
| 989 fLoading = true; | 902 fLoading = true; |
| 990 SkStream* stream = SkNEW_ARGS(SkFILEStream, (fileName.c_str())); | 903 SkStream* stream = SkNEW_ARGS(SkFILEStream, (fileName.c_str())); |
| 991 | 904 |
| 992 bool success = false; | 905 bool success = false; |
| 993 | 906 |
| 994 SkOffsetPicture* picture = SkNEW_ARGS(SkOffsetPicture, | 907 SkPicture* picture = SkNEW_ARGS(SkPicture, |
| 995 (stream, &success, &SkImageDecoder::De
codeMemory)); | 908 (stream, &success, &SkImageDecoder::DecodeMe
mory)); |
| 996 | 909 |
| 997 if (!success) { | 910 if (!success) { |
| 998 QMessageBox::critical(this, "Error loading file", "Couldn't read file, s
orry."); | 911 QMessageBox::critical(this, "Error loading file", "Couldn't read file, s
orry."); |
| 999 SkSafeUnref(stream); | 912 SkSafeUnref(stream); |
| 1000 return; | 913 return; |
| 1001 } | 914 } |
| 1002 | 915 |
| 1003 fCanvasWidget.resetWidgetTransform(); | 916 fCanvasWidget.resetWidgetTransform(); |
| 1004 fDebugger.loadPicture(picture); | 917 fDebugger.loadPicture(picture); |
| 1005 | 918 |
| 1006 fOffsets = picture->offsets(); | 919 fSkipCommands.setCount(fDebugger.getSize()); |
| 1007 | 920 for (int i = 0; i < fSkipCommands.count(); ++i) { |
| 1008 fSkipCommands.setCount(fOffsets.count()); | |
| 1009 for (int i = 0; i < fOffsets.count(); ++i) { | |
| 1010 fSkipCommands[i] = false; | 921 fSkipCommands[i] = false; |
| 1011 } | 922 } |
| 1012 | 923 |
| 1013 SkSafeUnref(stream); | 924 SkSafeUnref(stream); |
| 1014 SkSafeUnref(picture); | 925 SkSafeUnref(picture); |
| 1015 | 926 |
| 1016 // Will this automatically clear out due to nature of refcnt? | 927 // Will this automatically clear out due to nature of refcnt? |
| 1017 SkTArray<SkString>* commands = fDebugger.getDrawCommandsAsStrings(); | 928 SkTArray<SkString>* commands = fDebugger.getDrawCommandsAsStrings(); |
| 1018 | 929 |
| 1019 // If SkPicturePlayback is compiled w/o SK_PICTURE_PROFILING_STUBS | 930 fActionProfile.setDisabled(false); |
| 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 | 931 |
| 1026 /* fDebugCanvas is reinitialized every load picture. Need it to retain value | 932 /* fDebugCanvas is reinitialized every load picture. Need it to retain value |
| 1027 * of the visibility filter. | 933 * of the visibility filter. |
| 1028 * TODO(chudy): This should be deprecated since fDebugger is not | 934 * TODO(chudy): This should be deprecated since fDebugger is not |
| 1029 * recreated. | 935 * recreated. |
| 1030 * */ | 936 * */ |
| 1031 fDebugger.highlightCurrentCommand(fSettingsWidget.getVisibilityButton()->isC
hecked()); | 937 fDebugger.highlightCurrentCommand(fSettingsWidget.getVisibilityButton()->isC
hecked()); |
| 1032 | 938 |
| 1033 setupListWidget(commands); | 939 setupListWidget(commands); |
| 1034 setupComboBox(commands); | 940 setupComboBox(commands); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1093 } | 999 } |
| 1094 | 1000 |
| 1095 // NOTE(chudy): Makes first item unselectable. | 1001 // NOTE(chudy): Makes first item unselectable. |
| 1096 QStandardItemModel* model = qobject_cast<QStandardItemModel*>( | 1002 QStandardItemModel* model = qobject_cast<QStandardItemModel*>( |
| 1097 fFilter.model()); | 1003 fFilter.model()); |
| 1098 QModelIndex firstIndex = model->index(0, fFilter.modelColumn(), | 1004 QModelIndex firstIndex = model->index(0, fFilter.modelColumn(), |
| 1099 fFilter.rootModelIndex()); | 1005 fFilter.rootModelIndex()); |
| 1100 QStandardItem* firstItem = model->itemFromIndex(firstIndex); | 1006 QStandardItem* firstItem = model->itemFromIndex(firstIndex); |
| 1101 firstItem->setSelectable(false); | 1007 firstItem->setSelectable(false); |
| 1102 } | 1008 } |
| OLD | NEW |