]> git.cworth.org Git - apitrace/blobdiff - gui/retracer.cpp
image: Support reading PFM images.
[apitrace] / gui / retracer.cpp
index d0e07ef9f4d54066e56042ed8df7ae16fd036427..b42446bdd6af2ca064f3b522466dc3b778105cc2 100644 (file)
@@ -3,7 +3,9 @@
 #include "apitracecall.h"
 #include "thumbnail.h"
 
-#include "image.hpp"
+#include "image/image.hpp"
+
+#include "trace_profiler.hpp"
 
 #include <QDebug>
 #include <QVariant>
@@ -128,23 +130,14 @@ Retracer::Retracer(QObject *parent)
     : QThread(parent),
       m_benchmarking(false),
       m_doubleBuffered(true),
+      m_singlethread(false),
       m_captureState(false),
-      m_captureCall(0)
+      m_captureCall(0),
+      m_profileGpu(false),
+      m_profileCpu(false),
+      m_profilePixels(false)
 {
     qRegisterMetaType<QList<ApiTraceError> >();
-
-#ifdef Q_OS_WIN
-    QString format = QLatin1String("%1;");
-#else
-    QString format = QLatin1String("%1:");
-#endif
-    QString buildPath = format.arg(APITRACE_BINARY_DIR);
-    m_processEnvironment = QProcessEnvironment::systemEnvironment();
-    m_processEnvironment.insert("PATH", buildPath +
-                                m_processEnvironment.value("PATH"));
-
-    qputenv("PATH",
-            m_processEnvironment.value("PATH").toLatin1());
 }
 
 QString Retracer::fileName() const
@@ -157,6 +150,16 @@ void Retracer::setFileName(const QString &name)
     m_fileName = name;
 }
 
+QString Retracer::remoteTarget() const
+{
+    return m_remoteTarget;
+}
+
+void Retracer::setRemoteTarget(const QString &host)
+{
+    m_remoteTarget = host;
+}
+
 void Retracer::setAPI(trace::API api)
 {
     m_api = api;
@@ -182,6 +185,43 @@ void Retracer::setDoubleBuffered(bool db)
     m_doubleBuffered = db;
 }
 
+bool Retracer::isSinglethread() const
+{
+    return m_singlethread;
+}
+
+void Retracer::setSinglethread(bool singlethread)
+{
+    m_singlethread = singlethread;
+}
+
+bool Retracer::isProfilingGpu() const
+{
+    return m_profileGpu;
+}
+
+bool Retracer::isProfilingCpu() const
+{
+    return m_profileCpu;
+}
+
+bool Retracer::isProfilingPixels() const
+{
+    return m_profilePixels;
+}
+
+bool Retracer::isProfiling() const
+{
+    return m_profileGpu || m_profileCpu || m_profilePixels;
+}
+
+void Retracer::setProfiling(bool gpu, bool cpu, bool pixels)
+{
+    m_profileGpu = gpu;
+    m_profileCpu = cpu;
+    m_profilePixels = pixels;
+}
+
 void Retracer::setCaptureAtCallNumber(qlonglong num)
 {
     m_captureCall = num;
@@ -212,7 +252,6 @@ void Retracer::setCaptureThumbnails(bool enable)
     m_captureThumbnails = enable;
 }
 
