]> git.cworth.org Git - apitrace/blobdiff - gui/apitracecall.cpp
Use skiplist-based FastCallSet within trace::CallSet
[apitrace] / gui / apitracecall.cpp
index 2d41e25a4425f972b56d6f0daafabd8c694d5863..33774861013cc99165c323800a09f6cbef0fc1ac 100644 (file)
@@ -1,19 +1,22 @@
 #include "apitracecall.h"
 
 #include "apitrace.h"
+#include "traceloader.h"
 #include "trace_model.hpp"
 
 #include <QDebug>
+#include <QLocale>
 #include <QObject>
 #define QT_USE_FAST_OPERATOR_PLUS
 #include <QStringBuilder>
+#include <QTextDocument>
 
 const char * const styleSheet =
     ".call {\n"
     "    font-weight:bold;\n"
     // text shadow looks great but doesn't work well in qtwebkit 4.7
     "    /*text-shadow: 0px 2px 3px #555;*/\n"
-    "    font-size: 1.2em;\n"
+    "    font-size: 1.1em;\n"
     "}\n"
     ".arg-name {\n"
     "    border: 1px solid rgb(238,206,0);\n"
@@ -42,24 +45,72 @@ const char * const styleSheet =
     //"    -moz-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n"
     "}\n";
 
-ApiPointer::ApiPointer(unsigned long long val)
-    : m_value(val)
-{
-}
 
-QString ApiPointer::toString() const
+// Qt::convertFromPlainText doesn't do precisely what we want
+static QString
+plainTextToHTML(const QString & plain, bool multiLine)
 {
-    if (m_value)
-        return QString("0x%1").arg(m_value, 0, 16);
-    else
-        return QLatin1String("NULL");
+    int col = 0;
+    bool quote = false;
+    QString rich;
+    for (int i = 0; i < plain.length(); ++i) {
+        if (plain[i] == QLatin1Char('\n')){
+            if (multiLine) {
+                rich += QLatin1String("<br>\n");
+            } else {
+                rich += QLatin1String("\\n");
+            }
+            col = 0;
+            quote = true;
+        } else {
+            if (plain[i] == QLatin1Char('\t')){
+                if (multiLine) {
+                    rich += QChar(0x00a0U);
+                    ++col;
+                    while (col % 8) {
+                        rich += QChar(0x00a0U);
+                        ++col;
+                    }
+                } else {
+                    rich += QLatin1String("\\t");
+                }
+                quote = true;
+            } else if (plain[i].isSpace()) {
+                rich += QChar(0x00a0U);
+                quote = true;
+            } else if (plain[i] == QLatin1Char('<')) {
+                rich += QLatin1String("&lt;");
+            } else if (plain[i] == QLatin1Char('>')) {
+                rich += QLatin1String("&gt;");
+            } else if (plain[i] == QLatin1Char('&')) {
+                rich += QLatin1String("&amp;");
+            } else {
+                rich += plain[i];
+            }
+            ++col;
+        }
+    }
+
+    if (quote) {
+        return QLatin1Literal("\"") + rich + QLatin1Literal("\"");
+    }
+
+    return rich;
 }
 
