diff options
Diffstat (limited to 'debugger')
-rw-r--r-- | debugger/QT/SkDebuggerGUI.cpp | 245 | ||||
-rw-r--r-- | debugger/QT/SkDebuggerGUI.h | 1 |
2 files changed, 245 insertions, 1 deletions
diff --git a/debugger/QT/SkDebuggerGUI.cpp b/debugger/QT/SkDebuggerGUI.cpp index f61371b293..6ad4805aa5 100644 --- a/debugger/QT/SkDebuggerGUI.cpp +++ b/debugger/QT/SkDebuggerGUI.cpp @@ -9,6 +9,12 @@ #include "SkGraphics.h" #include "SkImageDecoder.h" #include <QListWidgetItem> +#include "PictureBenchmark.h" +#include "PictureRenderer.h" +#include "SkBenchLogger.h" +#include "SkPictureRecord.h" +#include "SkPicturePlayback.h" +#include "BenchTimer.h" SkDebuggerGUI::SkDebuggerGUI(QWidget *parent) : QMainWindow(parent) @@ -119,7 +125,167 @@ void SkDebuggerGUI::showDeletes() { } } +// The timed picture playback uses the SkPicturePlayback's profiling stubs +// to time individual commands. The offsets are needed to map SkPicture +// offsets to individual commands. +class SkTimedPicturePlayback : public SkPicturePlayback { +public: + SkTimedPicturePlayback(SkStream* stream, const SkPictInfo& info, bool* isValid, + SkSerializationHelpers::DecodeBitmap decoder, + const SkTDArray<size_t>& offsets) + : INHERITED(stream, info, isValid, decoder) + , fTot(0.0) + , fCurCommand(0) + , fOffsets(offsets) { + fTimes.setCount(fOffsets.count()); + for (int i = 0; i < fOffsets.count(); ++i) { + fTimes[i] = 0; + } + } + + int count() const { return fTimes.count(); } + + double time(int index) const { return fTimes[index] / fTot; } + +protected: + BenchTimer fTimer; + SkTDArray<size_t> fOffsets; // offset in the SkPicture for each command + SkTDArray<double> fTimes; // sum of time consumed for each command + double fTot; // total of all times in 'fTimes' + size_t fCurOffset; + int fCurCommand; // the current command being executed/timed + + virtual void preDraw(size_t offset, int type) { + // This search isn't as bad as it seems. In normal playback mode, the + // base class steps through the commands in order and can only skip ahead + // a bit on a clip. This class is only used during profiling so we + // don't have to worry about forward/backward scrubbing through commands. + for (int i = 0; offset != fOffsets[fCurCommand]; ++i) { + fCurCommand = (fCurCommand+1) % fOffsets.count(); + SkASSERT(i <= fOffsets.count()); // should always find the offset in the list + } + + fCurOffset = offset; + + fTimer.start(); + } + + virtual void postDraw(size_t offset) { + fTimer.end(); + + SkASSERT(offset == fCurOffset); + + fTimes[fCurCommand] += fTimer.fWall; + fTot += fTimer.fWall; + } + +private: + typedef SkPicturePlayback INHERITED; +}; + +// Wrap SkPicture to allow installation of an SkTimedPicturePlayback object +class SkTimedPicture : public SkPicture { +public: + explicit SkTimedPicture(SkStream* stream, + bool* success, + SkSerializationHelpers::DecodeBitmap decoder, + const SkTDArray<size_t>& offsets) { + if (success) { + *success = false; + } + fRecord = NULL; + fPlayback = NULL; + fWidth = fHeight = 0; + + SkPictInfo info; + + if (!stream->read(&info, sizeof(info))) { + return; + } + if (SkPicture::PICTURE_VERSION != info.fVersion) { + return; + } + + if (stream->readBool()) { + bool isValid = false; + fPlayback = SkNEW_ARGS(SkTimedPicturePlayback, + (stream, info, &isValid, decoder, offsets)); + if (!isValid) { + SkDELETE(fPlayback); + fPlayback = NULL; + return; + } + } + + // do this at the end, so that they will be zero if we hit an error. + fWidth = info.fWidth; + fHeight = info.fHeight; + if (success) { + *success = true; + } + } + + int count() const { return ((SkTimedPicturePlayback*) fPlayback)->count(); } + + // return the fraction of the total time this command consumed + double time(int index) const { return ((SkTimedPicturePlayback*) fPlayback)->time(index); } + +private: + typedef SkPicture INHERITED; +}; + void SkDebuggerGUI::actionProfile() { + // In order to profile we pass the command offsets (that were read-in + // in loadPicture by the SkOffsetPicture) to an SkTimedPlaybackPicture. + // The SkTimedPlaybackPicture in turn passes the offsets to an + // SkTimedPicturePlayback object which uses them to track the performance + // of individual commands. + if (fFileName.isEmpty()) { + return; + } + + SkFILEStream inputStream; + + inputStream.setPath(fFileName.c_str()); + if (!inputStream.isValid()) { + return; + } + + bool success = false; + SkTimedPicture picture(&inputStream, &success, &SkImageDecoder::DecodeStream, fOffsets); + if (!success) { + return; + } + + sk_tools::PictureBenchmark benchmark; + + sk_tools::TiledPictureRenderer* renderer = NULL; + + renderer = SkNEW(sk_tools::TiledPictureRenderer); + renderer->setTileWidth(256); + renderer->setTileHeight(256); + + + benchmark.setRepeats(2); + benchmark.setRenderer(renderer); + benchmark.setTimersToShow(true, false, true, false, false); + + SkBenchLogger logger; + + benchmark.setLogger(&logger); + + benchmark.run(&picture); + + SkASSERT(picture.count() == fListWidget.count()); + + // extract the individual command times from the SkTimedPlaybackPicture + for (int i = 0; i < picture.count(); ++i) { + double temp = picture.time(i); + + QListWidgetItem* item = fListWidget.item(i); + + item->setData(Qt::UserRole + 4, 100.0*temp); + } } void SkDebuggerGUI::actionCancel() { @@ -585,20 +751,97 @@ void SkDebuggerGUI::setupDirectoryWidget() { } } +// SkOffsetPicturePlayback records the offset of each command in the picture. +// These are needed by the profiling system. +class SkOffsetPicturePlayback : public SkPicturePlayback { +public: + SkOffsetPicturePlayback(SkStream* stream, const SkPictInfo& info, bool* isValid, + SkSerializationHelpers::DecodeBitmap decoder) + : INHERITED(stream, info, isValid, decoder) { + } + + const SkTDArray<size_t>& offsets() const { return fOffsets; } + +protected: + SkTDArray<size_t> fOffsets; + + virtual void preDraw(size_t offset, int type) { + *fOffsets.append() = offset; + } + +private: + typedef SkPicturePlayback INHERITED; +}; + +// Picture to wrap an SkOffsetPicturePlayback. +class SkOffsetPicture : public SkPicture { +public: + SkOffsetPicture(SkStream* stream, + bool* success, + SkSerializationHelpers::DecodeBitmap decoder) { + if (success) { + *success = false; + } + fRecord = NULL; + fPlayback = NULL; + fWidth = fHeight = 0; + + SkPictInfo info; + + if (!stream->read(&info, sizeof(info))) { + return; + } + if (PICTURE_VERSION != info.fVersion) { + return; + } + + if (stream->readBool()) { + bool isValid = false; + fPlayback = SkNEW_ARGS(SkOffsetPicturePlayback, (stream, info, &isValid, decoder)); + if (!isValid) { + SkDELETE(fPlayback); + fPlayback = NULL; + return; + } + } + + // do this at the end, so that they will be zero if we hit an error. + fWidth = info.fWidth; + fHeight = info.fHeight; + if (success) { + *success = true; + } + } + + const SkTDArray<size_t>& offsets() const { + return ((SkOffsetPicturePlayback*) fPlayback)->offsets(); + } + +private: + typedef SkPicture INHERITED; +}; + + + void SkDebuggerGUI::loadPicture(const SkString& fileName) { fFileName = fileName; fLoading = true; SkStream* stream = SkNEW_ARGS(SkFILEStream, (fileName.c_str())); - SkPicture* picture = SkNEW_ARGS(SkPicture, (stream, NULL, &SkImageDecoder::DecodeStream)); + SkOffsetPicture* picture = SkNEW_ARGS(SkOffsetPicture, (stream, NULL, &SkImageDecoder::DecodeStream)); + fCanvasWidget.resetWidgetTransform(); fDebugger.loadPicture(picture); + fOffsets = picture->offsets(); + SkSafeUnref(stream); SkSafeUnref(picture); // Will this automatically clear out due to nature of refcnt? SkTDArray<SkString*>* commands = fDebugger.getDrawCommands(); + SkASSERT(commands->count() == fOffsets.count()); + /* fDebugCanvas is reinitialized every load picture. Need it to retain value * of the visibility filter. * TODO(chudy): This should be deprecated since fDebugger is not diff --git a/debugger/QT/SkDebuggerGUI.h b/debugger/QT/SkDebuggerGUI.h index 0ad275e76a..570ebdbf12 100644 --- a/debugger/QT/SkDebuggerGUI.h +++ b/debugger/QT/SkDebuggerGUI.h @@ -251,6 +251,7 @@ private: QString fPath; SkString fFileName; + SkTDArray<size_t> fOffsets; // the offset of each command in the SkPicture bool fDirectoryWidgetActive; QMenuBar fMenuBar; |