X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=gui%2Fapitracecall.cpp;h=c3f883147fe9f743a8135e08421229e3d93ef301;hb=6dce37c812e3fd86171934b72ad8286a3302a571;hp=39e4f5515dd8b725dc76dfa5678cbadfe2085eb6;hpb=c6247ddb0c7d2e26302727069703217d6107546e;p=apitrace diff --git a/gui/apitracecall.cpp b/gui/apitracecall.cpp index 39e4f55..c3f8831 100644 --- a/gui/apitracecall.cpp +++ b/gui/apitracecall.cpp @@ -4,9 +4,45 @@ #include "trace_model.hpp" #include +#include #include #define QT_USE_FAST_OPERATOR_PLUS #include +#include + +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" + "}\n" + ".arg-name {\n" + " border: 1px solid rgb(238,206,0);\n" + " border-radius: 4px;\n" + " background: yellow;\n" + " padding: 2px;\n" + " box-shadow: 0px 1px 3px dimgrey;\n" + " -webkit-transition: background 1s linear;\n" + "}\n" + ".arg-name:hover {\n" + " background: white;\n" + "}\n" + ".arg-value {\n" + " color: #0000ff;\n" + "}\n" + ".error {\n" + " border: 1px solid rgb(255,0,0);\n" + " margin: 10px;\n" + " padding: 1;\n" + " border-radius: 4px;\n" + // also looks great but qtwebkit doesn't support it + //" background: #6fb2e5;\n" + //" box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n" + //" -o-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n" + //" -webkit-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n" + //" -moz-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n" + "}\n"; ApiPointer::ApiPointer(unsigned long long val) : m_value(val) @@ -21,7 +57,59 @@ QString ApiPointer::toString() const return QLatin1String("NULL"); } -QString apiVariantToString(const QVariant &variant) +// Qt::convertFromPlainText doesn't do precisely what we want +static QString +plainTextToHTML(const QString & plain, bool multiLine) +{ + 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("
\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("<"); + } else if (plain[i] == QLatin1Char('>')) { + rich += QLatin1String(">"); + } else if (plain[i] == QLatin1Char('&')) { + rich += QLatin1String("&"); + } else { + rich += plain[i]; + } + ++col; + } + } + + if (quote) { + return QLatin1Literal("\"") + rich + QLatin1Literal("\""); + } + + return rich; +} + +QString apiVariantToString(const QVariant &variant, bool multiLine) { if (variant.userType() == QVariant::Double) { return QString::number(variant.toFloat()); @@ -36,6 +124,10 @@ QString apiVariantToString(const QVariant &variant) } } + if (variant.userType() == QVariant::String) { + return plainTextToHTML(variant.toString(), multiLine); + } + if (variant.userType() < QVariant::UserType) { return variant.toString(); } @@ -72,13 +164,13 @@ void ApiBitmask::init(const Trace::Bitmask *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) { + assert(it->value); QPair 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); } @@ -138,7 +230,7 @@ void ApiStruct::init(const Trace::Struct *s) return; m_sig.name = QString::fromStdString(s->sig->name); - for (unsigned i = 0; i < s->members.size(); ++i) { + for (unsigned i = 0; i < s->sig->num_members; ++i) { VariantVisitor vis; m_sig.memberNames.append( QString::fromStdString(s->sig->member_names[i])); @@ -149,7 +241,7 @@ void ApiStruct::init(const Trace::Struct *s) void VariantVisitor::visit(Trace::Null *) { - m_variant = QVariant(QLatin1String("NULL")); + m_variant = QVariant::fromValue(ApiPointer(0)); } void VariantVisitor::visit(Trace::Bool *node) @@ -179,13 +271,10 @@ void VariantVisitor::visit(Trace::String *node) void VariantVisitor::visit(Trace::Enum *e) { - VariantVisitor vis; - e->sig->second->visit(vis); - - QVariant val = vis.variant(); + QVariant val = QVariant(e->sig->value); m_variant = QVariant::fromValue( - ApiEnum(QString::fromStdString(e->sig->first), val)); + ApiEnum(QString::fromStdString(e->sig->name), val)); } void VariantVisitor::visit(Trace::Bitmask *bitmask) @@ -205,6 +294,14 @@ void VariantVisitor::visit(Trace::Array *array) void VariantVisitor::visit(Trace::Blob *blob) { + //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); } @@ -257,11 +354,13 @@ QStaticText ApiTraceCall::staticText() const if (m_staticText && !m_staticText->text().isEmpty()) return *m_staticText; + QVariantList argValues = arguments(); + QString richText = QString::fromLatin1( "%1(").arg(m_name); for (int i = 0; i < m_argNames.count(); ++i) { richText += QLatin1String(""); - QString argText = apiVariantToString(m_argValues[i]); + QString argText = apiVariantToString(argValues[i]); //if arguments are really long (e.g. shader text), cut them // and elide it @@ -291,6 +390,8 @@ QStaticText ApiTraceCall::staticText() const if (!m_staticText) m_staticText = new QStaticText(richText); + else + m_staticText->setText(richText); QTextOption opt; opt.setWrapMode(QTextOption::NoWrap); m_staticText->setTextOption(opt); @@ -304,25 +405,31 @@ QString ApiTraceCall::toHtml() const if (!m_richText.isEmpty()) return m_richText; + m_richText = QLatin1String("
"); + if (m_helpUrl.isEmpty()) { - m_richText = QString::fromLatin1( - "%1) %2(") - .arg(m_index) - .arg(m_name); + m_richText += QString::fromLatin1( + "%1) %2(") + .arg(m_index) + .arg(m_name); } else { - m_richText = QString::fromLatin1( - "%1) %3(") + m_richText += QString::fromLatin1( + "%1) %3(") .arg(m_index) .arg(m_helpUrl.toString()) .arg(m_name); } + QVariantList argValues = arguments(); for (int i = 0; i < m_argNames.count(); ++i) { - m_richText += m_argNames[i] + - QLatin1Literal(" = ") + - QLatin1Literal("") + - apiVariantToString(m_argValues[i]) + - QLatin1Literal(""); + m_richText += + QLatin1String("") + + m_argNames[i] + + QLatin1String("") + + QLatin1Literal(" = ") + + QLatin1Literal("") + + apiVariantToString(argValues[i], true) + + QLatin1Literal(""); if (i < m_argNames.count() - 1) m_richText += QLatin1String(", "); } @@ -332,10 +439,28 @@ QString ApiTraceCall::toHtml() const m_richText += QLatin1String(" = ") + QLatin1String("") + - apiVariantToString(m_returnValue) + + apiVariantToString(m_returnValue, true) + QLatin1String(""); } + m_richText += QLatin1String("
"); + + if (hasError()) { + QString errorStr = + QString::fromLatin1( + "
%1
") + .arg(m_error); + m_richText += errorStr; + } + + m_richText = + QString::fromLatin1( + "%2") + .arg(styleSheet) + .arg(m_richText); m_richText.squeeze(); + + //qDebug()<text().isEmpty()) return *m_staticText; - QString richText = - QString::fromLatin1("Frame %1").arg(number); + QString richText; + + //mark the frame if it uploads more than a meg a frame + if (m_binaryDataSize > (1024*1024)) { + richText = + QObject::tr( + "" + "Frame %1" + "" + "    (%2MB)") + .arg(number) + .arg(double(m_binaryDataSize / (1024.*1024.)), 0, 'g', 2); + } else { + richText = + QObject::tr( + "Frame %1") + .arg(number); + } if (!m_staticText) m_staticText = new QStaticText(richText); @@ -392,12 +530,13 @@ int ApiTraceCall::numChildren() const int ApiTraceFrame::numChildren() const { - return calls.count(); + return m_calls.count(); } ApiTraceFrame::ApiTraceFrame() : ApiTraceEvent(ApiTraceEvent::Frame), - m_parentTrace(0) + m_parentTrace(0), + m_binaryDataSize(0) { } @@ -468,44 +607,34 @@ ApiTraceState::ApiTraceState(const QVariantMap &parsedJson) 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); - } - } - } + m_uniforms = parsedJson[QLatin1String("uniforms")].toMap(); + + 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(); + 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.setLabel(itr.key()); + tex.contentsFromBase64(dataArray); + + m_textures.append(tex); } QVariantMap fbos = @@ -534,27 +663,32 @@ ApiTraceState::ApiTraceState(const QVariantMap &parsedJson) } } -QVariantMap ApiTraceState::parameters() const +const QVariantMap & ApiTraceState::parameters() const { return m_parameters; } -QMap ApiTraceState::shaderSources() const +const QMap & ApiTraceState::shaderSources() const { return m_shaderSources; } +const QVariantMap & ApiTraceState::uniforms() const +{ + return m_uniforms; +} + bool ApiTraceState::isEmpty() const { return m_parameters.isEmpty(); } -QList ApiTraceState::textures() const +const QList & ApiTraceState::textures() const { return m_textures; } -QList ApiTraceState::framebuffers() const +const QList & ApiTraceState::framebuffers() const { return m_framebuffers; } @@ -606,7 +740,7 @@ ApiTraceCall::ApiTraceCall(const Trace::Call *call) m_index = call->no; QString argumentsText; - for (int i = 0; i < call->sig->arg_names.size(); ++i) { + for (int i = 0; i < call->sig->num_args; ++i) { m_argNames += QString::fromStdString(call->sig->arg_names[i]); } @@ -619,19 +753,10 @@ ApiTraceCall::ApiTraceCall(const Trace::Call *call) VariantVisitor argVisitor; call->args[i]->visit(argVisitor); m_argValues += argVisitor.variant(); - - //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 should - // use something like Boost's shared_ptr or - // Qt's QSharedPointer to handle it. - Trace::Blob *b = dynamic_cast(call->args[i]); - if (b && b->blob()) { - char *buf = (char*)b->blob(); - delete [] buf; + if (m_argValues[i].type() == QVariant::ByteArray) { + m_hasBinaryData = true; + m_binaryDataIndex = i; } - } } @@ -677,10 +802,14 @@ QVariantList ApiTraceCall::originalValues() const void ApiTraceCall::setEditedValues(const QVariantList &lst) { - ApiTrace *trace = 0; - if (m_parentFrame) - trace = m_parentFrame->parentTrace(); + ApiTrace *trace = parentTrace(); + m_editedValues = lst; + //lets regenerate data + m_richText = QString(); + m_filterText = QString(); + delete m_staticText; + m_staticText = 0; if (trace) { if (!lst.isEmpty()) { @@ -747,3 +876,66 @@ unsigned long long ApiPointer::value() const return m_value; } +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) { + ApiTrace *trace = parentTrace(); + m_error = msg; + m_richText = QString(); + if (trace) + trace->callError(this); + } +} + +ApiTrace * ApiTraceCall::parentTrace() const +{ + if (m_parentFrame) + return m_parentFrame->parentTrace(); + return NULL; +} + +void ApiTraceFrame::addCall(ApiTraceCall *call) +{ + m_calls.append(call); + if (call->hasBinaryData()) { + QByteArray data = + call->arguments()[call->binaryDataIndex()].toByteArray(); + m_binaryDataSize += data.size(); + } +} + +QList ApiTraceFrame::calls() const +{ + return m_calls; +} + +ApiTraceCall * ApiTraceFrame::call(int idx) const +{ + return m_calls.value(idx); +} + +int ApiTraceFrame::callIndex(ApiTraceCall *call) const +{ + return m_calls.indexOf(call); +} + +bool ApiTraceFrame::isEmpty() const +{ + return m_calls.isEmpty(); +} + +int ApiTraceFrame::binaryDataSize() const +{ + return m_binaryDataSize; +} +