-QString apiVariantToString(const QVariant &variant)
+QString
+apiVariantToString(const QVariant &variant, bool multiLine)
 {
-    if (variant.userType() == QVariant::Double) {
+    if (variant.isNull()) {
+        return QLatin1String("?");
+    }
+
+    if (variant.userType() == QMetaType::Float) {
         return QString::number(variant.toFloat());
     }
+    if (variant.userType() == QVariant::Double) {
+        return QString::number(variant.toDouble());
+    }
     if (variant.userType() == QVariant::ByteArray) {
         if (variant.toByteArray().size() < 1024) {
             int bytes = variant.toByteArray().size();
@@ -70,6 +121,10 @@ QString apiVariantToString(const QVariant &variant)
         }
     }
 
+    if (variant.userType() == QVariant::String) {
+        return plainTextToHTML(variant.toString(), multiLine);
+    }
+
     if (variant.userType() < QVariant::UserType) {
         return variant.toString();
     }
@@ -81,10 +136,10 @@ QString apiVariantToString(const QVariant &variant)
         return variant.value<ApiBitmask>().toString();
     }
     if (variant.canConvert<ApiStruct>()) {
-        return variant.value<ApiStruct>().toString();
+        return variant.value<ApiStruct>().toString(multiLine);
     }
     if (variant.canConvert<ApiArray>()) {
-        return variant.value<ApiArray>().toString();
+        return variant.value<ApiArray>().toString(multiLine);
     }
     if (variant.canConvert<ApiEnum>()) {
         return variant.value<ApiEnum>().toString();
@@ -93,26 +148,204 @@ QString apiVariantToString(const QVariant &variant)
     return QString();
 }
 
-ApiBitmask::ApiBitmask(const Trace::Bitmask *bitmask)
+
+void VariantVisitor::visit(trace::Null *)
+{
+    m_variant = QVariant::fromValue(ApiPointer(0));
+}
+
+void VariantVisitor::visit(trace::Bool *node)
+{
+    m_variant = QVariant(node->value);
+}
+
+void VariantVisitor::visit(trace::SInt *node)
+{
+    m_variant = QVariant(node->value);
+}
+
+void VariantVisitor::visit(trace::UInt *node)
+{
+    m_variant = QVariant(node->value);
+}
+
+void VariantVisitor::visit(trace::Float *node)
+{
+    m_variant = QVariant(node->value);
+}
+
+void VariantVisitor::visit(trace::Double *node)
+{
+    m_variant = QVariant(node->value);
+}
+
+void VariantVisitor::visit(trace::String *node)
+{
+    m_variant = QVariant(QString::fromStdString(node->value));
+}
+
+void VariantVisitor::visit(trace::Enum *e)
+{
+    ApiTraceEnumSignature *sig = 0;
+
+    if (m_loader) {
+        sig = m_loader->enumSignature(e->sig->id);
+    }
+    if (!sig) {
+        sig = new ApiTraceEnumSignature(e->sig);
+        if (m_loader) {
+            m_loader->addEnumSignature(e->sig->id, sig);
+        }
+    }
+
+    m_variant = QVariant::fromValue(ApiEnum(sig, e->value));
+}
+
+void VariantVisitor::visit(trace::Bitmask *bitmask)
+{
+    m_variant = QVariant::fromValue(ApiBitmask(bitmask));
+}
+
+void VariantVisitor::visit(trace::Struct *str)
+{
+    m_variant = QVariant::fromValue(ApiStruct(str));
+}
+
+void VariantVisitor::visit(trace::Array *array)
+{
+    m_variant = QVariant::fromValue(ApiArray(array));
+}
+
+void VariantVisitor::visit(trace::Blob *blob)
+{
+    QByteArray barray = QByteArray(blob->buf, blob->size);
+    m_variant = QVariant(barray);
+}
+
+void VariantVisitor::visit(trace::Pointer *ptr)
+{
+    m_variant = QVariant::fromValue(ApiPointer(ptr->value));
+}
+
+void VariantVisitor::visit(trace::Repr *repr)
+{
+    /* TODO: Preserve both the human and machine value */
+    repr->humanValue->visit(*this);
+}
+
+ApiTraceEnumSignature::ApiTraceEnumSignature(const trace::EnumSig *sig)
+{
+    for (const trace::EnumValue *it = sig->values;
+         it != sig->values + sig->num_values; ++it) {
+        QPair<QString, signed long long> pair;
+
+        pair.first = QString::fromStdString(it->name);
+        pair.second = it->value;
+
+        m_names.append(pair);
+    }
+}
+
+QString ApiTraceEnumSignature::name(signed long long value) const
+{
+    for (ValueList::const_iterator it = m_names.begin();
+         it != m_names.end(); ++it) {
+        if (value == it->second) {
+            return it->first;
+        }
+    }
+    return QString::fromLatin1("%1").arg(value);
+}
+
+ApiEnum::ApiEnum(ApiTraceEnumSignature *sig, signed long long value)
+    : m_sig(sig), m_value(value)
+{
+}
+
+QString ApiEnum::toString() const
+{
+    if (m_sig) {
+        return m_sig->name(m_value);
+    }
+    Q_ASSERT(!"should never happen");
+    return QString();
+}
+
+QVariant ApiEnum::value() const
+{
+    if (m_sig) {
+        return QVariant::fromValue(m_value);
+    }
+    Q_ASSERT(!"should never happen");
+    return QVariant();
+}
+
+QString ApiEnum::name() const
+{
+    if (m_sig) {
+        return m_sig->name(m_value);
+    }
+    Q_ASSERT(!"should never happen");
+    return QString();
+}
+
+unsigned long long ApiBitmask::value() const
+{
+    return m_value;
+}
+
+ApiBitmask::Signature ApiBitmask::signature() const
+{
+    return m_sig;
+}
+
+ApiStruct::Signature ApiStruct::signature() const
+{
+    return m_sig;
+}
+
+QList<QVariant> ApiStruct::values() const
+{
+    return m_members;
+}
+
+ApiPointer::ApiPointer(unsigned long long val)
+    : m_value(val)
+{
+}
+
+
+unsigned long long ApiPointer::value() const
+{
+    return m_value;
+}
+
+QString ApiPointer::toString() const
+{
+    if (m_value)
+        return QString("0x%1").arg(m_value, 0, 16);
+    else
+        return QLatin1String("NULL");
+}
+
+ApiBitmask::ApiBitmask(const trace::Bitmask *bitmask)
     : m_value(0)
 {
     init(bitmask);
 }
 
-
-void ApiBitmask::init(const Trace::Bitmask *bitmask)
+void ApiBitmask::init(const trace::Bitmask *bitmask)
 {
     if (!bitmask)
         return;
 
     m_value = bitmask->value;
-    for (Trace::Bitmask::Signature::const_iterator it = bitmask->sig->begin();
-         it != bitmask->sig->end(); ++it) {
-        assert(it->second);
+    for (const trace::BitmaskFlag *it = bitmask->sig->flags;
+         it != bitmask->sig->flags + bitmask->sig->num_flags; ++it) {
         QPair<QString, unsigned long long> pair;
 
-        pair.first = QString::fromStdString(it->first);
-        pair.second = it->second;
+        pair.first = QString::fromStdString(it->name);
+        pair.second = it->value;
 
         m_sig.append(pair);
     }
@@ -123,10 +356,10 @@ QString ApiBitmask::toString() const
     QString str;
     unsigned long long value = m_value;
     bool first = true;
-    for (Signature::const_iterator it = m_sig.begin();
-         value != 0 && it != m_sig.end(); ++it) {
-        Q_ASSERT(it->second);
-        if ((value & it->second) == it->second) {
+    for (Signature::const_iterator it = m_sig.begin(); it != m_sig.end(); ++it) {
+        Q_ASSERT(it->second || first);
+        if ((it->second && (value & it->second) == it->second) ||
+            (!it->second && value == 0)) {
             if (!first) {
                 str += QLatin1String(" | ");
             }
@@ -134,6 +367,9 @@ QString ApiBitmask::toString() const
             value &= ~it->second;
             first = false;
         }
+        if (value == 0) {
+            break;
+        }
     }
     if (value || first) {
         if (!first) {
@@ -144,12 +380,12 @@ QString ApiBitmask::toString() const
     return str;
 }
 
-ApiStruct::ApiStruct(const Trace::Struct *s)
+ApiStruct::ApiStruct(const trace::Struct *s)
 {
     init(s);
 }
 
-QString ApiStruct::toString() const
+QString ApiStruct::toString(bool multiLine) const
 {
     QString str;
 
@@ -157,7 +393,7 @@ QString ApiStruct::toString() const
     for (unsigned i = 0; i < m_members.count(); ++i) {
         str += m_sig.memberNames[i] %
                QLatin1Literal(" = ") %
-               apiVariantToString(m_members[i]);
+               apiVariantToString(m_members[i], multiLine);
         if (i < m_members.count() - 1)
             str += QLatin1String(", ");
     }
@@ -166,14 +402,14 @@ QString ApiStruct::toString() const
     return str;
 }
 
-void ApiStruct::init(const Trace::Struct *s)
+void ApiStruct::init(const trace::Struct *s)
 {
     if (!s)
         return;
 
     m_sig.name = QString::fromStdString(s->sig->name);
-    for (unsigned i = 0; i < s->members.size(); ++i) {
-        VariantVisitor vis;
+    for (unsigned i = 0; i < s->sig->num_members; ++i) {
+        VariantVisitor vis(0);
         m_sig.memberNames.append(
             QString::fromStdString(s->sig->member_names[i]));
         s->members[i]->visit(vis);
@@ -181,117 +417,407 @@ void ApiStruct::init(const Trace::Struct *s)
     }
 }
 
-void VariantVisitor::visit(Trace::Null *)
+ApiArray::ApiArray(const trace::Array *arr)
 {
-    m_variant = QVariant::fromValue(ApiPointer(0));
+    init(arr);
 }
 
-void VariantVisitor::visit(Trace::Bool *node)
+ApiArray::ApiArray(const QVector<QVariant> &vals)
+    : m_array(vals)
 {
-    m_variant = QVariant(node->value);
 }
 
-void VariantVisitor::visit(Trace::SInt *node)
+QVector<QVariant> ApiArray::values() const
 {
-    m_variant = QVariant(node->value);
+    return m_array;
 }
 
-void VariantVisitor::visit(Trace::UInt *node)
+QString ApiArray::toString(bool multiLine) const
 {
-    m_variant = QVariant(node->value);
+    QString str;
+    str += QLatin1String("[");
+    for(int i = 0; i < m_array.count(); ++i) {
+        const QVariant &var = m_array[i];
+        str += apiVariantToString(var, multiLine);
+        if (i < m_array.count() - 1)
+            str += QLatin1String(", ");
+    }
+    str += QLatin1String("]");
+
+    return str;
 }
 
-void VariantVisitor::visit(Trace::Float *node)
+void ApiArray::init(const trace::Array *arr)
 {
-    m_variant = QVariant(node->value);
+    if (!arr)
+        return;
+
+    m_array.reserve(arr->values.size());
+    for (int i = 0; i < arr->values.size(); ++i) {
+        VariantVisitor vis(0);
+        arr->values[i]->visit(vis);
+
+        m_array.append(vis.variant());
+    }
+    m_array.squeeze();
 }
 
-void VariantVisitor::visit(Trace::String *node)
+ApiTraceState::ApiTraceState()
 {
-    m_variant = QVariant(QString::fromStdString(node->value));
 }
 
-void VariantVisitor::visit(Trace::Enum *e)
+ApiTraceState::ApiTraceState(const QVariantMap &parsedJson)
 {
-    VariantVisitor vis;
-    e->sig->second->visit(vis);
+    m_parameters = parsedJson[QLatin1String("parameters")].toMap();
+    QVariantMap attachedShaders =
+        parsedJson[QLatin1String("shaders")].toMap();
+    QVariantMap::const_iterator itr;
+
+
+    for (itr = attachedShaders.constBegin(); itr != attachedShaders.constEnd();
+         ++itr) {
+        QString type = itr.key();
+        QString source = itr.value().toString();
+        m_shaderSources[type] = source;
+    }
+
+    m_uniforms = parsedJson[QLatin1String("uniforms")].toMap();
 
-    QVariant val = vis.variant();
+    QVariantMap textures =
+        parsedJson[QLatin1String("textures")].toMap();
+    for (itr = textures.constBegin(); itr != textures.constEnd(); ++itr) {
+        QVariantMap image = itr.value().toMap();
+        QSize size(image[QLatin1String("__width__")].toInt(),
+                   image[QLatin1String("__height__")].toInt());
+        QString cls = image[QLatin1String("__class__")].toString();
+        int depth =
+            image[QLatin1String("__depth__")].toInt();
+        QString formatName =
+            image[QLatin1String("__format__")].toString();
+
+        QByteArray dataArray =
+            image[QLatin1String("__data__")].toByteArray();
+
+        ApiTexture tex;
+        tex.setSize(size);
+        tex.setDepth(depth);
+        tex.setFormatName(formatName);
+        tex.setLabel(itr.key());
+        tex.contentsFromBase64(dataArray);
+
+        m_textures.append(tex);
+    }
+
+    QVariantMap fbos =
+        parsedJson[QLatin1String("framebuffer")].toMap();
+    for (itr = fbos.constBegin(); itr != fbos.constEnd(); ++itr) {
+        QVariantMap buffer = itr.value().toMap();
+        QSize size(buffer[QLatin1String("__width__")].toInt(),
+                   buffer[QLatin1String("__height__")].toInt());
+        QString cls = buffer[QLatin1String("__class__")].toString();
+        int depth = buffer[QLatin1String("__depth__")].toInt();
+        QString formatName = buffer[QLatin1String("__format__")].toString();
 
-    m_variant = QVariant::fromValue(
-        ApiEnum(QString::fromStdString(e->sig->first), val));
+        QByteArray dataArray =
+            buffer[QLatin1String("__data__")].toByteArray();
+
+        ApiFramebuffer fbo;
+        fbo.setSize(size);
+        fbo.setDepth(depth);
+        fbo.setFormatName(formatName);
+        fbo.setType(itr.key());
+        fbo.contentsFromBase64(dataArray);
+        m_framebuffers.append(fbo);
+    }
 }
 
-void VariantVisitor::visit(Trace::Bitmask *bitmask)
+const QVariantMap & ApiTraceState::parameters() const
 {
-    m_variant = QVariant::fromValue(ApiBitmask(bitmask));
+    return m_parameters;
 }
 
-void VariantVisitor::visit(Trace::Struct *str)
+const QMap<QString, QString> & ApiTraceState::shaderSources() const
 {
-    m_variant = QVariant::fromValue(ApiStruct(str));
+    return m_shaderSources;
 }
 
-void VariantVisitor::visit(Trace::Array *array)
+const QVariantMap & ApiTraceState::uniforms() const
 {
-    m_variant = QVariant::fromValue(ApiArray(array));
+    return m_uniforms;
 }
 
-void VariantVisitor::visit(Trace::Blob *blob)
+bool ApiTraceState::isEmpty() const
 {
-    //XXX
-    //FIXME: this is a nasty hack. Trace::Blob's can't
-    //   delete the contents in the destructor because
-    //   the data is being used by other calls. We piggy back
-    //   on that assumption and don't deep copy the data. If
-    //   Blob's will start deleting the data we will need to
-    //   start deep copying it or switch to using something like
-    //   Boost's shared_ptr or Qt's QSharedPointer to handle it
-    QByteArray barray = QByteArray::fromRawData(blob->buf, blob->size);
-    m_variant = QVariant(barray);
+    return m_parameters.isEmpty() &&
+           m_shaderSources.isEmpty() &&
+           m_textures.isEmpty() &&
+           m_framebuffers.isEmpty();
 }
 
-void VariantVisitor::visit(Trace::Pointer *ptr)
+const QList<ApiTexture> & ApiTraceState::textures() const
 {
-    m_variant = QVariant::fromValue(ApiPointer(ptr->value));
+    return m_textures;
 }
 
-ApiArray::ApiArray(const Trace::Array *arr)
+const QList<ApiFramebuffer> & ApiTraceState::framebuffers() const
 {
-    init(arr);
+    return m_framebuffers;
 }
 
-ApiArray::ApiArray(const QList<QVariant> &vals)
-    : m_array(vals)
+ApiFramebuffer ApiTraceState::colorBuffer() const
 {
+    foreach (ApiFramebuffer fbo, m_framebuffers) {
+        if (fbo.type() == QLatin1String("GL_BACK")) {
+            return fbo;
+        }
+    }
+    foreach (ApiFramebuffer fbo, m_framebuffers) {
+        if (fbo.type() == QLatin1String("GL_FRONT")) {
+            return fbo;
+        }
+    }
+    return ApiFramebuffer();
 }
 
-QString ApiArray::toString() const
+
+ApiTraceCallSignature::ApiTraceCallSignature(const QString &name,
+                                             const QStringList &argNames)
+    : m_name(name),
+      m_argNames(argNames)
 {
-    QString str;
-    str += QLatin1String("[");
-    for(int i = 0; i < m_array.count(); ++i) {
-        const QVariant &var = m_array[i];
-        str += apiVariantToString(var);
-        if (i < m_array.count() - 1)
-            str += QLatin1String(", ");
+}
+
+ApiTraceCallSignature::~ApiTraceCallSignature()
+{
+}
+
+QUrl ApiTraceCallSignature::helpUrl() const
+{
+    return m_helpUrl;
+}
+
+void ApiTraceCallSignature::setHelpUrl(const QUrl &url)
+{
+    m_helpUrl = url;
+}
+
+ApiTraceEvent::ApiTraceEvent()
+    : m_type(ApiTraceEvent::None),
+      m_hasBinaryData(false),
+      m_binaryDataIndex(0),
+      m_state(0),
+      m_staticText(0)
+{
+}
+
+ApiTraceEvent::ApiTraceEvent(Type t)
+    : m_type(t),
+      m_hasBinaryData(false),
+      m_binaryDataIndex(0),
+      m_state(0),
+      m_staticText(0)
+{
+}
+
+ApiTraceEvent::~ApiTraceEvent()
+{
+    delete m_state;
+    delete m_staticText;
+}
+
+QVariantMap ApiTraceEvent::stateParameters() const
+{
+    if (m_state) {
+        return m_state->parameters();
+    } else {
+        return QVariantMap();
     }
-    str += QLatin1String("]");
+}
 
-    return str;
+ApiTraceState *ApiTraceEvent::state() const
+{
+    return m_state;
 }
 
-void ApiArray::init(const Trace::Array *arr)
+void ApiTraceEvent::setState(ApiTraceState *state)
 {
-    if (!arr)
-        return;
+    m_state = state;
+}
 
-    for (int i = 0; i < arr->values.size(); ++i) {
-        VariantVisitor vis;
-        arr->values[i]->visit(vis);
+ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame,
+                           TraceLoader *loader,
+                           const trace::Call *call)
+    : ApiTraceEvent(ApiTraceEvent::Call),
+      m_parentFrame(parentFrame)
+{
+    m_index = call->no;
 
-        m_array.append(vis.variant());
+    m_signature = loader->signature(call->sig->id);
+
+    if (!m_signature) {
+        QString name = QString::fromStdString(call->sig->name);
+        QStringList argNames;
+        argNames.reserve(call->sig->num_args);
+        for (int i = 0; i < call->sig->num_args; ++i) {
+            argNames += QString::fromStdString(call->sig->arg_names[i]);
+        }
+        m_signature = new ApiTraceCallSignature(name, argNames);
+        loader->addSignature(call->sig->id, m_signature);
+    }
+    if (call->ret) {
+        VariantVisitor retVisitor(loader);
+        call->ret->visit(retVisitor);
+        m_returnValue = retVisitor.variant();
+    }
+    m_argValues.reserve(call->args.size());
+    for (int i = 0; i < call->args.size(); ++i) {
+        if (call->args[i].value) {
+            VariantVisitor argVisitor(loader);
+            call->args[i].value->visit(argVisitor);
+            m_argValues.append(argVisitor.variant());
+            if (m_argValues[i].type() == QVariant::ByteArray) {
+                m_hasBinaryData = true;
+                m_binaryDataIndex = i;
+            }
+        } else {
+            m_argValues.append(QVariant());
+        }
     }
+    m_argValues.squeeze();
+    m_flags = call->flags;
+}
+
+ApiTraceCall::~ApiTraceCall()
+{
+}
+
+
+bool ApiTraceCall::hasError() const
+{
+    return !m_error.isEmpty();
+}
+
+QString ApiTraceCall::error() const
+{
+    return m_error;
+}
+
+void ApiTraceCall::setError(const QString &msg)
+{
+    if (m_error != msg) {
+        m_error = msg;
+        m_richText = QString();
+    }
+}
+
+ApiTrace * ApiTraceCall::parentTrace() const
+{
+    if (m_parentFrame)
+        return m_parentFrame->parentTrace();
+    return NULL;
+}
+
+QVector<QVariant> ApiTraceCall::originalValues() const
+{
+    return m_argValues;
+}
+
+void ApiTraceCall::setEditedValues(const QVector<QVariant> &lst)
+{
+    ApiTrace *trace = parentTrace();
+
+    m_editedValues = lst;
+    //lets regenerate data
+    m_richText = QString();
+    m_searchText = QString();
+    delete m_staticText;
+    m_staticText = 0;
+
+    if (trace) {
+        if (!lst.isEmpty()) {
+            trace->callEdited(this);
+        } else {
+            trace->callReverted(this);
+        }
+    }
+}
+
+QVector<QVariant> ApiTraceCall::editedValues() const
+{
+    return m_editedValues;
+}
+
+bool ApiTraceCall::edited() const
+{
+    return !m_editedValues.isEmpty();
+}
+
+void ApiTraceCall::revert()
+{
+    setEditedValues(QVector<QVariant>());
+}
+
+void ApiTraceCall::setHelpUrl(const QUrl &url)
+{
+    m_signature->setHelpUrl(url);
+}
+
+void ApiTraceCall::setParentFrame(ApiTraceFrame *frame)
+{
+    m_parentFrame = frame;
+}
+
+ApiTraceFrame * ApiTraceCall::parentFrame()const
+{
+    return m_parentFrame;
+}
+
+int ApiTraceCall::index() const
+{
+    return m_index;
+}
+
+QString ApiTraceCall::name() const
+{
+    return m_signature->name();
+}
+
+QStringList ApiTraceCall::argNames() const
+{
+    return m_signature->argNames();
+}
+
+QVector<QVariant> ApiTraceCall::arguments() const
+{
+    if (m_editedValues.isEmpty())
+        return m_argValues;
+    else
+        return m_editedValues;
+}
+
+QVariant ApiTraceCall::returnValue() const
+{
+    return m_returnValue;
+}
+
+trace::CallFlags ApiTraceCall::flags() const
+{
+    return m_flags;
+}
+
+QUrl ApiTraceCall::helpUrl() const
+{
+    return m_signature->helpUrl();
+}
+
+bool ApiTraceCall::hasBinaryData() const
+{
+    return m_hasBinaryData;
+}
+
+int ApiTraceCall::binaryDataIndex() const
+{
+    return m_binaryDataIndex;
 }
 
 QStaticText ApiTraceCall::staticText() const
@@ -299,11 +825,13 @@ QStaticText ApiTraceCall::staticText() const
     if (m_staticText && !m_staticText->text().isEmpty())
         return *m_staticText;
 
-    QVariantList argValues = arguments();
+    QVector<QVariant> argValues = arguments();
 
     QString richText = QString::fromLatin1(
-        "<span style=\"font-weight:bold\">%1</span>(").arg(m_name);
-    for (int i = 0; i < m_argNames.count(); ++i) {
+        "<span style=\"font-weight:bold\">%1</span>(").arg(
+            m_signature->name());
+    QStringList argNames = m_signature->argNames();
+    for (int i = 0; i < argNames.count(); ++i) {
         richText += QLatin1String("<span style=\"color:#0000ff\">");
         QString argText = apiVariantToString(argValues[i]);
 
@@ -314,14 +842,14 @@ QStaticText ApiTraceCall::staticText() const
             shortened[argText.length() - 5] = '.';
             shortened[argText.length() - 4] = '.';
             shortened[argText.length() - 3] = '.';
-            shortened[argText.length() - 2] = argText[argText.length() - 2];
-            shortened[argText.length() - 1] = argText[argText.length() - 1];
+            shortened[argText.length() - 2] = argText.at(argText.length() - 2);
+            shortened[argText.length() - 1] = argText.at(argText.length() - 1);
             richText += shortened;
         } else {
             richText += argText;
         }
         richText += QLatin1String("</span>");
-        if (i < m_argNames.count() - 1)
+        if (i < argNames.count() - 1)
             richText += QLatin1String(", ");
     }
     richText += QLatin1String(")");
@@ -350,32 +878,44 @@ QString ApiTraceCall::toHtml() const
     if (!m_richText.isEmpty())
         return m_richText;
 
-    m_richText = QLatin1String("<div class=\"call\">");
+    m_richText += QLatin1String("<div class=\"call\">");
 
-    if (m_helpUrl.isEmpty()) {
+
+    m_richText +=
+        QString::fromLatin1("%1) ")
+        .arg(m_index);
+    QString parentTip;
+    if (m_parentFrame) {
+        parentTip =
+            QString::fromLatin1("Frame %1")
+            .arg(m_parentFrame->number);
+    }
+    QUrl helpUrl = m_signature->helpUrl();
+    if (helpUrl.isEmpty()) {
         m_richText += QString::fromLatin1(
-            "%1) <span class=\"callName\">%2</span>(")
-                      .arg(m_index)
-                      .arg(m_name);
+            "<span class=\"callName\" title=\"%1\">%2</span>(")
+                      .arg(parentTip)
+                      .arg(m_signature->name());
     } else {
         m_richText += QString::fromLatin1(
-            "%1) <span class=\"callName\"><a href=\"%2\">%3</a></span>(")
-                      .arg(m_index)
-                      .arg(m_helpUrl.toString())
-                      .arg(m_name);
+         "<span class=\"callName\" title=\"%1\"><a href=\"%2\">%3</a></span>(")
+                      .arg(parentTip)
+                      .arg(helpUrl.toString())
+                      .arg(m_signature->name());
     }
 
-    QVariantList argValues = arguments();
-    for (int i = 0; i < m_argNames.count(); ++i) {
+    QVector<QVariant> argValues = arguments();
+    QStringList argNames = m_signature->argNames();
+    for (int i = 0; i < argNames.count(); ++i) {
         m_richText +=
             QLatin1String("<span class=\"arg-name\">") +
-            m_argNames[i] +
+            argNames[i] +
             QLatin1String("</span>") +
             QLatin1Literal(" = ") +
             QLatin1Literal("<span class=\"arg-value\">") +
-            apiVariantToString(argValues[i]) +
+            apiVariantToString(argValues[i], true) +
             QLatin1Literal("</span>");
-        if (i < m_argNames.count() - 1)
+        if (i < argNames.count() - 1)
             m_richText += QLatin1String(", ");
     }
     m_richText += QLatin1String(")");
@@ -384,7 +924,7 @@ QString ApiTraceCall::toHtml() const
         m_richText +=
             QLatin1String(" = ") +
             QLatin1String("<span style=\"color:#0000ff\">") +
-            apiVariantToString(m_returnValue) +
+            apiVariantToString(m_returnValue, true) +
             QLatin1String("</span>");
     }
     m_richText += QLatin1String("</div>");
@@ -409,51 +949,29 @@ QString ApiTraceCall::toHtml() const
     return m_richText;
 }
 
-QString ApiTraceCall::filterText() const
+QString ApiTraceCall::searchText() const
 {
-    if (!m_filterText.isEmpty())
-        return m_filterText;
+    if (!m_searchText.isEmpty())
+        return m_searchText;
 
-    QVariantList argValues = arguments();
-    m_filterText = m_name + QLatin1Literal("(");
-    for (int i = 0; i < m_argNames.count(); ++i) {
-        m_filterText += m_argNames[i] +
+    QVector<QVariant> argValues = arguments();
+    m_searchText = m_signature->name() + QLatin1Literal("(");
+    QStringList argNames = m_signature->argNames();
+    for (int i = 0; i < argNames.count(); ++i) {
+        m_searchText += argNames[i] +
                         QLatin1Literal(" = ") +
                         apiVariantToString(argValues[i]);
-        if (argValues[i].type() == QVariant::ByteArray) {
-            m_hasBinaryData = true;
-            m_binaryDataIndex = i;
-        }
-        if (i < m_argNames.count() - 1)
-            m_filterText += QLatin1String(", ");
+        if (i < argNames.count() - 1)
+            m_searchText += QLatin1String(", ");
     }
-    m_filterText += QLatin1String(")");
+    m_searchText += QLatin1String(")");
 
     if (m_returnValue.isValid()) {
-        m_filterText += QLatin1Literal(" = ") +
+        m_searchText += QLatin1Literal(" = ") +
                         apiVariantToString(m_returnValue);
     }
-    m_filterText.squeeze();
-    return m_filterText;
-}
-
-QStaticText ApiTraceFrame::staticText() const
-{
-    if (m_staticText && !m_staticText->text().isEmpty())
-        return *m_staticText;
-
-    QString richText =
-        QString::fromLatin1("<span style=\"font-weight:bold\">Frame %1</span>").arg(number);
-
-    if (!m_staticText)
-        m_staticText = new QStaticText(richText);
-
-    QTextOption opt;
-    opt.setWrapMode(QTextOption::NoWrap);
-    m_staticText->setTextOption(opt);
-    m_staticText->prepare();
-
-    return *m_staticText;
+    m_searchText.squeeze();
+    return m_searchText;
 }
 
 int ApiTraceCall::numChildren() const
@@ -461,379 +979,224 @@ int ApiTraceCall::numChildren() const
     return 0;
 }
 
-int ApiTraceFrame::numChildren() const
-{
-    return calls.count();
-}
-
-ApiTraceFrame::ApiTraceFrame()
-    : ApiTraceEvent(ApiTraceEvent::Frame),
-      m_parentTrace(0)
-{
-}
-
-ApiTraceCall::ApiTraceCall()
-    : ApiTraceEvent(ApiTraceEvent::Call),
-      m_hasBinaryData(false),
-      m_binaryDataIndex(0)
-{
-}
-
-ApiTraceEvent::ApiTraceEvent()
-    : m_type(ApiTraceEvent::None),
-      m_staticText(0)
-{
-}
-
-ApiTraceEvent::ApiTraceEvent(Type t)
-    : m_type(t),
-      m_staticText(0)
-{
-}
-
-ApiTraceCall::~ApiTraceCall()
-{
-}
-
-QVariantMap ApiTraceEvent::stateParameters() const
-{
-    return m_state.parameters();
-}
-
-ApiTraceState ApiTraceEvent::state() const
-{
-    return m_state;
-}
-
-void ApiTraceEvent::setState(const ApiTraceState &state)
+bool ApiTraceCall::contains(const QString &str,
+                            Qt::CaseSensitivity sensitivity) const
 {
-    m_state = state;
+    QString txt = searchText();
+    return txt.contains(str, sensitivity);
 }
 
-bool ApiTraceCall::hasBinaryData() const
-{
-    return m_hasBinaryData;
-}
 
-int ApiTraceCall::binaryDataIndex() const
+ApiTraceFrame::ApiTraceFrame(ApiTrace *parentTrace)
+    : ApiTraceEvent(ApiTraceEvent::Frame),
+      m_parentTrace(parentTrace),
+      m_binaryDataSize(0),
+      m_loaded(false),
+      m_callsToLoad(0),
+      m_lastCallIndex(0)
 {
-    return m_binaryDataIndex;
 }
 
-ApiTraceState::ApiTraceState()
+ApiTraceFrame::~ApiTraceFrame()
 {
+    qDeleteAll(m_calls);
 }
 
-ApiTraceState::ApiTraceState(const QVariantMap &parsedJson)
+QStaticText ApiTraceFrame::staticText() const
 {
-    m_parameters = parsedJson[QLatin1String("parameters")].toMap();
-    QVariantMap attachedShaders =
-        parsedJson[QLatin1String("shaders")].toMap();
-    QVariantMap::const_iterator itr;
-
-
-    for (itr = attachedShaders.constBegin(); itr != attachedShaders.constEnd();
-         ++itr) {
-        QString type = itr.key();
-        QString source = itr.value().toString();
-        m_shaderSources[type] = source;
-    }
-
-    QVariantList textureUnits =
-        parsedJson[QLatin1String("textures")].toList();
-    for (int i = 0; i < textureUnits.count(); ++i) {
-        QVariantMap unit = textureUnits[i].toMap();
-        for (itr = unit.constBegin(); itr != unit.constEnd(); ++itr) {
-            QVariantMap target = itr.value().toMap();
-            if (target.count()) {
-                QVariantList levels = target[QLatin1String("levels")].toList();
-                for (int j = 0; j < levels.count(); ++j) {
-                    QVariantMap level = levels[j].toMap();
-                    QVariantMap image = level[QLatin1String("image")].toMap();
-                    QSize size(image[QLatin1String("__width__")].toInt(),
-                               image[QLatin1String("__height__")].toInt());
-                    QString cls = image[QLatin1String("__class__")].toString();
-                    QString type = image[QLatin1String("__type__")].toString();
-                    bool normalized =
-                        image[QLatin1String("__normalized__")].toBool();
-                    int numChannels =
-                        image[QLatin1String("__channels__")].toInt();
-
-                    Q_ASSERT(type == QLatin1String("uint8"));
-                    Q_ASSERT(normalized == true);
-
-                    QByteArray dataArray =
-                        image[QLatin1String("__data__")].toByteArray();
-
-                    ApiTexture tex;
-                    tex.setSize(size);
-                    tex.setNumChannels(numChannels);
-                    tex.setLevel(j);
-                    tex.setUnit(i);
-                    tex.setTarget(itr.key());
-                    tex.contentsFromBase64(dataArray);
-
-                    m_textures.append(tex);
-                }
-            }
-        }
-    }
-
-    QVariantMap fbos =
-        parsedJson[QLatin1String("framebuffer")].toMap();
-    for (itr = fbos.constBegin(); itr != fbos.constEnd(); ++itr) {
-        QVariantMap buffer = itr.value().toMap();
-        QSize size(buffer[QLatin1String("__width__")].toInt(),
-                   buffer[QLatin1String("__height__")].toInt());
-        QString cls = buffer[QLatin1String("__class__")].toString();
-        QString type = buffer[QLatin1String("__type__")].toString();
-        bool normalized = buffer[QLatin1String("__normalized__")].toBool();
-        int numChannels = buffer[QLatin1String("__channels__")].toInt();
-
-        Q_ASSERT(type == QLatin1String("uint8"));
-        Q_ASSERT(normalized == true);
-
-        QByteArray dataArray =
-            buffer[QLatin1String("__data__")].toByteArray();
+    if (m_staticText && !m_staticText->text().isEmpty())
+        return *m_staticText;
 
-        ApiFramebuffer fbo;
-        fbo.setSize(size);
-        fbo.setNumChannels(numChannels);
-        fbo.setType(itr.key());
-        fbo.contentsFromBase64(dataArray);
-        m_framebuffers.append(fbo);
+    QString richText = QObject::tr(
+                "<span style=\"font-weight:bold\">Frame %1</span>"
+                "&nbsp;&nbsp;&nbsp;"
+                "<span style=\"font-style:italic;font-size:small;font-weight:lighter;\"> "
+                "(%2 calls)</span>")
+            .arg(number)
+            .arg(m_loaded ? m_calls.count() : m_callsToLoad);
+
+    //mark the frame if it uploads more than a meg a frame
+    if (m_binaryDataSize > (1024*1024)) {
+        richText =
+            QObject::tr(
+                "%1"
+                "<span style=\"font-style:italic;\">"
+                "&nbsp;&nbsp;&nbsp;&nbsp;(%2MB)</span>")
+            .arg(richText)
+            .arg(double(m_binaryDataSize / (1024.*1024.)), 0, 'g', 2);
     }
-}
-
-QVariantMap ApiTraceState::parameters() const
-{
-    return m_parameters;
-}
 
-QMap<QString, QString> ApiTraceState::shaderSources() const
-{
-    return m_shaderSources;
-}
+    if (!m_staticText)
+        m_staticText = new QStaticText(richText);
 
-bool ApiTraceState::isEmpty() const
-{
-    return m_parameters.isEmpty();
-}
+    QTextOption opt;
+    opt.setWrapMode(QTextOption::NoWrap);
+    m_staticText->setTextOption(opt);
+    m_staticText->prepare();
 
-QList<ApiTexture> ApiTraceState::textures() const
-{
-    return m_textures;
+    return *m_staticText;
 }
 
-QList<ApiFramebuffer> ApiTraceState::framebuffers() const
+int ApiTraceFrame::numChildren() const
 {
-    return m_framebuffers;
+    return m_calls.count();
 }
 
-QList<QVariant> ApiArray::values() const
+ApiTrace * ApiTraceFrame::parentTrace() const
 {
-    return m_array;
+    return m_parentTrace;
 }
 
-int ApiTraceCall::index() const
+void ApiTraceFrame::addCall(ApiTraceCall *call)
 {
-    return m_index;
+    m_calls.append(call);
+    if (call->hasBinaryData()) {
+        QByteArray data =
+            call->arguments()[call->binaryDataIndex()].toByteArray();
+        m_binaryDataSize += data.size();
+    }
 }
 
-QString ApiTraceCall::name() const
+QVector<ApiTraceCall*> ApiTraceFrame::calls() const
 {
-    return m_name;
+    return m_calls;
 }
 
-QStringList ApiTraceCall::argNames() const
+ApiTraceCall * ApiTraceFrame::call(int idx) const
 {
-    return m_argNames;
+    return m_calls.value(idx);
 }
 
-QVariantList ApiTraceCall::arguments() const
-{
-    if (m_editedValues.isEmpty())
-        return m_argValues;
-    else
-        return m_editedValues;
-}
 
-QVariant ApiTraceCall::returnValue() const
+ApiTraceCall * ApiTraceFrame::callWithIndex(int index) const
 {
-    return m_returnValue;
+    QVector<ApiTraceCall*>::const_iterator itr;
+    for (itr = m_calls.constBegin(); itr != m_calls.constEnd(); ++itr) {
+        if ((*itr)->index() == index) {
+            return *itr;
+        }
+    }
+    return 0;
 }
 
-QUrl ApiTraceCall::helpUrl() const
+int ApiTraceFrame::callIndex(ApiTraceCall *call) const
 {
-    return m_helpUrl;
+    return m_calls.indexOf(call);
 }
 
-ApiTraceCall::ApiTraceCall(const Trace::Call *call)
-    : ApiTraceEvent(ApiTraceEvent::Call),
-      m_hasBinaryData(false),
-      m_binaryDataIndex(0)
+bool ApiTraceFrame::isEmpty() const
 {
-    m_name = QString::fromStdString(call->sig->name);
-    m_index = call->no;
-
-    QString argumentsText;
-    for (int i = 0; i < call->sig->arg_names.size(); ++i) {
-        m_argNames +=
-            QString::fromStdString(call->sig->arg_names[i]);
-    }
-    if (call->ret) {
-        VariantVisitor retVisitor;
-        call->ret->visit(retVisitor);
-        m_returnValue = retVisitor.variant();
-    }
-    for (int i = 0; i < call->args.size(); ++i) {
-        VariantVisitor argVisitor;
-        call->args[i]->visit(argVisitor);
-        m_argValues += argVisitor.variant();
+    if (m_loaded) {
+        return m_calls.isEmpty();
+    } else {
+        return m_callsToLoad == 0;
     }
 }
 
-void ApiTraceCall::setHelpUrl(const QUrl &url)
+int ApiTraceFrame::binaryDataSize() const
 {
-    m_helpUrl = url;
+    return m_binaryDataSize;
 }
 
-void ApiTraceCall::setParentFrame(ApiTraceFrame *frame)
+void ApiTraceFrame::setCalls(const QVector<ApiTraceCall*> &calls,
+                             quint64 binaryDataSize)
 {
-    m_parentFrame = frame;
+    m_calls = calls;
+    m_binaryDataSize = binaryDataSize;
+    m_loaded = true;
+    delete m_staticText;
+    m_staticText = 0;
 }
 
-ApiTraceFrame * ApiTraceCall::parentFrame()const
+bool ApiTraceFrame::isLoaded() const
 {
-    return m_parentFrame;
+    return m_loaded;
 }
 
-ApiTraceEvent::~ApiTraceEvent()
+void ApiTraceFrame::setLoaded(bool l)
 {
-    delete m_staticText;
+    m_loaded = l;
 }
 
-void ApiTraceCall::revert()
+void ApiTraceFrame::setNumChildren(int num)
 {
-    setEditedValues(QVariantList());
+    m_callsToLoad = num;
 }
 
-ApiTrace * ApiTraceFrame::parentTrace() const
+void ApiTraceFrame::setParentTrace(ApiTrace *parent)
 {
-    return m_parentTrace;
+    m_parentTrace = parent;
 }
 
-void ApiTraceFrame::setParentTrace(ApiTrace *trace)
+int ApiTraceFrame::numChildrenToLoad() const
 {
-    m_parentTrace = trace;
+    return m_callsToLoad;
 }
 
-QVariantList ApiTraceCall::originalValues() const
+ApiTraceCall *
+ApiTraceFrame::findNextCall(ApiTraceCall *from,
+                            const QString &str,
+                            Qt::CaseSensitivity sensitivity) const
 {
-    return m_argValues;
-}
+    Q_ASSERT(m_loaded);
 
-void ApiTraceCall::setEditedValues(const QVariantList &lst)
-{
-    ApiTrace *trace = parentTrace();
+    int callIndex = 0;
 
-    m_editedValues = lst;
-    //lets regenerate data
-    m_richText = QString();
-    m_filterText = QString();
-    delete m_staticText;
-    m_staticText = 0;
+    if (from) {
+        callIndex = m_calls.indexOf(from) + 1;
+    }
 
-    if (trace) {
-        if (!lst.isEmpty()) {
-            trace->callEdited(this);
-        } else {
-            trace->callReverted(this);
+    for (int i = callIndex; i < m_calls.count(); ++i) {
+        ApiTraceCall *call = m_calls[i];
+        if (call->contains(str, sensitivity)) {
+            return call;
         }
     }
+    return 0;
 }
 
-QVariantList ApiTraceCall::editedValues() const
-{
-    return m_editedValues;
-}
-
-bool ApiTraceCall::edited() const
-{
-    return !m_editedValues.isEmpty();
-}
-
-ApiEnum::ApiEnum(const QString &name, const QVariant &val)
-    : m_name(name),
-      m_value(val)
-{
-}
-
-QString ApiEnum::toString() const
-{
-    return m_name;
-}
-
-QVariant ApiEnum::value() const
-{
-    return m_value;
-}
-
-QString ApiEnum::name() const
-{
-    return m_name;
-}
-
-unsigned long long ApiBitmask::value() const
-{
-    return m_value;
-}
-
-ApiBitmask::Signature ApiBitmask::signature() const
+ApiTraceCall *
+ApiTraceFrame::findPrevCall(ApiTraceCall *from,
+                            const QString &str,
+                            Qt::CaseSensitivity sensitivity) const
 {
-    return m_sig;
-}
+    Q_ASSERT(m_loaded);
 
-ApiStruct::Signature ApiStruct::signature() const
-{
-    return m_sig;
-}
+    int callIndex = m_calls.count() - 1;
 
-QList<QVariant> ApiStruct::values() const
-{
-    return m_members;
-}
+    if (from) {
+        callIndex = m_calls.indexOf(from) - 1;
+    }
 
-unsigned long long ApiPointer::value() const
-{
-    return m_value;
+    for (int i = callIndex; i >= 0; --i) {
+        ApiTraceCall *call = m_calls[i];
+        if (call->contains(str, sensitivity)) {
+            return call;
+        }
+    }
+    return 0;
 }
 
-bool ApiTraceCall::hasError() const
+void ApiTraceFrame::setLastCallIndex(unsigned index)
 {
-    return !m_error.isEmpty();
+    m_lastCallIndex = index;
 }
 
-QString ApiTraceCall::error() const
+unsigned ApiTraceFrame::lastCallIndex() const
 {
-    return m_error;
+    if (m_loaded && !m_calls.isEmpty()) {
+        return m_calls.last()->index();
+    } else {
+        return m_lastCallIndex;
+    }
 }
 
-void ApiTraceCall::setError(const QString &msg)
+void ApiTraceFrame::setThumbnail(const QImage & thumbnail)
 {
-    if (m_error != msg) {
-        ApiTrace *trace = parentTrace();
-        m_error = msg;
-        m_richText = QString();
-        if (trace)
-            trace->callError(this);
-    }
+    m_thumbnail = thumbnail;
 }
 
-ApiTrace * ApiTraceCall::parentTrace() const
+const QImage & ApiTraceFrame::thumbnail() const
 {
-    if (m_parentFrame)
-        return m_parentFrame->parentTrace();
-    return NULL;
+    return m_thumbnail;
 }
-