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