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