[PATCH 4/6] Prepare to receive sparse thumbnail data

Dan McCabe zen3d.linux at gmail.com
Fri Jun 1 13:40:05 PDT 2012


The previous implementation assumed that all frame thumbnails would be
provided to the trace by the retracer. Now, not only are just a subset of
frame thumbnails being provided, but call thumbnails may also be present,
depending on where the user was looking.

Therefore, rather than process a list of thumbnails, one for each frame,
this patch modifies the code to process a hash table of thumbnails which
is addressed by the call index.

In addition, the code now needs to extract the call index that was encoded
by glretrace as an image comment. Therefore, the PNM parser will now
attempt to interpret the comment in the PNM header as a number and return
it in addition to the other header data.

In order for Qt to manage the modified message data, main.cpp now has to
define a different data packet as well (ImageHash). I tried to not define
that new type but the Qt preprocessor didn't like the two type parameters
I was using.

Finally, ApiTrace::bindThumbnails is made more generic to deal with the
sparse data in the hash table as well as potentially assign call
thumbnails as well as frame thumbnails.
---
 common/image.hpp     |    2 +-
 common/image_pnm.cpp |   12 +++++++++++-
 gui/apitrace.cpp     |   38 ++++++++++++++++++++++++++++++--------
 gui/apitrace.h       |    5 ++++-
 gui/main.cpp         |    4 ++--
 gui/mainwindow.cpp   |    8 ++++----
 gui/mainwindow.h     |    2 +-
 gui/retracer.cpp     |    7 ++++---
 gui/retracer.h       |    3 ++-
 9 files changed, 59 insertions(+), 22 deletions(-)

diff --git a/common/image.hpp b/common/image.hpp
index e930512..939a6e1 100644
--- a/common/image.hpp
+++ b/common/image.hpp
@@ -109,7 +109,7 @@ Image *
 readPNG(const char *filename);
 
 const char *
-readPNMHeader(const char *buffer, size_t size, unsigned *channels, unsigned *width, unsigned *height);
+readPNMHeader(const char *buffer, size_t size, unsigned *channels, unsigned *width, unsigned *height, int *commentNumber);
 
 } /* namespace image */
 
diff --git a/common/image_pnm.cpp b/common/image_pnm.cpp
index f9cd05d..9b4c614 100644
--- a/common/image_pnm.cpp
+++ b/common/image_pnm.cpp
@@ -110,7 +110,7 @@ Image::writePNM(std::ostream &os, const char *comment) const {
 }
 
 const char *
