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