-
 /**
  * Starting point for the retracing thread.
  *
@@ -220,7 +259,7 @@ void Retracer::setCaptureThumbnails(bool enable)
  */
 void Retracer::run()
 {
-    QString msg;
+    QString msg = QLatin1String("Replay finished!");
 
     /*
      * Construct command line
@@ -229,19 +268,32 @@ void Retracer::run()
     QString prog;
     QStringList arguments;
 
-    if (m_api == trace::API_GL) {
+    switch (m_api) {
+    case trace::API_GL:
         prog = QLatin1String("glretrace");
-    } else if (m_api == trace::API_EGL) {
+        break;
+    case trace::API_EGL:
         prog = QLatin1String("eglretrace");
-    } else {
+        break;
+    case trace::API_DX:
+    case trace::API_D3D7:
+    case trace::API_D3D8:
+    case trace::API_D3D9:
+    case trace::API_DXGI:
+#ifdef Q_OS_WIN
+        prog = QLatin1String("d3dretrace");
+#else
+        prog = QLatin1String("wine");
+        arguments << QLatin1String("d3dretrace.exe");
+#endif
+        break;
+    default:
         emit finished(QLatin1String("Unsupported API"));
         return;
     }
 
-    if (m_doubleBuffered) {
-        arguments << QLatin1String("-db");
-    } else {
-        arguments << QLatin1String("-sb");
+    if (m_singlethread) {
+        arguments << QLatin1String("--singlethread");
     }
 
     if (m_captureState) {
@@ -250,12 +302,42 @@ void Retracer::run()
     } else if (m_captureThumbnails) {
         arguments << QLatin1String("-s"); // emit snapshots
         arguments << QLatin1String("-"); // emit to stdout
-    } else if (m_benchmarking) {
-        arguments << QLatin1String("-b");
+    } else if (isProfiling()) {
+        if (m_profileGpu) {
+            arguments << QLatin1String("--pgpu");
+        }
+
+        if (m_profileCpu) {
+            arguments << QLatin1String("--pcpu");
+        }
+
+        if (m_profilePixels) {
+            arguments << QLatin1String("--ppd");
+        }
+    } else {
+        if (m_doubleBuffered) {
+            arguments << QLatin1String("--db");
+        } else {
+            arguments << QLatin1String("--sb");
+        }
+
+        if (m_benchmarking) {
+            arguments << QLatin1String("-b");
+        }
     }
 
     arguments << m_fileName;
 
+    /*
+     * Support remote execution on a separate target.
+     */
+
+    if (m_remoteTarget.length() != 0) {
+        arguments.prepend(prog);
+        arguments.prepend(m_remoteTarget);
+        prog = QLatin1String("ssh");
+    }
+
     /*
      * Start the process.
      */
@@ -274,6 +356,7 @@ void Retracer::run()
 
     QList<QImage> thumbnails;
     QVariantMap parsedJson;
+    trace::Profile* profile = NULL;
 
     process.setReadChannel(QProcess::StandardOutput);
     if (process.waitForReadyRead(-1)) {
@@ -283,8 +366,6 @@ void Retracer::run()
             /*
              * Parse JSON from the output.
              *
-             * XXX: QJSON expects blocking IO.
-             *
              * XXX: QJSON's scanner is inneficient as it abuses single
              * character QIODevice::peek (not cheap), instead of maintaining a
              * lookahead character on its own.
@@ -292,7 +373,19 @@ void Retracer::run()
 
             bool ok = false;
             QJson::Parser jsonParser;
+
+            // Allow Nan/Infinity
+            jsonParser.allowSpecialNumbers(true);
+#if 0
             parsedJson = jsonParser.parse(&io, &ok).toMap();
+#else
+            /*
+             * XXX: QJSON expects blocking IO, and it looks like
+             * BlockingIODevice does not work reliably in all cases.
+             */
+            process.waitForFinished(-1);
+            parsedJson = jsonParser.parse(&process, &ok).toMap();
+#endif
             if (!ok) {
                 msg = QLatin1String("failed to parse JSON");
             }
@@ -302,9 +395,7 @@ void Retracer::run()
              */
 
             while (!io.atEnd()) {
-                unsigned channels = 0;
-                unsigned width = 0;
-                unsigned height = 0;
+                image::PNMInfo info;
 
                 char header[512];
                 qint64 headerSize = 0;
@@ -321,14 +412,19 @@ void Retracer::run()
                     headerSize += headerRead;
                 }
 
-                const char *headerEnd = image::readPNMHeader(header, headerSize, &channels, &width, &height);
+                const char *headerEnd = image::readPNMHeader(header, headerSize, info);
 
                 // if invalid PNM header was encountered, ...
-                if (header == headerEnd) {
+                if (headerEnd == NULL ||
+                    info.channelType != image::TYPE_UNORM8) {
                     qDebug() << "error: invalid snapshot stream encountered";
                     break;
                 }
 
+                unsigned channels = info.channels;
+                unsigned width = info.width;
+                unsigned height = info.height;
+
                 // qDebug() << "channels: " << channels << ", width: " << width << ", height: " << height";
 
                 QImage snapshot = QImage(width, height, channels == 1 ? QImage::Format_Mono : QImage::Format_RGB888);
@@ -338,6 +434,7 @@ void Retracer::run()
                     unsigned char *scanLine = snapshot.scanLine(y);
                     qint64 readBytes = io.read((char *) scanLine, rowBytes);
                     Q_ASSERT(readBytes == rowBytes);
+                    (void)readBytes;
                 }
 
                 QImage thumb = thumbnail(snapshot);
@@ -345,11 +442,26 @@ void Retracer::run()
             }
 
             Q_ASSERT(process.state() != QProcess::Running);
+        } else if (isProfiling()) {
+            profile = new trace::Profile();
+
+            while (!io.atEnd()) {
+                char line[256];
+                qint64 lineLength;
 
+                lineLength = io.readLine(line, 256);
+
+                if (lineLength == -1)
+                    break;
+
+                trace::Profiler::parseLine(line, profile);
+            }
         } else {
             QByteArray output;
             output = process.readAllStandardOutput();
-            msg = QString::fromUtf8(output);
+            if (output.length() < 80) {
+                msg = QString::fromUtf8(output);
+            }
         }
     }
 
@@ -380,6 +492,14 @@ void Retracer::run()
             error.type = regexp.cap(2);
             error.message = regexp.cap(3);
             errors.append(error);
+        } else if (!errors.isEmpty()) {
+            // Probably a multiligne message
+            ApiTraceError &previous = errors.last();
+            if (line.endsWith("\n")) {
+                line.chop(1);
+            }
+            previous.message.append('\n');
+            previous.message.append(line);
         }
     }
 
@@ -390,13 +510,16 @@ void Retracer::run()
     if (m_captureState) {
         ApiTraceState *state = new ApiTraceState(parsedJson);
         emit foundState(state);
-        msg = QLatin1String("State fetched.");
     }
 
     if (m_captureThumbnails && !thumbnails.isEmpty()) {
         emit foundThumbnails(thumbnails);
     }
 
+    if (isProfiling() && profile) {
+        emit foundProfile(profile);
+    }
+
     if (!errors.isEmpty()) {
         emit retraceErrors(errors);
     }