From 668ca0508895f3be3c3724205e60d79d202ebbed Mon Sep 17 00:00:00 2001 From: Jeremy Hayes Date: Thu, 29 Jan 2015 13:03:36 -0700 Subject: [PATCH] Add draw state diagram on pause events. Add a Qt image viewer. Use Qt image viewer to view draw state diagram. Dump DOT files in appropriate entry points. Conflicts: layers/draw_state.c --- layers/draw_state.c | 14 ++ .../src/glv_extensions/glvdebug_xgl/CMakeLists.txt | 1 + .../glvdebug_xgl/glvdebug_xgl_qcontroller.cpp | 55 ++++-- .../glvdebug_xgl/glvdebug_xgl_qcontroller.h | 4 + tools/glave/src/glvdebug/CMakeLists.txt | 2 + tools/glave/src/glvdebug/glvdebug_qimageviewer.h | 215 +++++++++++++++++++++ 6 files changed, 271 insertions(+), 20 deletions(-) create mode 100644 tools/glave/src/glvdebug/glvdebug_qimageviewer.h diff --git a/layers/draw_state.c b/layers/draw_state.c index 383211a..5f3e5c3 100644 --- a/layers/draw_state.c +++ b/layers/draw_state.c @@ -913,6 +913,12 @@ static void printDSConfig() } } +static void synchAndDumpDot() +{ + synchDSMapping(); + dumpDotFile("pipeline_dump.dot"); +} + static void synchAndPrintDSConfig() { synchDSMapping(); @@ -1664,6 +1670,8 @@ XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglResetCommandBuffer(XGL_CMD_BUFFER cmdBuffe XGL_LAYER_EXPORT void XGLAPI xglCmdBindPipeline(XGL_CMD_BUFFER cmdBuffer, XGL_PIPELINE_BIND_POINT pipelineBindPoint, XGL_PIPELINE pipeline) { + synchAndDumpDot(); + if (getPipeline(pipeline)) { lastBoundPipeline = pipeline; } @@ -1677,17 +1685,23 @@ XGL_LAYER_EXPORT void XGLAPI xglCmdBindPipeline(XGL_CMD_BUFFER cmdBuffer, XGL_PI XGL_LAYER_EXPORT void XGLAPI xglCmdBindPipelineDelta(XGL_CMD_BUFFER cmdBuffer, XGL_PIPELINE_BIND_POINT pipelineBindPoint, XGL_PIPELINE_DELTA delta) { + synchAndDumpDot(); + nextTable.CmdBindPipelineDelta(cmdBuffer, pipelineBindPoint, delta); } XGL_LAYER_EXPORT void XGLAPI xglCmdBindDynamicStateObject(XGL_CMD_BUFFER cmdBuffer, XGL_STATE_BIND_POINT stateBindPoint, XGL_DYNAMIC_STATE_OBJECT state) { + synchAndDumpDot(); + setLastBoundDynamicState(state, stateBindPoint); nextTable.CmdBindDynamicStateObject(cmdBuffer, stateBindPoint, state); } XGL_LAYER_EXPORT void XGLAPI xglCmdBindDescriptorSet(XGL_CMD_BUFFER cmdBuffer, XGL_PIPELINE_BIND_POINT pipelineBindPoint, XGL_DESCRIPTOR_SET descriptorSet, const uint32_t* pUserData) { + synchAndDumpDot(); + // TODO : Improve this. Can track per-cmd buffer and store bind point and pUserData if (getSetNode(descriptorSet)) { if (dsUpdateActive(descriptorSet)) { diff --git a/tools/glave/src/glv_extensions/glvdebug_xgl/CMakeLists.txt b/tools/glave/src/glv_extensions/glvdebug_xgl/CMakeLists.txt index 3f60073..f9c8001 100644 --- a/tools/glave/src/glv_extensions/glvdebug_xgl/CMakeLists.txt +++ b/tools/glave/src/glv_extensions/glvdebug_xgl/CMakeLists.txt @@ -55,6 +55,7 @@ set(UI_HEADER_LIST glvdebug_xgl_qfile_model.h glvdebug_xgl_qgroupframesproxymodel.h ${SRC_DIR}/glvdebug/glvdebug_qgroupthreadsproxymodel.h + ${SRC_DIR}/glvdebug/glvdebug_qimageviewer.h ${SRC_DIR}/glvdebug/glvdebug_QTraceFileModel.h ${SRC_DIR}/glvdebug/glvdebug_QReplayWidget.h ${SRC_DIR}/glvdebug/glvdebug_QReplayWorker.h diff --git a/tools/glave/src/glv_extensions/glvdebug_xgl/glvdebug_xgl_qcontroller.cpp b/tools/glave/src/glv_extensions/glvdebug_xgl/glvdebug_xgl_qcontroller.cpp index e79e38e..5426fbd 100644 --- a/tools/glave/src/glv_extensions/glvdebug_xgl/glvdebug_xgl_qcontroller.cpp +++ b/tools/glave/src/glv_extensions/glvdebug_xgl/glvdebug_xgl_qcontroller.cpp @@ -30,6 +30,7 @@ extern "C" { #include "glvdebug_xgl_qcontroller.h" #include +#include #include #include #include @@ -38,7 +39,8 @@ extern "C" { #include "glvreplay_seq.h" glvdebug_xgl_QController::glvdebug_xgl_QController() - : m_pReplayWidget(NULL), + : m_pDrawStateDiagram(NULL), + m_pReplayWidget(NULL), m_pTraceFileModel(NULL) { initialize_default_settings(); @@ -121,8 +123,10 @@ void glvdebug_xgl_QController::updateCallTreeBasedOnSettings() void glvdebug_xgl_QController::setStateWidgetsEnabled(bool bEnabled) { - // TODO: enable or disable state widgets - // m_pWidget->setEnabled(bEnabled); + if(m_pDrawStateDiagram != NULL) + { + m_pDrawStateDiagram->setEnabled(bEnabled); + } } void glvdebug_xgl_QController::onReplayStarted() @@ -132,23 +136,28 @@ void glvdebug_xgl_QController::onReplayStarted() void glvdebug_xgl_QController::onReplayPaused(uint64_t packetIndex) { - // TODO: Get state data from XGL layers (if they are enabled) and use m_pView->add_custom_state_viewer(...) to add the necessary widgets to the UI. - // The widgets should be allocated here and kept as members variable, so that they can be made more dynamic as features are added. - // eg: - // if (m_pWidget == NULL) - // { - // bool bringToFront = false; - // m_pWidget = new QSomeKindOfNewXGLWidget(); - // m_pView->add_custom_state_viewer(m_pWidget, QString("Cool State Feature"), bringToFront); - // } - // - // // update the widget with the current state information - // m_pWidget->SomeKindOfStateSettingFunction(somePieceOfCoolState); - // - // otherwise, if that particular "cool state feature" is not applicable to the current API call, using the member variable allows us to hide it: - // m_pWidget->setVisible(false); - - setStateWidgetsEnabled(true); + if(m_pDrawStateDiagram == NULL) + { + m_pDrawStateDiagram = new glvdebug_qimageviewer; + if(m_pDrawStateDiagram != NULL) + { + m_pView->add_custom_state_viewer(m_pDrawStateDiagram, tr("Draw State Diagram"), false); + setStateWidgetsEnabled(false); + } + } + + if(m_pDrawStateDiagram != NULL) + { + // Convert the DOT to a png. + if(access( "/usr/bin/dot", X_OK) != -1) { + system("/usr/bin/dot pipeline_dump.dot -Tpng -o pipeline_dump.png"); + } + + if(m_pDrawStateDiagram->loadImage(tr("pipeline_dump.png"))) + { + setStateWidgetsEnabled(true); + } + } } void glvdebug_xgl_QController::onReplayContinued() @@ -226,6 +235,12 @@ void glvdebug_xgl_QController::UnloadTraceFile(void) m_pReplayWidget = NULL; } + if (m_pDrawStateDiagram != NULL) + { + delete m_pDrawStateDiagram; + m_pDrawStateDiagram = NULL; + } + // Clean up replayers if (m_pReplayers != NULL) { diff --git a/tools/glave/src/glv_extensions/glvdebug_xgl/glvdebug_xgl_qcontroller.h b/tools/glave/src/glv_extensions/glvdebug_xgl/glvdebug_xgl_qcontroller.h index 4c7d934..7b40b1e 100644 --- a/tools/glave/src/glv_extensions/glvdebug_xgl/glvdebug_xgl_qcontroller.h +++ b/tools/glave/src/glv_extensions/glvdebug_xgl/glvdebug_xgl_qcontroller.h @@ -27,10 +27,13 @@ #include "glv_trace_packet_identifiers.h" #include "glvdebug_xgl_qgroupframesproxymodel.h" #include "glvdebug_qgroupthreadsproxymodel.h" +#include "glvdebug_qimageviewer.h" #include "glvdebug_QReplayWidget.h" #include "glvdebug_QReplayWorker.h" #include "glvdebug_xgl_qfile_model.h" #include +#include +#include class glvdebug_xgl_QController : public glvdebug_QReplayWorker { @@ -62,6 +65,7 @@ protected slots: void onReplayFinished(); private: + glvdebug_qimageviewer* m_pDrawStateDiagram; glvdebug_QReplayWidget* m_pReplayWidget; glvdebug_xgl_QFileModel* m_pTraceFileModel; glvdebug_xgl_QGroupFramesProxyModel m_groupByFramesProxy; diff --git a/tools/glave/src/glvdebug/CMakeLists.txt b/tools/glave/src/glvdebug/CMakeLists.txt index abe786f..124f5c8 100755 --- a/tools/glave/src/glvdebug/CMakeLists.txt +++ b/tools/glave/src/glvdebug/CMakeLists.txt @@ -53,6 +53,7 @@ set(UI_HEADER_LIST glvdebug_qgeneratetracedialog.h glvdebug_qsettingsdialog.h glvdebug_qtimelineview.h + glvdebug_qimageviewer.h glvdebug_QReplayWidget.h glvdebug_QReplayWorker.h glvdebug_QTraceFileModel.h @@ -68,6 +69,7 @@ set(HEADER_LIST glvdebug_qgeneratetracedialog.h glvdebug_qsettingsdialog.h glvdebug_qtimelineview.h + glvdebug_qimageviewer.h glvdebug_QReplayWidget.h glvdebug_QReplayWorker.h glvdebug_QTraceFileModel.h diff --git a/tools/glave/src/glvdebug/glvdebug_qimageviewer.h b/tools/glave/src/glvdebug/glvdebug_qimageviewer.h new file mode 100644 index 0000000..9efd061 --- /dev/null +++ b/tools/glave/src/glvdebug/glvdebug_qimageviewer.h @@ -0,0 +1,215 @@ +/************************************************************************** + * + * Copyright 2014 Valve Software + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#ifndef _GLVDEBUG_QIMAGEVIEWER_H_ +#define _GLVDEBUG_QIMAGEVIEWER_H_ + +#include + +#include +#include +#include +#include +#include + +// Pretend an image is a QScrollArea with some some special event handling. +class glvdebug_qimageviewer : public QScrollArea +{ + Q_OBJECT +public: + explicit glvdebug_qimageviewer(QWidget* parent = 0) + : QScrollArea(parent), + m_pImageLabel(NULL), + m_pPanStart(0, 0), + m_pPan(false), + m_pAutoFit(false) + { + // Create a basic image viewer using a QLabel to display the image. + m_pImageLabel = new QLabel; + assert(m_pImageLabel != NULL); + + m_pImageLabel->setBackgroundRole(QPalette::Base); + m_pImageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + m_pImageLabel->setScaledContents(true); + + // The QLabel is embedded in a QScrollArea so the image can be panned. + this->setBackgroundRole(QPalette::Dark); + this->setWidget(m_pImageLabel); + } + + virtual ~glvdebug_qimageviewer() + { + if (m_pImageLabel != NULL) + { + delete m_pImageLabel; + m_pImageLabel = NULL; + } + } + + void mouseMoveEvent(QMouseEvent* event) + { + if(m_pPan) + { + this->horizontalScrollBar()->setValue(this->horizontalScrollBar()->value() - + (event->x() - m_pPanStart.x())); + this->verticalScrollBar()->setValue(this->verticalScrollBar()->value() - + (event->y() - m_pPanStart.y())); + m_pPanStart = event->pos(); + + event->accept(); + return; + } + + event->ignore(); + } + + void mousePressEvent(QMouseEvent* event) + { + if(event->button() == Qt::MiddleButton) + { + m_pPan = true; + setCursor(Qt::ClosedHandCursor); + m_pPanStart = event->pos(); + + event->accept(); + return; + } + + event->ignore(); + } + + void mouseReleaseEvent(QMouseEvent* event) + { + if(event->button() == Qt::MiddleButton) + { + m_pPan = false; + setCursor(Qt::ArrowCursor); + + event->accept(); + return; + } + + event->ignore(); + } + + void resizeEvent(QResizeEvent* event) + { + QSize const size = computeMinimumSize(); + m_pImageLabel->setMinimumSize(size); + + if(m_pAutoFit) + { + m_pImageLabel->resize(size); + } + + event->accept(); + } + + void wheelEvent(QWheelEvent* event) + { + if(event->orientation() == Qt::Vertical) + { + // Stop automatically resizing the image when zoom is requested. + m_pAutoFit = false; + + // Compute the scaling factor. + int const numDegrees = event->delta() / 8; + int const numSteps = numDegrees / 15; + double const factor = 1.0 + 0.1 * numSteps; + + m_pImageLabel->resize(m_pImageLabel->size() * factor); + + zoomScrollBar(this->horizontalScrollBar(), factor); + zoomScrollBar(this->verticalScrollBar(), factor); + + event->accept(); + return; + } + + event->ignore(); + } + + bool loadImage(QString const& fileName) + { + QFileInfo fileInfo(fileName); + if(!fileInfo.exists() || !fileInfo.isFile()) + { + return false; + } + + QImage image(fileName); + if(image.isNull()) + { + return false; + } + + m_pImageLabel->setPixmap(QPixmap::fromImage(image)); + m_pImageLabel->adjustSize(); + m_pImageLabel->setMaximumSize(image.size()); + + // Resize the image to the scroll area. + m_pAutoFit = true; + + return true; + } + +private: + QSize computeMinimumSize() const + { + if(m_pImageLabel->pixmap() == NULL) + { + return QSize(0, 0); + } + + double const aspect = m_pImageLabel->pixmap()->width() / + m_pImageLabel->pixmap()->height(); + if(aspect > 1.0) + { + int const minWidth = this->width() - 2 * this->frameWidth(); + int const minHeight = minWidth * 1.0 / aspect; + return QSize(minWidth, minHeight); + } + else + { + int const minHeight = this->height() - 2 * this->frameWidth(); + int const minWidth = minHeight * aspect; + return QSize(minWidth, minHeight); + } + } + + void zoomScrollBar(QScrollBar* scrollBar, double const& factor) + { + int const value = static_cast(factor * scrollBar->value() + + ((factor - 1.0) * scrollBar->pageStep() / 2)); + scrollBar->setValue(value); + } + + QLabel* m_pImageLabel; + QPoint m_pPanStart; + bool m_pPan; + bool m_pAutoFit; +}; + +#endif //_GLVDEBUG_QIMAGEVIEWER_H_ -- 2.7.4