]> git.cworth.org Git - apitrace/blob - gui/apitracecall.cpp
Further reduce memory usage by a couple of hundreds of megs.
[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 {
391 }
392
393 ApiTraceCall::ApiTraceCall()
394     : ApiTraceEvent(ApiTraceEvent::Call),
395       m_hasBinaryData(false),
396       m_binaryDataIndex(0)
397 {
398 }
399
400 ApiTraceEvent::ApiTraceEvent()
401     : m_type(ApiTraceEvent::None),
402       m_staticText(0)
403 {
404 }
405
406 ApiTraceEvent::ApiTraceEvent(Type t)
407     : m_type(t),
408       m_staticText(0)
409 {
410 }
411
412 ApiTraceCall::~ApiTraceCall()
413 {
414 }
415
416 QVariantMap ApiTraceEvent::stateParameters() const
417 {
418     return m_state.parameters();
419 }
420
421 ApiTraceState ApiTraceEvent::state() const
422 {
423     return m_state;
424 }
425
426 void ApiTraceEvent::setState(const ApiTraceState &state)
427 {
428     m_state = state;
429 }
430
431 bool ApiTraceCall::hasBinaryData() const
432 {
433     return m_hasBinaryData;
434 }
435
436 int ApiTraceCall::binaryDataIndex() const
437 {
438     return m_binaryDataIndex;
439 }
440
441 ApiTraceState::ApiTraceState()
442 {
443 }
444
445 ApiTraceState::ApiTraceState(const QVariantMap &parsedJson)
446 {
447     m_parameters = parsedJson[QLatin1String("parameters")].toMap();
448     QVariantMap attachedShaders =
449         parsedJson[QLatin1String("shaders")].toMap();
450     QVariantMap::const_iterator itr;
451
452
453     for (itr = attachedShaders.constBegin(); itr != attachedShaders.constEnd();
454          ++itr) {
455         QString type = itr.key();
456         QString source = itr.value().toString();
457         m_shaderSources[type] = source;
458     }
459
460     QVariantList textureUnits =
461         parsedJson[QLatin1String("textures")].toList();
462     for (int i = 0; i < textureUnits.count(); ++i) {
463         QVariantMap unit = textureUnits[i].toMap();
464         for (itr = unit.constBegin(); itr != unit.constEnd(); ++itr) {
465             QVariantMap target = itr.value().toMap();
466             if (target.count()) {
467                 QVariantList levels = target[QLatin1String("levels")].toList();
468                 for (int j = 0; j < levels.count(); ++j) {
469                     QVariantMap level = levels[j].toMap();
470                     QVariantMap image = level[QLatin1String("image")].toMap();
471                     QSize size(image[QLatin1String("__width__")].toInt(),
472                                image[QLatin1String("__height__")].toInt());
473                     QString cls = image[QLatin1String("__class__")].toString();
474                     QString type = image[QLatin1String("__type__")].toString();
475                     bool normalized =
476                         image[QLatin1String("__normalized__")].toBool();
477                     int numChannels =
478                         image[QLatin1String("__channels__")].toInt();
479
480                     Q_ASSERT(type == QLatin1String("uint8"));
481                     Q_ASSERT(normalized == true);
482
483                     QByteArray dataArray =
484                         image[QLatin1String("__data__")].toByteArray();
485
486                     ApiTexture tex;
487                     tex.setSize(size);
488                     tex.setNumChannels(numChannels);
489                     tex.setLevel(j);
490                     tex.setUnit(i);
491                     tex.setTarget(itr.key());
492                     tex.contentsFromBase64(dataArray);
493
494                     m_textures.append(tex);
495                 }
496             }
497         }
498     }
499
500     QVariantMap fbos =
501         parsedJson[QLatin1String("framebuffer")].toMap();
502     for (itr = fbos.constBegin(); itr != fbos.constEnd(); ++itr) {
503         QVariantMap buffer = itr.value().toMap();
504         QSize size(buffer[QLatin1String("__width__")].toInt(),
505                    buffer[QLatin1String("__height__")].toInt());
506         QString cls = buffer[QLatin1String("__class__")].toString();
507         QString type = buffer[QLatin1String("__type__")].toString();
508         bool normalized = buffer[QLatin1String("__normalized__")].toBool();
509         int numChannels = buffer[QLatin1String("__channels__")].toInt();
510
511         Q_ASSERT(type == QLatin1String("uint8"));
512         Q_ASSERT(normalized == true);
513
514         QByteArray dataArray =
515             buffer[QLatin1String("__data__")].toByteArray();
516
517         ApiFramebuffer fbo;
518         fbo.setSize(size);
519         fbo.setNumChannels(numChannels);
520         fbo.setType(itr.key());
521         fbo.contentsFromBase64(dataArray);
522         m_framebuffers.append(fbo);
523     }
524 }
525
526 QVariantMap ApiTraceState::parameters() const
527 {
528     return m_parameters;
529 }
530
531 QMap<QString, QString> ApiTraceState::shaderSources() const
532 {
533     return m_shaderSources;
534 }
535
536 bool ApiTraceState::isEmpty() const
537 {
538     return m_parameters.isEmpty();
539 }
540
541 QList<ApiTexture> ApiTraceState::textures() const
542 {
543     return m_textures;
544 }
545
546 QList<ApiFramebuffer> ApiTraceState::framebuffers() const
547 {
548     return m_framebuffers;
549 }
550
551 QList<QVariant> ApiArray::values() const
552 {
553     return m_array;
554 }
555
556 int ApiTraceCall::index() const
557 {
558     return m_index;
559 }
560
561 QString ApiTraceCall::name() const
562 {
563     return m_name;
564 }
565
566 QStringList ApiTraceCall::argNames() const
567 {
568     return m_argNames;
569 }
570
571 QVariantList ApiTraceCall::arguments() const
572 {
573     return m_argValues;
574 }
575
576 QVariant ApiTraceCall::returnValue() const
577 {
578     return m_returnValue;
579 }
580
581 QUrl ApiTraceCall::helpUrl() const
582 {
583     return m_helpUrl;
584 }
585
586 ApiTraceCall::ApiTraceCall(const Trace::Call *call)
587     : ApiTraceEvent(ApiTraceEvent::Call),
588       m_hasBinaryData(false),
589       m_binaryDataIndex(0)
590 {
591     m_name = QString::fromStdString(call->sig->name);
592     m_index = call->no;
593
594     QString argumentsText;
595     for (int i = 0; i < call->sig->arg_names.size(); ++i) {
596         m_argNames +=
597             QString::fromStdString(call->sig->arg_names[i]);
598     }
599     if (call->ret) {
600         VariantVisitor retVisitor;
601         call->ret->visit(retVisitor);
602         m_returnValue = retVisitor.variant();
603     }
604     for (int i = 0; i < call->args.size(); ++i) {
605         VariantVisitor argVisitor;
606         call->args[i]->visit(argVisitor);
607         m_argValues += argVisitor.variant();
608
609         //XXX
610         //FIXME: this is a nasty hack. Trace::Blob's can't
611         //   delete the contents in the destructor because
612         //   the data is being used by other calls. we should
613         //   use something like Boost's shared_ptr or
614         //   Qt's QSharedPointer to handle it.
615         Trace::Blob *b = dynamic_cast<Trace::Blob*>(call->args[i]);
616         if (b && b->blob()) {
617             char *buf = (char*)b->blob();
618             delete [] buf;
619         }
620
621     }
622 }
623
624 void ApiTraceCall::setHelpUrl(const QUrl &url)
625 {
626     m_helpUrl = url;
627 }
628
629 void ApiTraceCall::setParentFrame(ApiTraceFrame *frame)
630 {
631     m_parentFrame = frame;
632 }
633
634 ApiTraceFrame * ApiTraceCall::parentFrame()const
635 {
636     return m_parentFrame;
637 }
638
639 ApiTraceEvent::~ApiTraceEvent()
640 {
641     delete m_staticText;
642 }
643