]> git.cworth.org Git - apitrace/blob - gui/apitracecall.cpp
Implement a bulk of trace saving.
[apitrace] / gui / apitracecall.cpp
1 #include "apitracecall.h"
2
3 #include "apitrace.h"
4 #include "trace_model.hpp"
5
6 #include <QDebug>
7 #include <QObject>
8 #define QT_USE_FAST_OPERATOR_PLUS
9 #include <QStringBuilder>
10
11 ApiPointer::ApiPointer(unsigned long long val)
12     : m_value(val)
13 {
14 }
15
16 QString ApiPointer::toString() const
17 {
18     if (m_value)
19         return QString("0x%1").arg(m_value, 0, 16);
20     else
21         return QLatin1String("NULL");
22 }
23
24 QString apiVariantToString(const QVariant &variant)
25 {
26     if (variant.userType() == QVariant::Double) {
27         return QString::number(variant.toFloat());
28     }
29     if (variant.userType() == QVariant::ByteArray) {
30         if (variant.toByteArray().size() < 1024) {
31             int bytes = variant.toByteArray().size();
32             return QObject::tr("[binary data, size = %1 bytes]").arg(bytes);
33         } else {
34             float kb = variant.toByteArray().size()/1024.;
35             return QObject::tr("[binary data, size = %1 kb]").arg(kb);
36         }
37     }
38
39     if (variant.userType() < QVariant::UserType) {
40         return variant.toString();
41     }
42
43     if (variant.canConvert<ApiPointer>()) {
44         return variant.value<ApiPointer>().toString();
45     }
46     if (variant.canConvert<ApiBitmask>()) {
47         return variant.value<ApiBitmask>().toString();
48     }
49     if (variant.canConvert<ApiStruct>()) {
50         return variant.value<ApiStruct>().toString();
51     }
52     if (variant.canConvert<ApiArray>()) {
53         return variant.value<ApiArray>().toString();
54     }
55     if (variant.canConvert<ApiEnum>()) {
56         return variant.value<ApiEnum>().toString();
57     }
58
59     return QString();
60 }
61
62 ApiBitmask::ApiBitmask(const Trace::Bitmask *bitmask)
63     : m_value(0)
64 {
65     init(bitmask);
66 }
67
68
69 void ApiBitmask::init(const Trace::Bitmask *bitmask)
70 {
71     if (!bitmask)
72         return;
73
74     m_value = bitmask->value;
75     for (Trace::Bitmask::Signature::const_iterator it = bitmask->sig->begin();
76          it != bitmask->sig->end(); ++it) {
77         assert(it->second);
78         QPair<QString, unsigned long long> pair;
79
80         pair.first = QString::fromStdString(it->first);
81         pair.second = it->second;
82
83         m_sig.append(pair);
84     }
85 }
86
87 QString ApiBitmask::toString() const
88 {
89     QString str;
90     unsigned long long value = m_value;
91     bool first = true;
92     for (Signature::const_iterator it = m_sig.begin();
93          value != 0 && it != m_sig.end(); ++it) {
94         Q_ASSERT(it->second);
95         if ((value & it->second) == it->second) {
96             if (!first) {
97                 str += QLatin1String(" | ");
98             }
99             str += it->first;
100             value &= ~it->second;
101             first = false;
102         }
103     }
104     if (value || first) {
105         if (!first) {
106             str += QLatin1String(" | ");
107         }
108         str += QString::fromLatin1("0x%1").arg(value, 0, 16);
109     }
110     return str;
111 }
112
113 ApiStruct::ApiStruct(const Trace::Struct *s)
114 {
115     init(s);
116 }
117
118 QString ApiStruct::toString() const
119 {
120     QString str;
121
122     str += QLatin1String("{");
123     for (unsigned i = 0; i < m_members.count(); ++i) {
124         str += m_sig.memberNames[i] %
125                QLatin1Literal(" = ") %
126                apiVariantToString(m_members[i]);
127         if (i < m_members.count() - 1)
128             str += QLatin1String(", ");
129     }
130     str += QLatin1String("}");
131
132     return str;
133 }
134
135 void ApiStruct::init(const Trace::Struct *s)
136 {
137     if (!s)
138         return;
139
140     m_sig.name = QString::fromStdString(s->sig->name);
141     for (unsigned i = 0; i < s->members.size(); ++i) {
142         VariantVisitor vis;
143         m_sig.memberNames.append(
144             QString::fromStdString(s->sig->member_names[i]));
145         s->members[i]->visit(vis);
146         m_members.append(vis.variant());
147     }
148 }
149
150 void VariantVisitor::visit(Trace::Null *)
151 {
152     m_variant = QVariant(QLatin1String("NULL"));
153 }
154
155 void VariantVisitor::visit(Trace::Bool *node)
156 {
157     m_variant = QVariant(node->value);
158 }
159
160 void VariantVisitor::visit(Trace::SInt *node)
161 {
162     m_variant = QVariant(node->value);
163 }
164
165 void VariantVisitor::visit(Trace::UInt *node)
166 {
167     m_variant = QVariant(node->value);
168 }
169
170 void VariantVisitor::visit(Trace::Float *node)
171 {
172     m_variant = QVariant(node->value);
173 }
174
175 void VariantVisitor::visit(Trace::String *node)
176 {
177     m_variant = QVariant(QString::fromStdString(node->value));
178 }
179
180 void VariantVisitor::visit(Trace::Enum *e)
181 {
182     VariantVisitor vis;
183     e->sig->second->visit(vis);
184
185     QVariant val = vis.variant();
186
187     m_variant = QVariant::fromValue(
188         ApiEnum(QString::fromStdString(e->sig->first), val));
189 }
190
191 void VariantVisitor::visit(Trace::Bitmask *bitmask)
192 {
193     m_variant = QVariant::fromValue(ApiBitmask(bitmask));
194 }
195
196 void VariantVisitor::visit(Trace::Struct *str)
197 {
198     m_variant = QVariant::fromValue(ApiStruct(str));
199 }
200
201 void VariantVisitor::visit(Trace::Array *array)
202 {
203     m_variant = QVariant::fromValue(ApiArray(array));
204 }
205
206 void VariantVisitor::visit(Trace::Blob *blob)
207 {
208     QByteArray barray = QByteArray::fromRawData(blob->buf, blob->size);
209     m_variant = QVariant(barray);
210 }
211
212 void VariantVisitor::visit(Trace::Pointer *ptr)
213 {
214     m_variant = QVariant::fromValue(ApiPointer(ptr->value));
215 }
216
217 ApiArray::ApiArray(const Trace::Array *arr)
218 {
219     init(arr);
220 }
221
222 ApiArray::ApiArray(const QList<QVariant> &vals)
223     : m_array(vals)
224 {
225 }
226
227 QString ApiArray::toString() const
228 {
229     QString str;
230     str += QLatin1String("[");
231     for(int i = 0; i < m_array.count(); ++i) {
232         const QVariant &var = m_array[i];
233         str += apiVariantToString(var);
234         if (i < m_array.count() - 1)
235             str += QLatin1String(", ");
236     }
237     str += QLatin1String("]");
238
239     return str;
240 }
241
242 void ApiArray::init(const Trace::Array *arr)
243 {
244     if (!arr)
245         return;
246
247     for (int i = 0; i < arr->values.size(); ++i) {
248         VariantVisitor vis;
249         arr->values[i]->visit(vis);
250
251         m_array.append(vis.variant());
252     }
253 }
254
255 QStaticText ApiTraceCall::staticText() const
256 {
257     if (m_staticText && !m_staticText->text().isEmpty())
258         return *m_staticText;
259
260     QString richText = QString::fromLatin1(
261         "<span style=\"font-weight:bold\">%1</span>(").arg(m_name);
262     for (int i = 0; i < m_argNames.count(); ++i) {
263         richText += QLatin1String("<span style=\"color:#0000ff\">");
264         QString argText = apiVariantToString(m_argValues[i]);
265
266         //if arguments are really long (e.g. shader text), cut them
267         // and elide it
268         if (argText.length() > 40) {
269             QString shortened = argText.mid(0, 40);
270             shortened[argText.length() - 5] = '.';
271             shortened[argText.length() - 4] = '.';
272             shortened[argText.length() - 3] = '.';
273             shortened[argText.length() - 2] = argText[argText.length() - 2];
274             shortened[argText.length() - 1] = argText[argText.length() - 1];
275             richText += shortened;
276         } else {
277             richText += argText;
278         }
279         richText += QLatin1String("</span>");
280         if (i < m_argNames.count() - 1)
281             richText += QLatin1String(", ");
282     }
283     richText += QLatin1String(")");
284     if (m_returnValue.isValid()) {
285         richText +=
286             QLatin1Literal(" = ") %
287             QLatin1Literal("<span style=\"color:#0000ff\">") %
288             apiVariantToString(m_returnValue) %
289             QLatin1Literal("</span>");
290     }
291
292     if (!m_staticText)
293         m_staticText = new QStaticText(richText);
294     QTextOption opt;
295     opt.setWrapMode(QTextOption::NoWrap);
296     m_staticText->setTextOption(opt);
297     m_staticText->prepare();
298
299     return *m_staticText;
300 }
301
302 QString ApiTraceCall::toHtml() const
303 {
304     if (!m_richText.isEmpty())
305         return m_richText;
306
307     if (m_helpUrl.isEmpty()) {
308         m_richText = QString::fromLatin1(
309             "%1) <span style=\"font-weight:bold\">%2</span>(")
310                      .arg(m_index)
311                      .arg(m_name);
312     } else {
313         m_richText = QString::fromLatin1(
314             "%1) <span style=\"font-weight:bold\"><a href=\"%2\">%3</a></span>(")
315                       .arg(m_index)
316                       .arg(m_helpUrl.toString())
317                       .arg(m_name);
318     }
319
320     for (int i = 0; i < m_argNames.count(); ++i) {
321         m_richText += m_argNames[i] +
322                       QLatin1Literal(" = ") +
323                       QLatin1Literal("<span style=\"color:#0000ff\">") +
324                       apiVariantToString(m_argValues[i]) +
325                       QLatin1Literal("</span>");
326         if (i < m_argNames.count() - 1)
327             m_richText += QLatin1String(", ");
328     }
329     m_richText += QLatin1String(")");
330
331     if (m_returnValue.isValid()) {
332         m_richText +=
333             QLatin1String(" = ") +
334             QLatin1String("<span style=\"color:#0000ff\">") +
335             apiVariantToString(m_returnValue) +
336             QLatin1String("</span>");
337     }
338     m_richText.squeeze();
339     return m_richText;
340 }
341
342 QString ApiTraceCall::filterText() const
343 {
344     if (!m_filterText.isEmpty())
345         return m_filterText;
346
347     m_filterText = m_name + QLatin1Literal("(");
348     for (int i = 0; i < m_argNames.count(); ++i) {
349         m_filterText += m_argNames[i] +
350                         QLatin1Literal(" = ") +
351                         apiVariantToString(m_argValues[i]);
352         if (m_argValues[i].type() == QVariant::ByteArray) {
353             m_hasBinaryData = true;
354             m_binaryDataIndex = i;
355         }
356         if (i < m_argNames.count() - 1)
357             m_filterText += QLatin1String(", ");
358     }
359     m_filterText += QLatin1String(")");
360
361     if (m_returnValue.isValid()) {
362         m_filterText += QLatin1Literal(" = ") +
363                         apiVariantToString(m_returnValue);
364     }
365     m_filterText.squeeze();
366     return m_filterText;
367 }
368
369 QStaticText ApiTraceFrame::staticText() const
370 {
371     if (m_staticText && !m_staticText->text().isEmpty())
372         return *m_staticText;
373
374     QString richText =
375         QString::fromLatin1("<span style=\"font-weight:bold\">Frame %1</span>").arg(number);
376
377     if (!m_staticText)
378         m_staticText = new QStaticText(richText);
379
380     QTextOption opt;
381     opt.setWrapMode(QTextOption::NoWrap);
382     m_staticText->setTextOption(opt);
383     m_staticText->prepare();
384
385     return *m_staticText;
386 }
387
388 int ApiTraceCall::numChildren() const
389 {
390     return 0;
391 }
392
393 int ApiTraceFrame::numChildren() const
394 {
395     return calls.count();
396 }
397
398 ApiTraceFrame::ApiTraceFrame()
399     : ApiTraceEvent(ApiTraceEvent::Frame),
400       m_parentTrace(0)
401 {
402 }
403
404 ApiTraceCall::ApiTraceCall()
405     : ApiTraceEvent(ApiTraceEvent::Call),
406       m_hasBinaryData(false),
407       m_binaryDataIndex(0)
408 {
409 }
410
411 ApiTraceEvent::ApiTraceEvent()
412     : m_type(ApiTraceEvent::None),
413       m_staticText(0)
414 {
415 }
416
417 ApiTraceEvent::ApiTraceEvent(Type t)
418     : m_type(t),
419       m_staticText(0)
420 {
421 }
422
423 ApiTraceCall::~ApiTraceCall()
424 {
425 }
426
427 QVariantMap ApiTraceEvent::stateParameters() const
428 {
429     return m_state.parameters();
430 }
431
432 ApiTraceState ApiTraceEvent::state() const
433 {
434     return m_state;
435 }
436
437 void ApiTraceEvent::setState(const ApiTraceState &state)
438 {
439     m_state = state;
440 }
441
442 bool ApiTraceCall::hasBinaryData() const
443 {
444     return m_hasBinaryData;
445 }
446
447 int ApiTraceCall::binaryDataIndex() const
448 {
449     return m_binaryDataIndex;
450 }
451
452 ApiTraceState::ApiTraceState()
453 {
454 }
455
456 ApiTraceState::ApiTraceState(const QVariantMap &parsedJson)
457 {
458     m_parameters = parsedJson[QLatin1String("parameters")].toMap();
459     QVariantMap attachedShaders =
460         parsedJson[QLatin1String("shaders")].toMap();
461     QVariantMap::const_iterator itr;
462
463
464     for (itr = attachedShaders.constBegin(); itr != attachedShaders.constEnd();
465          ++itr) {
466         QString type = itr.key();
467         QString source = itr.value().toString();
468         m_shaderSources[type] = source;
469     }
470
471     QVariantList textureUnits =
472         parsedJson[QLatin1String("textures")].toList();
473     for (int i = 0; i < textureUnits.count(); ++i) {
474         QVariantMap unit = textureUnits[i].toMap();
475         for (itr = unit.constBegin(); itr != unit.constEnd(); ++itr) {
476             QVariantMap target = itr.value().toMap();
477             if (target.count()) {
478                 QVariantList levels = target[QLatin1String("levels")].toList();
479                 for (int j = 0; j < levels.count(); ++j) {
480                     QVariantMap level = levels[j].toMap();
481                     QVariantMap image = level[QLatin1String("image")].toMap();
482                     QSize size(image[QLatin1String("__width__")].toInt(),
483                                image[QLatin1String("__height__")].toInt());
484                     QString cls = image[QLatin1String("__class__")].toString();
485                     QString type = image[QLatin1String("__type__")].toString();
486                     bool normalized =
487                         image[QLatin1String("__normalized__")].toBool();
488                     int numChannels =
489                         image[QLatin1String("__channels__")].toInt();
490
491                     Q_ASSERT(type == QLatin1String("uint8"));
492                     Q_ASSERT(normalized == true);
493
494                     QByteArray dataArray =
495                         image[QLatin1String("__data__")].toByteArray();
496
497                     ApiTexture tex;
498                     tex.setSize(size);
499                     tex.setNumChannels(numChannels);
500                     tex.setLevel(j);
501                     tex.setUnit(i);
502                     tex.setTarget(itr.key());
503                     tex.contentsFromBase64(dataArray);
504
505                     m_textures.append(tex);
506                 }
507             }
508         }
509     }
510
511     QVariantMap fbos =
512         parsedJson[QLatin1String("framebuffer")].toMap();
513     for (itr = fbos.constBegin(); itr != fbos.constEnd(); ++itr) {
514         QVariantMap buffer = itr.value().toMap();
515         QSize size(buffer[QLatin1String("__width__")].toInt(),
516                    buffer[QLatin1String("__height__")].toInt());
517         QString cls = buffer[QLatin1String("__class__")].toString();
518         QString type = buffer[QLatin1String("__type__")].toString();
519         bool normalized = buffer[QLatin1String("__normalized__")].toBool();
520         int numChannels = buffer[QLatin1String("__channels__")].toInt();
521
522         Q_ASSERT(type == QLatin1String("uint8"));
523         Q_ASSERT(normalized == true);
524
525         QByteArray dataArray =
526             buffer[QLatin1String("__data__")].toByteArray();
527
528         ApiFramebuffer fbo;
529         fbo.setSize(size);
530         fbo.setNumChannels(numChannels);
531         fbo.setType(itr.key());
532         fbo.contentsFromBase64(dataArray);
533         m_framebuffers.append(fbo);
534     }
535 }
536
537 QVariantMap ApiTraceState::parameters() const
538 {
539     return m_parameters;
540 }
541
542 QMap<QString, QString> ApiTraceState::shaderSources() const
543 {
544     return m_shaderSources;
545 }
546
547 bool ApiTraceState::isEmpty() const
548 {
549     return m_parameters.isEmpty();
550 }
551
552 QList<ApiTexture> ApiTraceState::textures() const
553 {
554     return m_textures;
555 }
556
557 QList<ApiFramebuffer> ApiTraceState::framebuffers() const
558 {
559     return m_framebuffers;
560 }
561
562 QList<QVariant> ApiArray::values() const
563 {
564     return m_array;
565 }
566
567 int ApiTraceCall::index() const
568 {
569     return m_index;
570 }
571
572 QString ApiTraceCall::name() const
573 {
574     return m_name;
575 }
576
577 QStringList ApiTraceCall::argNames() const
578 {
579     return m_argNames;
580 }
581
582 QVariantList ApiTraceCall::arguments() const
583 {
584     if (m_editedValues.isEmpty())
585         return m_argValues;
586     else
587         return m_editedValues;
588 }
589
590 QVariant ApiTraceCall::returnValue() const
591 {
592     return m_returnValue;
593 }
594
595 QUrl ApiTraceCall::helpUrl() const
596 {
597     return m_helpUrl;
598 }
599
600 ApiTraceCall::ApiTraceCall(const Trace::Call *call)
601     : ApiTraceEvent(ApiTraceEvent::Call),
602       m_hasBinaryData(false),
603       m_binaryDataIndex(0)
604 {
605     m_name = QString::fromStdString(call->sig->name);
606     m_index = call->no;
607
608     QString argumentsText;
609     for (int i = 0; i < call->sig->arg_names.size(); ++i) {
610         m_argNames +=
611             QString::fromStdString(call->sig->arg_names[i]);
612     }
613     if (call->ret) {
614         VariantVisitor retVisitor;
615         call->ret->visit(retVisitor);
616         m_returnValue = retVisitor.variant();
617     }
618     for (int i = 0; i < call->args.size(); ++i) {
619         VariantVisitor argVisitor;
620         call->args[i]->visit(argVisitor);
621         m_argValues += argVisitor.variant();
622
623         //XXX
624         //FIXME: this is a nasty hack. Trace::Blob's can't
625         //   delete the contents in the destructor because
626         //   the data is being used by other calls. we should
627         //   use something like Boost's shared_ptr or
628         //   Qt's QSharedPointer to handle it.
629         Trace::Blob *b = dynamic_cast<Trace::Blob*>(call->args[i]);
630         if (b && b->blob()) {
631             char *buf = (char*)b->blob();
632             delete [] buf;
633         }
634
635     }
636 }
637
638 void ApiTraceCall::setHelpUrl(const QUrl &url)
639 {
640     m_helpUrl = url;
641 }
642
643 void ApiTraceCall::setParentFrame(ApiTraceFrame *frame)
644 {
645     m_parentFrame = frame;
646 }
647
648 ApiTraceFrame * ApiTraceCall::parentFrame()const
649 {
650     return m_parentFrame;
651 }
652
653 ApiTraceEvent::~ApiTraceEvent()
654 {
655     delete m_staticText;
656 }
657
658 void ApiTraceCall::revert()
659 {
660     setEditedValues(QVariantList());
661 }
662
663 ApiTrace * ApiTraceFrame::parentTrace() const
664 {
665     return m_parentTrace;
666 }
667
668 void ApiTraceFrame::setParentTrace(ApiTrace *trace)
669 {
670     m_parentTrace = trace;
671 }
672
673 QVariantList ApiTraceCall::originalValues() const
674 {
675     return m_argValues;
676 }
677
678 void ApiTraceCall::setEditedValues(const QVariantList &lst)
679 {
680     ApiTrace *trace = 0;
681     if (m_parentFrame)
682         trace = m_parentFrame->parentTrace();
683     m_editedValues = lst;
684
685     if (trace) {
686         if (!lst.isEmpty()) {
687             trace->callEdited(this);
688         } else {
689             trace->callReverted(this);
690         }
691     }
692 }
693
694 QVariantList ApiTraceCall::editedValues() const
695 {
696     return m_editedValues;
697 }
698
699 bool ApiTraceCall::edited() const
700 {
701     return !m_editedValues.isEmpty();
702 }
703
704 ApiEnum::ApiEnum(const QString &name, const QVariant &val)
705     : m_name(name),
706       m_value(val)
707 {
708 }
709
710 QString ApiEnum::toString() const
711 {
712     return m_name;
713 }
714
715 QVariant ApiEnum::value() const
716 {
717     return m_value;
718 }
719
720 QString ApiEnum::name() const
721 {
722     return m_name;
723 }
724
725 unsigned long long ApiBitmask::value() const
726 {
727     return m_value;
728 }
729
730 ApiBitmask::Signature ApiBitmask::signature() const
731 {
732     return m_sig;
733 }
734
735 ApiStruct::Signature ApiStruct::signature() const
736 {
737     return m_sig;
738 }
739
740 QList<QVariant> ApiStruct::values() const
741 {
742     return m_members;
743 }
744
745 unsigned long long ApiPointer::value() const
746 {
747     return m_value;
748 }
749