1 #include "mainwindow.h"
4 #include "apitracecall.h"
5 #include "apicalldelegate.h"
6 #include "apitracemodel.h"
7 #include "apitracefilter.h"
8 #include "imageviewer.h"
10 #include "settingsdialog.h"
11 #include "shaderssourcewidget.h"
12 #include "ui_retracerdialog.h"
13 #include "vertexdatainterpreter.h"
15 #include <qjson/parser.h>
19 #include <QDesktopServices>
21 #include <QFileDialog>
23 #include <QMessageBox>
24 #include <QProgressBar>
27 #include <QVBoxLayout>
32 MainWindow::MainWindow()
36 m_jsonParser(new QJson::Parser())
43 void MainWindow::openTrace()
46 QFileDialog::getOpenFileName(
50 tr("Trace Files (*.trace)"));
52 qDebug()<< "File name : " <<fileName;
54 newTraceFile(fileName);
57 void MainWindow::loadTrace(const QString &fileName)
59 if (!QFile::exists(fileName)) {
60 QMessageBox::warning(this, tr("File Missing"),
61 tr("File '%1' doesn't exist.").arg(fileName));
64 qDebug()<< "Loading : " <<fileName;
66 m_progressBar->setValue(0);
67 newTraceFile(fileName);
70 void MainWindow::callItemSelected(const QModelIndex &index)
72 ApiTraceEvent *event =
73 index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
75 if (event && event->type() == ApiTraceEvent::Call) {
76 ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
77 m_ui.detailsWebView->setHtml(call->toHtml());
78 m_ui.detailsDock->show();
79 if (call->hasBinaryData()) {
81 call->argValues[call->binaryDataIndex()].toByteArray();
82 m_vdataInterpreter->setData(data);
84 for (int i = 0; i < call->argNames.count(); ++i) {
85 QString name = call->argNames[i];
86 if (name == QLatin1String("stride")) {
87 int stride = call->argValues[i].toInt();
88 m_ui.vertexStrideSB->setValue(stride);
89 } else if (name == QLatin1String("size")) {
90 int components = call->argValues[i].toInt();
91 m_ui.vertexComponentsSB->setValue(components);
92 } else if (name == QLatin1String("type")) {
93 QString val = call->argValues[i].toString();
94 int textIndex = m_ui.vertexTypeCB->findText(val);
96 m_ui.vertexTypeCB->setCurrentIndex(textIndex);
100 m_ui.vertexDataDock->setVisible(call->hasBinaryData());
101 m_selectedEvent = call;
103 if (event && event->type() == ApiTraceEvent::Frame) {
104 m_selectedEvent = static_cast<ApiTraceFrame*>(event);
107 m_ui.detailsDock->hide();
108 m_ui.vertexDataDock->hide();
110 if (m_selectedEvent && !m_selectedEvent->state().isEmpty()) {
113 m_ui.stateDock->hide();
116 void MainWindow::filterTrace()
118 m_proxyModel->setFilterString(m_filterEdit->text());
121 void MainWindow::replayStart()
124 Ui_RetracerDialog dlgUi;
127 dlgUi.doubleBufferingCB->setChecked(
128 m_retracer->isDoubleBuffered());
129 dlgUi.benchmarkCB->setChecked(
130 m_retracer->isBenchmarking());
132 if (dlg.exec() == QDialog::Accepted) {
133 m_retracer->setDoubleBuffered(
134 dlgUi.doubleBufferingCB->isChecked());
135 m_retracer->setBenchmarking(
136 dlgUi.benchmarkCB->isChecked());
141 void MainWindow::replayStop()
143 m_retracer->terminate();
144 m_ui.actionStop->setEnabled(false);
145 m_ui.actionReplay->setEnabled(true);
146 m_ui.actionLookupState->setEnabled(true);
149 void MainWindow::newTraceFile(const QString &fileName)
151 m_traceFileName = fileName;
152 m_trace->setFileName(fileName);
154 if (m_traceFileName.isEmpty()) {
155 m_ui.actionReplay->setEnabled(false);
156 m_ui.actionLookupState->setEnabled(false);
157 setWindowTitle(tr("QApiTrace"));
159 QFileInfo info(fileName);
160 m_ui.actionReplay->setEnabled(true);
161 m_ui.actionLookupState->setEnabled(true);
163 tr("QApiTrace - %1").arg(info.fileName()));
167 void MainWindow::replayFinished(const QByteArray &output)
169 m_ui.actionStop->setEnabled(false);
170 m_ui.actionReplay->setEnabled(true);
171 m_ui.actionLookupState->setEnabled(true);
173 if (m_retracer->captureState()) {
175 QVariantMap parsedJson = m_jsonParser->parse(output, &ok).toMap();
176 parseState(parsedJson);
177 } else if (output.length() < 80) {
178 statusBar()->showMessage(output);
183 void MainWindow::replayError(const QString &message)
185 m_ui.actionStop->setEnabled(false);
186 m_ui.actionReplay->setEnabled(true);
187 m_ui.actionLookupState->setEnabled(true);
190 QMessageBox::warning(
191 this, tr("Replay Failed"), message);
194 void MainWindow::startedLoadingTrace()
197 m_progressBar->show();
198 QFileInfo info(m_trace->fileName());
199 statusBar()->showMessage(
200 tr("Loading %1...").arg(info.fileName()));
203 void MainWindow::finishedLoadingTrace()
205 m_progressBar->hide();
209 QFileInfo info(m_trace->fileName());
210 statusBar()->showMessage(
211 tr("Loaded %1").arg(info.fileName()), 3000);
214 void MainWindow::replayTrace(bool dumpState)
216 if (m_traceFileName.isEmpty())
219 m_retracer->setFileName(m_traceFileName);
220 m_retracer->setCaptureState(dumpState);
221 if (m_retracer->captureState() && m_selectedEvent) {
223 if (m_selectedEvent->type() == ApiTraceEvent::Call) {
224 index = static_cast<ApiTraceCall*>(m_selectedEvent)->index;
225 } else if (m_selectedEvent->type() == ApiTraceEvent::Frame) {
226 ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(m_selectedEvent);
227 if (frame->calls.isEmpty()) {
228 //XXX i guess we could still get the current state
229 qDebug()<<"tried to get a state for an empty frame";
232 index = frame->calls.first()->index;
234 qDebug()<<"Unknown event type";
237 m_retracer->setCaptureAtCallNumber(index);
241 m_ui.actionStop->setEnabled(true);
244 void MainWindow::lookupState()
246 if (!m_selectedEvent) {
247 QMessageBox::warning(
248 this, tr("Unknown Event"),
249 tr("To inspect the state select an event in the event list."));
252 m_stateEvent = m_selectedEvent;
256 MainWindow::~MainWindow()
261 void MainWindow::parseState(const QVariantMap &parsedJson)
263 m_stateEvent->setState(ApiTraceState(parsedJson));
264 m_model->stateSetOnEvent(m_stateEvent);
265 if (m_selectedEvent == m_stateEvent) {
268 m_ui.stateDock->hide();
273 variantToString(const QVariant &var, QString &str)
275 if (var.type() == QVariant::List) {
276 QVariantList lst = var.toList();
277 str += QLatin1String("[");
278 for (int i = 0; i < lst.count(); ++i) {
279 QVariant val = lst[i];
280 variantToString(val, str);
281 if (i < lst.count() - 1)
282 str += QLatin1String(", ");
284 str += QLatin1String("]");
285 } else if (var.type() == QVariant::Map) {
286 Q_ASSERT(!"unsupported state type");
287 } else if (var.type() == QVariant::Hash) {
288 Q_ASSERT(!"unsupported state type");
290 str += var.toString();
294 void MainWindow::fillStateForFrame()
296 QVariantMap::const_iterator itr;
299 if (!m_selectedEvent || m_selectedEvent->state().isEmpty())
302 const ApiTraceState &state = m_selectedEvent->state();
303 m_ui.stateTreeWidget->clear();
304 params = state.parameters();
305 QList<QTreeWidgetItem *> items;
306 for (itr = params.constBegin(); itr != params.constEnd(); ++itr) {
307 QString key = itr.key();
310 variantToString(itr.value(), val);
311 //qDebug()<<"key = "<<key;
312 //qDebug()<<"val = "<<val;
316 items.append(new QTreeWidgetItem((QTreeWidget*)0, lst));
318 m_ui.stateTreeWidget->insertTopLevelItems(0, items);
320 QStringList shaderSources = state.shaderSources();
321 if (shaderSources.isEmpty()) {
322 m_sourcesWidget->setShaders(shaderSources);
324 m_sourcesWidget->setShaders(shaderSources);
327 const QList<ApiTexture> &textures =
330 m_ui.surfacesTreeWidget->clear();
331 if (textures.isEmpty()) {
332 m_ui.surfacesTab->setDisabled(false);
334 QTreeWidgetItem *textureItem =
335 new QTreeWidgetItem(m_ui.surfacesTreeWidget);
336 m_ui.surfacesTreeWidget->setIconSize(QSize(64, 64));
337 textureItem->setText(0, tr("Textures"));
338 for (int i = 0; i < textures.count(); ++i) {
339 const ApiTexture &texture =
341 QIcon icon(QPixmap::fromImage(texture.thumb()));
342 QTreeWidgetItem *item = new QTreeWidgetItem(textureItem);
343 item->setIcon(0, icon);
344 int width = texture.size().width();
345 int height = texture.size().height();
347 QString::fromLatin1("%1, %2 x %3")
348 .arg(texture.target())
351 item->setText(1, descr);
353 item->setData(0, Qt::UserRole,
356 m_ui.surfacesTab->setEnabled(true);
358 m_ui.stateDock->show();
361 void MainWindow::showSettings()
363 SettingsDialog dialog;
364 dialog.setFilterOptions(m_proxyModel->filterOptions());
366 if (dialog.exec() == QDialog::Accepted) {
367 m_proxyModel->setFilterOptions(dialog.filterOptions());
371 void MainWindow::openHelp(const QUrl &url)
373 QDesktopServices::openUrl(url);
376 void MainWindow::showSurfacesMenu(const QPoint &pos)
378 QTreeWidget *tree = m_ui.surfacesTreeWidget;
379 QTreeWidgetItem *item = tree->itemAt(pos);
383 QMenu menu(tr("Surfaces"), this);
385 QAction *act = menu.addAction(tr("View Image"));
386 act->setStatusTip(tr("View the currently selected surface"));
387 connect(act, SIGNAL(triggered()),
388 SLOT(showSelectedSurface()));
390 menu.exec(tree->viewport()->mapToGlobal(pos));
393 void MainWindow::showSelectedSurface()
395 QTreeWidgetItem *item =
396 m_ui.surfacesTreeWidget->currentItem();
401 QVariant var = item->data(0, Qt::UserRole);
402 m_imageViewer->setImage(var.value<QImage>());
403 m_imageViewer->show();
404 m_imageViewer->raise();
405 m_imageViewer->activateWindow();
408 void MainWindow::initObjects()
410 m_ui.stateTreeWidget->sortByColumn(0, Qt::AscendingOrder);
412 m_sourcesWidget = new ShadersSourceWidget(m_ui.shadersTab);
413 QVBoxLayout *layout = new QVBoxLayout;
414 layout->addWidget(m_sourcesWidget);
415 m_ui.shadersTab->setLayout(layout);
417 m_trace = new ApiTrace();
418 m_retracer = new Retracer(this);
420 m_vdataInterpreter = new VertexDataInterpreter(this);
421 m_vdataInterpreter->setListWidget(m_ui.vertexDataListWidget);
422 m_vdataInterpreter->setStride(
423 m_ui.vertexStrideSB->value());
424 m_vdataInterpreter->setComponents(
425 m_ui.vertexComponentsSB->value());
426 m_vdataInterpreter->setStartingOffset(
427 m_ui.startingOffsetSB->value());
428 m_vdataInterpreter->setTypeFromString(
429 m_ui.vertexTypeCB->currentText());
431 m_imageViewer = new ImageViewer(this);
433 m_model = new ApiTraceModel();
434 m_model->setApiTrace(m_trace);
435 m_proxyModel = new ApiTraceFilter();
436 m_proxyModel->setSourceModel(m_model);
437 m_ui.callView->setModel(m_proxyModel);
438 m_ui.callView->setItemDelegate(new ApiCallDelegate);
439 m_ui.callView->resizeColumnToContents(0);
440 m_ui.callView->header()->swapSections(0, 1);
441 m_ui.callView->setColumnWidth(1, 42);
443 QToolBar *toolBar = addToolBar(tr("Navigation"));
444 m_filterEdit = new QLineEdit(toolBar);
445 toolBar->addWidget(m_filterEdit);
447 m_progressBar = new QProgressBar();
448 m_progressBar->setRange(0, 0);
449 statusBar()->addPermanentWidget(m_progressBar);
450 m_progressBar->hide();
452 m_ui.detailsDock->hide();
453 m_ui.vertexDataDock->hide();
454 m_ui.stateDock->hide();
455 setDockOptions(dockOptions() | QMainWindow::ForceTabbedDocks);
457 tabifyDockWidget(m_ui.stateDock, m_ui.vertexDataDock);
459 m_ui.surfacesTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
461 m_ui.detailsWebView->page()->setLinkDelegationPolicy(
462 QWebPage::DelegateExternalLinks);
465 void MainWindow::initConnections()
467 connect(m_trace, SIGNAL(startedLoadingTrace()),
468 this, SLOT(startedLoadingTrace()));
469 connect(m_trace, SIGNAL(finishedLoadingTrace()),
470 this, SLOT(finishedLoadingTrace()));
472 connect(m_retracer, SIGNAL(finished(const QByteArray&)),
473 this, SLOT(replayFinished(const QByteArray&)));
474 connect(m_retracer, SIGNAL(error(const QString&)),
475 this, SLOT(replayError(const QString&)));
477 connect(m_ui.vertexInterpretButton, SIGNAL(clicked()),
478 m_vdataInterpreter, SLOT(interpretData()));
479 connect(m_ui.vertexTypeCB, SIGNAL(currentIndexChanged(const QString&)),
480 m_vdataInterpreter, SLOT(setTypeFromString(const QString&)));
481 connect(m_ui.vertexStrideSB, SIGNAL(valueChanged(int)),
482 m_vdataInterpreter, SLOT(setStride(int)));
483 connect(m_ui.vertexComponentsSB, SIGNAL(valueChanged(int)),
484 m_vdataInterpreter, SLOT(setComponents(int)));
485 connect(m_ui.startingOffsetSB, SIGNAL(valueChanged(int)),
486 m_vdataInterpreter, SLOT(setStartingOffset(int)));
489 connect(m_ui.actionOpen, SIGNAL(triggered()),
490 this, SLOT(openTrace()));
491 connect(m_ui.actionQuit, SIGNAL(triggered()),
492 this, SLOT(close()));
494 connect(m_ui.actionReplay, SIGNAL(triggered()),
495 this, SLOT(replayStart()));
496 connect(m_ui.actionStop, SIGNAL(triggered()),
497 this, SLOT(replayStop()));
498 connect(m_ui.actionLookupState, SIGNAL(triggered()),
499 this, SLOT(lookupState()));
500 connect(m_ui.actionOptions, SIGNAL(triggered()),
501 this, SLOT(showSettings()));
503 connect(m_ui.callView, SIGNAL(activated(const QModelIndex &)),
504 this, SLOT(callItemSelected(const QModelIndex &)));
505 connect(m_filterEdit, SIGNAL(returnPressed()),
506 this, SLOT(filterTrace()));
508 connect(m_ui.surfacesTreeWidget,
509 SIGNAL(customContextMenuRequested(const QPoint &)),
510 SLOT(showSurfacesMenu(const QPoint &)));
511 connect(m_ui.surfacesTreeWidget,
512 SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
513 SLOT(showSelectedSurface()));
515 connect(m_ui.detailsWebView, SIGNAL(linkClicked(const QUrl&)),
516 this, SLOT(openHelp(const QUrl&)));
519 #include "mainwindow.moc"