]> git.cworth.org Git - apitrace/blob - gui/apitracecall.cpp
c9e61e2cb8c8e499dbd35de9a49849005b783518
[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     //XXX
209     //FIXME: this is a nasty hack. Trace::Blob's can't
210     //   delete the contents in the destructor because
211     //   the data is being used by other calls. We piggy back
212     //   on that assumption and don't deep copy the data. If
213     //   Blob's will start deleting the data we will need to
214     //   start deep copying it or switch to using something like
215     //   Boost's shared_ptr or Qt's QSharedPointer to handle it
216     QByteArray barray = QByteArray::fromRawData(blob->buf, blob->size);
217     m_variant = QVariant(barray);
218 }
219
220 void VariantVisitor::visit(Trace::Pointer *ptr)
221 {
222     m_variant = QVariant::fromValue(ApiPointer(ptr->value));
223 }
224
225 ApiArray::ApiArray(const Trace::Array *arr)
226 {
227     init(arr);
228 }
229
230 ApiArray::ApiArray(const QList<QVariant> &vals)
231     : m_array(vals)
232 {
233 }
234
235 QString ApiArray::toString() const
236 {
237     QString str;
238     str += QLatin1String("[");
239     for(int i = 0; i < m_array.count(); ++i) {
240         const QVariant &var = m_array[i];
241         str += apiVariantToString(var);
242         if (i < m_array.count() - 1)
243             str += QLatin1String(", ");
244     }
245     str += QLatin1String("]");
246
247     return str;
248 }
249
250 void ApiArray::init(const Trace::Array *arr)
251 {
252     if (!arr)
253         return;
254
255     for (int i = 0; i < arr->values.size(); ++i) {
256         VariantVisitor vis;
257         arr->values[i]->visit(vis);
258
259         m_array.append(vis.variant());
260     }
261 }
262
263 QStaticText ApiTraceCall::staticText() const
264 {
265     if (m_staticText && !m_staticText->text().isEmpty())
266         return *m_staticText;
267
268     QString richText = QString::fromLatin1(
269         "<span style=\"font-weight:bold\">%1</span>(").arg(m_name);
270     for (int i = 0; i < m_argNames.count(); ++i) {
271         richText += QLatin1String("<span style=\"color:#0000ff\">");
272         QString argText = apiVariantToString(m_argValues[i]);
273
274         //if arguments are really long (e.g. shader text), cut them
275         // and elide it
276         if (argText.length() > 40) {
277             QString shortened = argText.mid(0, 40);
278             shortened[argText.length() - 5] = '.';
279             shortened[argText.length() - 4] = '.';
280             shortened[argText.length() - 3] = '.';
281             shortened[argText.length() - 2] = argText[argText.length() - 2];
282             shortened[argText.length() - 1] = argText[argText.length() - 1];
283             richText += shortened;
284         } else {
285             richText += argText;
286         }
287         richText += QLatin1String("</span>");
288         if (i < m_argNames.count() - 1)
289             richText += QLatin1String(", ");
290     }
291     richText += QLatin1String(")");
292     if (m_returnValue.isValid()) {
293         richText +=
294             QLatin1Literal(" = ") %
295             QLatin1Literal("<span style=\"color:#0000ff\">") %
296             apiVariantToString(m_returnValue) %
297             QLatin1Literal("</span>");
298     }
299
300     if (!m_staticText)
301         m_staticText = new QStaticText(richText);
302     QTextOption opt;
303     opt.setWrapMode(QTextOption::NoWrap);
304     m_staticText->setTextOption(opt);
305     m_staticText->prepare();
306
307     return *m_staticText;
308 }
309
310 QString ApiTraceCall::toHtml() const
311 {
312     if (!m_richText.isEmpty())
313         return m_richText;
314
315     if (m_helpUrl.isEmpty()) {
316         m_richText = QString::fromLatin1(
317             "%1) <span style=\"font-weight:bold\">%2</span>(")
318                      .arg(m_index)
319                      .arg(m_name);
320     } else {
321         m_richText = QString::fromLatin1(
322             "%1) <span style=\"font-weight:bold\"><a href=\"%2\">%3</a></span>(")
323                       .arg(m_index)
324                       .arg(m_helpUrl.toString())
325                       .arg(m_name);
326     }
327
328     for (int i = 0; i < m_argNames.count(); ++i) {
329         m_richText += m_argNames[i] +
330                       QLatin1Literal(" = ") +
331                       QLatin1Literal("<span style=\"color:#0000ff\">") +
332                       apiVariantToString(m_argValues[i]) +
333                       QLatin1Literal("</span>");
334         if (i < m_argNames.count() - 1)
335             m_richText += QLatin1String(", ");
336     }
337     m_richText += QLatin1String(")");
338
339     if (m_returnValue.isValid()) {
340         m_richText +=
341             QLatin1String(" = ") +
342             QLatin1String("<span style=\"color:#0000ff\">") +
343             apiVariantToString(m_returnValue) +
344             QLatin1String("</span>");
345     }
346     m_richText.squeeze();
347     return m_richText;
348 }
349
350 QString ApiTraceCall::filterText() const
351 {
352     if (!m_filterText.isEmpty())
353         return m_filterText;
354
355     m_filterText = m_name + QLatin1Literal("(");
356     for (int i = 0; i < m_argNames.count(); ++i) {
357         m_filterText += m_argNames[i] +
358                         QLatin1Literal(" = ") +
359                         apiVariantToString(m_argValues[i]);
360         if (m_argValues[i].type() == QVariant::ByteArray) {
361             m_hasBinaryData = true;
362             m_binaryDataIndex = i;
363         }
364         if (i < m_argNames.count() - 1)
365             m_filterText += QLatin1String(", ");
366     }
367     m_filterText += QLatin1String(")");
368
369     if (m_returnValue.isValid()) {
370         m_filterText += QLatin1Literal(" = ") +
371                         apiVariantToString(m_returnValue);
372     }
373     m_filterText.squeeze();
374     return m_filterText;
375 }
376
377 QStaticText ApiTraceFrame::staticText() const
378 {
379     if (m_staticText && !m_staticText->text().isEmpty())
380         return *m_staticText;
381
382     QString richText =
383         QString::fromLatin1("<span style=\"font-weight:bold\">Frame %1</span>").arg(number);
384
385     if (!m_staticText)
386         m_staticText = new QStaticText(richText);
387
388     QTextOption opt;
389     opt.setWrapMode(QTextOption::NoWrap);
390     m_staticText->setTextOption(opt);
391     m_staticText->prepare();
392
393     return *m_staticText;
394 }
395
396 int ApiTraceCall::numChildren() const
397 {
398     return 0;
399 }
400
401 int ApiTraceFrame::numChildren() const
402 {
403     return calls.count();
404 }
405
406 ApiTraceFrame::ApiTraceFrame()
407     : ApiTraceEvent(ApiTraceEvent::Frame),
408       m_parentTrace(0)
409 {
410 }
411
412 ApiTraceCall::ApiTraceCall()
413     : ApiTraceEvent(ApiTraceEvent::Call),
414       m_hasBinaryData(false),
415       m_binaryDataIndex(0)
416 {
417 }
418
419 ApiTraceEvent::ApiTraceEvent()
420     : m_type(ApiTraceEvent::None),
421       m_staticText(0)
422 {
423 }
424
425 ApiTraceEvent::ApiTraceEvent(Type t)
426     : m_type(t),
427       m_staticText(0)
428 {
429 }
430
431 ApiTraceCall::~ApiTraceCall()
432 {
433 }
434
435 QVariantMap ApiTraceEvent::stateParameters() const
436 {
437     return m_state.parameters();
438 }
439
440 ApiTraceState ApiTraceEvent::state() const
441 {
442     return m_state;
443 }
444
445 void ApiTraceEvent::setState(const ApiTraceState &state)
446 {
447     m_state = state;
448 }
449
450 bool ApiTraceCall::hasBinaryData() const
451 {
452     return m_hasBinaryData;
453 }
454
455 int ApiTraceCall::binaryDataIndex() const
456 {
457     return m_binaryDataIndex;
458 }
459
460 ApiTraceState::ApiTraceState()
461 {
462 }
463
464 ApiTraceState::ApiTraceState(const QVariantMap &parsedJson)
465 {
466     m_parameters = parsedJson[QLatin1String("parameters")].toMap();
467     QVariantMap attachedShaders =
468         parsedJson[QLatin1String("shaders")].toMap();
469     QVariantMap::const_iterator itr;
470
471
472     for (itr = attachedShaders.constBegin(); itr != attachedShaders.constEnd();
473          ++itr) {
474         QString type = itr.key();
475         QString source = itr.value().toString();
476         m_shaderSources[type] = source;
477     }
478
479     QVariantList textureUnits =
480         parsedJson[QLatin1String("textures")].toList();
481     for (int i = 0; i < textureUnits.count(); ++i) {
482         QVariantMap unit = textureUnits[i].toMap();
483         for (itr = unit.constBegin(); itr != unit.constEnd(); ++itr) {
484             QVariantMap target = itr.value().toMap();
485             if (target.count()) {
486                 QVariantList levels = target[QLatin1String("levels")].toList();
487                 for (int j = 0; j < levels.count(); ++j) {
488                     QVariantMap level = levels[j].toMap();
489                     QVariantMap image = level[QLatin1String("image")].toMap();
490                     QSize size(image[QLatin1String("__width__")].toInt(),
491                                image[QLatin1String("__height__")].toInt());
492                     QString cls = image[QLatin1String("__class__")].toString();
493                     QString type = image[QLatin1String("__type__")].toString();
494                     bool normalized =
495                         image[QLatin1String("__normalized__")].toBool();
496                     int numChannels =
497                         image[QLatin1String("__channels__")].toInt();
498
499                     Q_ASSERT(type == QLatin1String("uint8"));
500                     Q_ASSERT(normalized == true);
501
502                     QByteArray dataArray =
503                         image[QLatin1String("__data__")].toByteArray();
504
505                     ApiTexture tex;
506                     tex.setSize(size);
507                     tex.setNumChannels(numChannels);
508                     tex.setLevel(j);
509                     tex.setUnit(i);
510                     tex.setTarget(itr.key());
511                     tex.contentsFromBase64(dataArray);
512
513                     m_textures.append(tex);
514                 }
515             }
516         }
517     }
518
519     QVariantMap fbos =
520         parsedJson[QLatin1String("framebuffer")].toMap();
521     for (itr = fbos.constBegin(); itr != fbos.constEnd(); ++itr) {
522         QVariantMap buffer = itr.value().toMap();
523         QSize size(buffer[QLatin1String("__width__")].toInt(),
524                    buffer[QLatin1String("__height__")].toInt());
525         QString cls = buffer[QLatin1String("__class__")].toString();
526         QString type = buffer[QLatin1String("__type__")].toString();
527         bool normalized = buffer[QLatin1String("__normalized__")].toBool();
528         int numChannels = buffer[QLatin1String("__channels__")].toInt();
529
530         Q_ASSERT(type == QLatin1String("uint8"));
531         Q_ASSERT(normalized == true);
532
533         QByteArray dataArray =
534             buffer[QLatin1String("__data__")].toByteArray();
535
536         ApiFramebuffer fbo;
537         fbo.setSize(size);
538         fbo.setNumChannels(numChannels);
539         fbo.setType(itr.key());
540         fbo.contentsFromBase64(dataArray);
541         m_framebuffers.append(fbo);
542     }
543 }
544
545 QVariantMap ApiTraceState::parameters() const
546 {
547     return m_parameters;
548 }
549
550 QMap<QString, QString> ApiTraceState::shaderSources() const
551 {
552     return m_shaderSources;
553 }
554
555 bool ApiTraceState::isEmpty() const
556 {
557     return m_parameters.isEmpty();
558 }
559
560 QList<ApiTexture> ApiTraceState::textures() const
561 {
562     return m_textures;
563 }
564
565 QList<ApiFramebuffer> ApiTraceState::framebuffers() const
566 {
567     return m_framebuffers;
568 }
569
570 QList<QVariant> ApiArray::values() const
571 {
572     return m_array;
573 }
574
575 int ApiTraceCall::index() const
576 {
577     return m_index;
578 }
579
580 QString ApiTraceCall::name() const
581 {
582     return m_name;
583 }
584
585 QStringList ApiTraceCall::argNames() const
586 {
587     return m_argNames;
588 }
589
590 QVariantList ApiTraceCall::arguments() const
591 {
592     if (m_editedValues.isEmpty())
593         return m_argValues;
594     else
595         return m_editedValues;
596 }
597
598 QVariant ApiTraceCall::returnValue() const
599 {
600     return m_returnValue;
601 }
602
603 QUrl ApiTraceCall::helpUrl() const
604 {
605     return m_helpUrl;
606 }
607
608 ApiTraceCall::ApiTraceCall(const Trace::Call *call)
609     : ApiTraceEvent(ApiTraceEvent::Call),
610       m_hasBinaryData(false),
611       m_binaryDataIndex(0)
612 {
613     m_name = QString::fromStdString(call->sig->name);
614     m_index = call->no;
615
616     QString argumentsText;
617     for (int i = 0; i < call->sig->arg_names.size(); ++i) {
618         m_argNames +=
619             QString::fromStdString(call->sig->arg_names[i]);
620     }
621     if (call->ret) {
622         VariantVisitor retVisitor;
623         call->ret->visit(retVisitor);
624         m_returnValue = retVisitor.variant();
625     }
626     for (int i = 0; i < call->args.size(); ++i) {
627         VariantVisitor argVisitor;
628         call->args[i]->visit(argVisitor);
629         m_argValues += argVisitor.variant();
630     }
631 }
632
633 void ApiTraceCall::setHelpUrl(const QUrl &url)
634 {
635     m_helpUrl = url;
636 }
637
638 void ApiTraceCall::setParentFrame(ApiTraceFrame *frame)
639 {
640     m_parentFrame = frame;
641 }
642
643 ApiTraceFrame * ApiTraceCall::parentFrame()const
644 {
645     return m_parentFrame;
646 }
647
648 ApiTraceEvent::~ApiTraceEvent()
649 {
650     delete m_staticText;
651 }
652
653 void ApiTraceCall::revert()
654 {
655     setEditedValues(QVariantList());
656 }
657
658 ApiTrace * ApiTraceFrame::parentTrace() const
659 {
660     return m_parentTrace;
661 }
662
663 void ApiTraceFrame::setParentTrace(ApiTrace *trace)
664 {
665     m_parentTrace = trace;
666 }
667
668 QVariantList ApiTraceCall::originalValues() const
669 {
670     return m_argValues;
671 }
672
673 void ApiTraceCall::setEditedValues(const QVariantList &lst)
674 {
675     ApiTrace *trace = 0;
676     if (m_parentFrame)
677         trace = m_parentFrame->parentTrace();
678     m_editedValues = lst;
679
680     if (trace) {
681         if (!lst.isEmpty()) {
682             trace->callEdited(this);
683         } else {
684             trace->callReverted(this);
685         }
686     }
687 }
688
689 QVariantList ApiTraceCall::editedValues() const
690 {
691     return m_editedValues;
692 }
693
694 bool ApiTraceCall::edited() const
695 {
696     return !m_editedValues.isEmpty();
697 }
698
699 ApiEnum::ApiEnum(const QString &name, const QVariant &val)
700     : m_name(name),
701       m_value(val)
702 {
703 }
704
705 QString ApiEnum::toString() const
706 {
707     return m_name;
708 }
709
710 QVariant ApiEnum::value() const
711 {
712     return m_value;
713 }
714
715 QString ApiEnum::name() const
716 {
717     return m_name;
718 }
719
720 unsigned long long ApiBitmask::value() const
721 {
722     return m_value;
723 }
724
725 ApiBitmask::Signature ApiBitmask::signature() const
726 {
727     return m_sig;
728 }
729
730 ApiStruct::Signature ApiStruct::signature() const
731 {
732     return m_sig;
733 }
734
735 QList<QVariant> ApiStruct::values() const
736 {
737     return m_members;
738 }
739
740 unsigned long long ApiPointer::value() const
741 {
742     return m_value;
743 }
744