-readPNMHeader(const char *buffer, size_t bufferSize, unsigned *channels, unsigned *width, unsigned *height)
+readPNMHeader(const char *buffer, size_t bufferSize, unsigned *channels, unsigned *width, unsigned *height, int *commentNumber)
 {
     *channels = 0;
     *width = 0;
@@ -135,6 +135,16 @@ readPNMHeader(const char *buffer, size_t bufferSize, unsigned *channels, unsigne
 
     // skip over optional comment
     if (*currentBuffer == '#') {
+        // advance past '#'
+        currentBuffer += 1;
+        bufferSize += 1;
+
+        // actually try to read a number
+        if (commentNumber != NULL) {
+            *commentNumber = -1; // initialize it to something sensible
+            sscanf(currentBuffer, "%d", commentNumber);
+        }
+
         // advance past comment line
         nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
         bufferSize -= nextBuffer - currentBuffer;
diff --git a/gui/apitrace.cpp b/gui/apitrace.cpp
index 0a2965e..699d30c 100644
--- a/gui/apitrace.cpp
+++ b/gui/apitrace.cpp
@@ -481,19 +481,41 @@ bool ApiTrace::isFrameLoading(ApiTraceFrame *frame) const
     return m_loadingFrames.contains(frame);
 }
 
-void ApiTrace::bindThumbnailsToFrames(const QList<QImage> &thumbnails)
+void ApiTrace::bindThumbnails(const ImageHash &thumbnails)
 {
-    QList<ApiTraceFrame *> frames = m_frames;
+    QHashIterator<int, QImage> i(thumbnails);
 
-    QList<QImage>::const_iterator thumbnail = thumbnails.begin();
+    while (i.hasNext()) {
+        i.next();
 
-    foreach (ApiTraceFrame *frame, frames) {
-        if (thumbnail != thumbnails.end()) {
-            frame->setThumbnail(*thumbnail);
+        if (!m_thumbnails.contains(i.key())) {
+            int callIndex = i.key();
+            const QImage &thumbnail = i.value();
 
-            ++thumbnail;
+            m_thumbnails.insert(callIndex, thumbnail);
 
-            emit changed(frame);
+            // find the frame associated with the call index
+            int frameIndex = 0;
+            while (frameAt(frameIndex)->lastCallIndex() < callIndex) {
+                ++frameIndex;
+            }
+
+            ApiTraceFrame *frame = frameAt(frameIndex);
+
+            // if the call was actually for a frame, ...
+            if (callIndex == frame->lastCallIndex()) {
+                frame->setThumbnail(thumbnail);
+
+                emit changed(frame);
+            } else {
+                QVector<ApiTraceCall*> calls = frame->calls();
+                int firstIndex = calls.at(0)->index();
+                ApiTraceCall *call = calls.at(callIndex - firstIndex);
+
+                call->setThumbnail(thumbnail);
+
+                emit changed(call);
+            }
         }
     }
 }
diff --git a/gui/apitrace.h b/gui/apitrace.h
index a01e761..6ccdd60 100644
--- a/gui/apitrace.h
+++ b/gui/apitrace.h
@@ -13,6 +13,7 @@ class SaverThread;
 class QThread;
 
 typedef void (*ThumbnailCallback)(void *object, int thumbnailIdx);
+typedef QHash<int, QImage> ImageHash;
 
 class ApiTrace : public QObject
 {
@@ -104,7 +105,7 @@ public slots:
     void findCallIndex(int index);
     void setCallError(const ApiTraceError &error);
 
-    void bindThumbnailsToFrames(const QList<QImage> &thumbnails);
+    void bindThumbnails(const ImageHash &thumbnails);
 
 signals:
     void loadTrace(const QString &name);
@@ -172,6 +173,8 @@ private:
     QSet<ApiTraceFrame*> m_loadingFrames;
 
     QSet<int> m_missingThumbnails;
+
+    ImageHash m_thumbnails;
 };
 
 #endif
diff --git a/gui/main.cpp b/gui/main.cpp
index 18e07f1..4a79f75 100644
--- a/gui/main.cpp
+++ b/gui/main.cpp
@@ -13,7 +13,7 @@ Q_DECLARE_METATYPE(QVector<ApiTraceCall*>);
 Q_DECLARE_METATYPE(Qt::CaseSensitivity);
 Q_DECLARE_METATYPE(ApiTrace::SearchResult);
 Q_DECLARE_METATYPE(ApiTrace::SearchRequest);
-Q_DECLARE_METATYPE(QList<QImage>);
+Q_DECLARE_METATYPE(ImageHash);
 
 static void usage(void)
 {
@@ -30,7 +30,7 @@ int main(int argc, char **argv)
     qRegisterMetaType<Qt::CaseSensitivity>();
     qRegisterMetaType<ApiTrace::SearchResult>();
     qRegisterMetaType<ApiTrace::SearchRequest>();
-    qRegisterMetaType<QList<QImage> >();
+    qRegisterMetaType<ImageHash>();
     QStringList args = app.arguments();
 
     int i = 1;
diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp
index 9eaa8b0..ae838b9 100644
--- a/gui/mainwindow.cpp
+++ b/gui/mainwindow.cpp
@@ -793,8 +793,8 @@ void MainWindow::initConnections()
             this, SLOT(replayError(const QString&)));
     connect(m_retracer, SIGNAL(foundState(ApiTraceState*)),
             this, SLOT(replayStateFound(ApiTraceState*)));
-    connect(m_retracer, SIGNAL(foundThumbnails(const QList<QImage>&)),
-            this, SLOT(replayThumbnailsFound(const QList<QImage>&)));
+    connect(m_retracer, SIGNAL(foundThumbnails(const ImageHash&)),
+            this, SLOT(replayThumbnailsFound(const ImageHash&)));
     connect(m_retracer, SIGNAL(retraceErrors(const QList<ApiTraceError>&)),
             this, SLOT(slotRetraceErrors(const QList<ApiTraceError>&)));
 
@@ -901,10 +901,10 @@ void MainWindow::replayStateFound(ApiTraceState *state)
     m_nonDefaultsLookupEvent = 0;
 }
 
-void MainWindow::replayThumbnailsFound(const QList<QImage> &thumbnails)
+void MainWindow::replayThumbnailsFound(const ImageHash &thumbnails)
 {
     m_ui.callView->setUniformRowHeights(false);
-    m_trace->bindThumbnailsToFrames(thumbnails);
+    m_trace->bindThumbnails(thumbnails);
 }
 
 void MainWindow::slotGoTo()
diff --git a/gui/mainwindow.h b/gui/mainwindow.h
index 021bf10..b0e6f11 100644
--- a/gui/mainwindow.h
+++ b/gui/mainwindow.h
@@ -51,7 +51,7 @@ private slots:
     void replayStop();
     void replayFinished(const QString &message);
     void replayStateFound(ApiTraceState *state);
-    void replayThumbnailsFound(const QList<QImage> &thumbnails);
+    void replayThumbnailsFound(const ImageHash &thumbnails);
     void replayError(const QString &msg);
     void startedLoadingTrace();
     void loadProgess(int percent);
diff --git a/gui/retracer.cpp b/gui/retracer.cpp
index 0c6de6e..aecd2f1 100644
--- a/gui/retracer.cpp
+++ b/gui/retracer.cpp
@@ -301,7 +301,7 @@ void Retracer::run()
      * Process standard output
      */
 
-    QList<QImage> thumbnails;
+    ImageHash thumbnails;
     QVariantMap parsedJson;
 
     process.setReadChannel(QProcess::StandardOutput);
@@ -357,7 +357,8 @@ void Retracer::run()
                     headerSize += headerRead;
                 }
 
-                const char *headerEnd = image::readPNMHeader(header, headerSize, &channels, &width, &height);
+                int callIdx = -1;
+                const char *headerEnd = image::readPNMHeader(header, headerSize, &channels, &width, &height, &callIdx);
 
                 // if invalid PNM header was encountered, ...
                 if (header == headerEnd) {
@@ -377,7 +378,7 @@ void Retracer::run()
                 }
 
                 QImage thumb = thumbnail(snapshot);
-                thumbnails.append(thumb);
+                thumbnails.insert(callIdx, thumb);
             }
 
             Q_ASSERT(process.state() != QProcess::Running);
diff --git a/gui/retracer.h b/gui/retracer.h
index 57abdc8..ff4efaf 100644
--- a/gui/retracer.h
+++ b/gui/retracer.h
@@ -2,6 +2,7 @@
 #define RETRACER_H
 
 #include "trace_api.hpp"
+#include "apitrace.h"
 #include "apitracecall.h"
 
 #include <QThread>
@@ -41,7 +42,7 @@ public:
 signals:
     void finished(const QString &output);
     void foundState(ApiTraceState *state);
-    void foundThumbnails(const QList<QImage> &thumbnails);
+    void foundThumbnails(const ImageHash &thumbnails);
     void error(const QString &msg);
     void retraceErrors(const QList<ApiTraceError> &errors);
 
-- 
1.7.9.1



More information about the apitrace mailing list