diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index a12fd7e23..f62343873 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -472,7 +472,7 @@ BufferViewer *CaptureContext::meshPreview() if(m_MeshPreview) return m_MeshPreview; - m_MeshPreview = new BufferViewer(this, m_MainWindow); + m_MeshPreview = new BufferViewer(this, true, m_MainWindow); m_MeshPreview->setObjectName("meshPreview"); setupDockWindow(m_MeshPreview); diff --git a/qrenderdoc/Code/FormatElement.cpp b/qrenderdoc/Code/FormatElement.cpp index 7208eb9de..4686e7d9a 100644 --- a/qrenderdoc/Code/FormatElement.cpp +++ b/qrenderdoc/Code/FormatElement.cpp @@ -759,7 +759,7 @@ ShaderVariable FormatElement::GetShaderVar(const byte *&data, const byte *end) c return ret; } -uint32_t FormatElement::byteSize() +uint32_t FormatElement::byteSize() const { uint32_t vecSize = format.compByteWidth * format.compCount; diff --git a/qrenderdoc/Code/QRDUtils.h b/qrenderdoc/Code/QRDUtils.h index 0390c041f..f4d5c8fe6 100644 --- a/qrenderdoc/Code/QRDUtils.h +++ b/qrenderdoc/Code/QRDUtils.h @@ -373,7 +373,7 @@ struct FormatElement QString ElementString(const QVariant &var); - uint32_t byteSize(); + uint32_t byteSize() const; QString name; int buffer; diff --git a/qrenderdoc/Windows/BufferViewer.cpp b/qrenderdoc/Windows/BufferViewer.cpp index 924df21af..51dddca53 100644 --- a/qrenderdoc/Windows/BufferViewer.cpp +++ b/qrenderdoc/Windows/BufferViewer.cpp @@ -325,6 +325,7 @@ public: void endReset() { cacheColumns(); + m_ColumnCount = columnLookup.count() + reservedColumnCount(); emit endResetModel(); } QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override @@ -339,7 +340,7 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const override { return numRows; } int columnCount(const QModelIndex &parent = QModelIndex()) const override { - return columnLookup.count() + 2; + return m_ColumnCount; } Qt::ItemFlags flags(const QModelIndex &index) const override { @@ -351,13 +352,13 @@ public: QVariant headerData(int section, Qt::Orientation orientation, int role) const override { - if(section < columnCount() && orientation == Qt::Horizontal && role == Qt::DisplayRole) + if(section < m_ColumnCount && orientation == Qt::Horizontal && role == Qt::DisplayRole) { - if(section == 0) + if(section == 0 && meshView) { return "VTX"; } - else if(section == 1) + else if(section == 1 && meshView) { return "IDX"; } @@ -387,7 +388,7 @@ public: opt.features |= QStyleOptionViewItem::HasDisplay; // pad these columns to allow for sufficiently wide data - if(index.column() < 2) + if(index.column() < 2 && meshView) opt.text = "999999"; else opt.text = data(index).toString(); @@ -402,9 +403,9 @@ public: uint32_t row = index.row(); int col = index.column(); - if(col >= 0 && col < columnCount() && row < numRows) + if(col >= 0 && col < m_ColumnCount && row < numRows) { - if(col == 0) + if(col == 0 && meshView) return row; uint32_t idx = row; @@ -418,7 +419,7 @@ public: idx = *(uint32_t *)idxData; } - if(col == 1) + if(col == 1 && meshView) return idx; const FormatElement &el = columnForIndex(col); @@ -510,6 +511,7 @@ public: uint32_t curInstance = 0; uint32_t numRows = 0; + bool meshView = true; BufferData indices; QList columns; QList buffers; @@ -523,9 +525,14 @@ private: // { 0, 1, 2, 3, 0, 1, 2, 0 }; QVector columnLookup; QVector componentLookup; + int m_ColumnCount; - const FormatElement &columnForIndex(int col) const { return columns[columnLookup[col - 2]]; } - int componentForIndex(int col) const { return componentLookup[col - 2]; } + int reservedColumnCount() const { return (meshView ? 2 : 0); } + const FormatElement &columnForIndex(int col) const + { + return columns[columnLookup[col - reservedColumnCount()]]; + } + int componentForIndex(int col) const { return componentLookup[col - reservedColumnCount()]; } void cacheColumns() { columnLookup.clear(); @@ -575,7 +582,7 @@ private: } }; -BufferViewer::BufferViewer(CaptureContext *ctx, QWidget *parent) +BufferViewer::BufferViewer(CaptureContext *ctx, bool meshview, QWidget *parent) : QFrame(parent), ui(new Ui::BufferViewer), m_Ctx(ctx) { ui->setupUi(this); @@ -588,17 +595,11 @@ BufferViewer::BufferViewer(CaptureContext *ctx, QWidget *parent) m_Arcball = new ArcballWrapper(); m_CurrentCamera = m_Arcball; + m_Output = NULL; + + memset(&m_Config, 0, sizeof(m_Config)); m_Config.type = eMeshDataStage_VSIn; - m_Config.ortho = false; - m_Config.showPrevInstances = false; - m_Config.showAllInstances = false; - m_Config.showWholePass = false; - m_Config.curInstance = 0; - m_Config.showBBox = false; - m_Config.solidShadeMode = eShade_None; m_Config.wireframeDraw = true; - memset(&m_Config.position, 0, sizeof(m_Config.position)); - memset(&m_Config.second, 0, sizeof(m_Config.second)); ui->outputTabs->setCurrentIndex(0); m_CurStage = eMeshDataStage_VSIn; @@ -607,46 +608,16 @@ BufferViewer::BufferViewer(CaptureContext *ctx, QWidget *parent) ui->vsoutData->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); ui->gsoutData->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); - setWindowTitle(tr("Mesh Output")); + m_ModelVSIn->meshView = m_ModelVSOut->meshView = m_ModelGSOut->meshView = m_MeshView = meshview; - ui->formatSpecifier->setVisible(false); - ui->cameraControlsGroup->setVisible(false); - - ui->outputTabs->setWindowTitle(tr("Preview")); - ui->dockarea->addToolWindow(ui->outputTabs, ToolWindowManager::EmptySpace); - ui->dockarea->setToolWindowProperties(ui->outputTabs, ToolWindowManager::HideCloseButton); - - ui->vsinData->setWindowTitle(tr("VS Input")); - ui->dockarea->addToolWindow( - ui->vsinData, ToolWindowManager::AreaReference(ToolWindowManager::TopOf, - ui->dockarea->areaOf(ui->outputTabs), 0.5f)); - ui->dockarea->setToolWindowProperties(ui->vsinData, ToolWindowManager::HideCloseButton); - - ui->vsoutData->setWindowTitle(tr("VS Output")); - ui->dockarea->addToolWindow( - ui->vsoutData, ToolWindowManager::AreaReference(ToolWindowManager::RightOf, - ui->dockarea->areaOf(ui->vsinData), 0.5f)); - ui->dockarea->setToolWindowProperties(ui->vsoutData, ToolWindowManager::HideCloseButton); - - ui->gsoutData->setWindowTitle(tr("GS/DS Output")); - ui->dockarea->addToolWindow( - ui->gsoutData, ToolWindowManager::AreaReference(ToolWindowManager::AddTo, - ui->dockarea->areaOf(ui->vsoutData), 0.5f)); - ui->dockarea->setToolWindowProperties(ui->gsoutData, ToolWindowManager::HideCloseButton); - - ToolWindowManager::raiseToolWindow(ui->vsoutData); + if(meshview) + SetupMeshView(); + else + SetupRawView(); ui->dockarea->setAllowFloatingWindow(false); ui->dockarea->setRubberBandLineWidth(50); - QVBoxLayout *vertical = new QVBoxLayout(this); - - vertical->setSpacing(3); - vertical->setContentsMargins(0, 0, 0, 0); - - vertical->addWidget(ui->meshToolbar); - vertical->addWidget(ui->dockarea); - ui->controlType->addItems({tr("Arcball"), tr("WASD")}); ui->controlType->adjustSize(); @@ -691,15 +662,92 @@ BufferViewer::BufferViewer(CaptureContext *ctx, QWidget *parent) QObject::connect(ui->matrixType, OverloadedSlot::of(&QComboBox::currentIndexChanged), [this](int) { camGuess_changed(0.0); }); + Reset(); + + m_Ctx->AddLogViewer(this); +} + +void BufferViewer::SetupRawView() +{ + ui->formatSpecifier->setVisible(true); + ui->outputTabs->setVisible(false); + ui->vsoutData->setVisible(false); + ui->gsoutData->setVisible(false); + + // hide buttons we don't want in the toolbar + ui->syncViews->setVisible(false); + ui->offsetLine->setVisible(false); + ui->instanceLabel->setVisible(false); + ui->instance->setVisible(false); + ui->rowOffsetLabel->setVisible(false); + ui->rowOffset->setVisible(false); + + ui->vsinData->setWindowTitle(tr("Buffer Contents")); + ui->dockarea->addToolWindow(ui->vsinData, ToolWindowManager::EmptySpace); + ui->dockarea->setToolWindowProperties(ui->vsinData, ToolWindowManager::HideCloseButton); + + ui->formatSpecifier->setWindowTitle(tr("Buffer Format")); + ui->dockarea->addToolWindow(ui->formatSpecifier, ToolWindowManager::AreaReference( + ToolWindowManager::BottomOf, + ui->dockarea->areaOf(ui->vsinData), 0.5f)); + ui->dockarea->setToolWindowProperties(ui->formatSpecifier, ToolWindowManager::HideCloseButton); + + QObject::connect(ui->formatSpecifier, &BufferFormatSpecifier::processFormat, this, + &BufferViewer::processFormat); + + QVBoxLayout *vertical = new QVBoxLayout(this); + + vertical->setSpacing(3); + vertical->setContentsMargins(0, 0, 0, 0); + + vertical->addWidget(ui->meshToolbar); + vertical->addWidget(ui->dockarea); +} + +void BufferViewer::SetupMeshView() +{ + setWindowTitle(tr("Mesh Output")); + + ui->formatSpecifier->setVisible(false); + ui->cameraControlsGroup->setVisible(false); + + ui->outputTabs->setWindowTitle(tr("Preview")); + ui->dockarea->addToolWindow(ui->outputTabs, ToolWindowManager::EmptySpace); + ui->dockarea->setToolWindowProperties(ui->outputTabs, ToolWindowManager::HideCloseButton); + + ui->vsinData->setWindowTitle(tr("VS Input")); + ui->dockarea->addToolWindow( + ui->vsinData, ToolWindowManager::AreaReference(ToolWindowManager::TopOf, + ui->dockarea->areaOf(ui->outputTabs), 0.5f)); + ui->dockarea->setToolWindowProperties(ui->vsinData, ToolWindowManager::HideCloseButton); + + ui->vsoutData->setWindowTitle(tr("VS Output")); + ui->dockarea->addToolWindow( + ui->vsoutData, ToolWindowManager::AreaReference(ToolWindowManager::RightOf, + ui->dockarea->areaOf(ui->vsinData), 0.5f)); + ui->dockarea->setToolWindowProperties(ui->vsoutData, ToolWindowManager::HideCloseButton); + + ui->gsoutData->setWindowTitle(tr("GS/DS Output")); + ui->dockarea->addToolWindow( + ui->gsoutData, ToolWindowManager::AreaReference(ToolWindowManager::AddTo, + ui->dockarea->areaOf(ui->vsoutData), 0.5f)); + ui->dockarea->setToolWindowProperties(ui->gsoutData, ToolWindowManager::HideCloseButton); + + ToolWindowManager::raiseToolWindow(ui->vsoutData); + + QVBoxLayout *vertical = new QVBoxLayout(this); + + vertical->setSpacing(3); + vertical->setContentsMargins(0, 0, 0, 0); + + vertical->addWidget(ui->meshToolbar); + vertical->addWidget(ui->dockarea); + QTimer *renderTimer = new QTimer(this); QObject::connect(renderTimer, &QTimer::timeout, this, &BufferViewer::render_timer); renderTimer->setSingleShot(false); renderTimer->setInterval(10); renderTimer->start(); - - Reset(); - - m_Ctx->AddLogViewer(this); } BufferViewer::~BufferViewer() @@ -717,7 +765,9 @@ BufferViewer::~BufferViewer() delete m_Arcball; delete m_Flycam; - m_Ctx->windowClosed(this); + if(m_MeshView) + m_Ctx->windowClosed(this); + m_Ctx->RemoveLogViewer(this); delete ui; } @@ -726,6 +776,9 @@ void BufferViewer::OnLogfileLoaded() { Reset(); + if(!m_MeshView) + return; + WId renderID = ui->render->winId(); m_Ctx->Renderer()->BlockInvoke([renderID, this](IReplayRenderer *r) { @@ -752,15 +805,18 @@ void BufferViewer::OnEventChanged(uint32_t eventID) int vsoutHoriz = ui->vsoutData->horizontalScrollBar()->value(); int gsoutHoriz = ui->gsoutData->horizontalScrollBar()->value(); - ClearModels(); + if(m_MeshView) + { + ClearModels(); - memset(&m_VSIn, 0, sizeof(m_VSIn)); - memset(&m_PostVS, 0, sizeof(m_PostVS)); - memset(&m_PostGS, 0, sizeof(m_PostGS)); + memset(&m_VSIn, 0, sizeof(m_VSIn)); + memset(&m_PostVS, 0, sizeof(m_PostVS)); + memset(&m_PostGS, 0, sizeof(m_PostGS)); - CalcColumnWidth(); + CalcColumnWidth(); - ClearModels(); + ClearModels(); + } EnableCameraGuessControls(); @@ -774,14 +830,255 @@ void BufferViewer::OnEventChanged(uint32_t eventID) const FetchDrawcall *draw = m_Ctx->CurDrawcall(); - QVector vinputs = m_Ctx->CurPipelineState.GetVertexInputs(); - ui->instance->setEnabled(draw && draw->numInstances > 1); if(!ui->instance->isEnabled()) ui->instance->setValue(0); ui->instance->setMaximum(qMax(0, int(draw->numInstances) - 1)); + if(m_MeshView) + ConfigureMeshColumns(); + + m_Ctx->Renderer()->AsyncInvoke([this, vsinHoriz, vsoutHoriz, gsoutHoriz](IReplayRenderer *r) { + + if(m_MeshView) + { + RT_FetchMeshData(r); + } + else + { + BufferData buf = {}; + rdctype::array data; + if(m_IsBuffer) + { + uint64_t len = m_ByteSize; + if(len == UINT64_MAX) + len = 0; + + r->GetBufferData(m_BufferID, m_ByteOffset, len, &data); + } + else + { + r->GetTextureData(m_BufferID, m_TexArrayIdx, m_TexMip, &data); + } + + buf.data = new byte[data.count]; + memcpy(buf.data, data.elems, data.count); + buf.end = buf.data + data.count; + + // calculate tight stride + buf.stride = 0; + for(const FormatElement &el : m_ModelVSIn->columns) + buf.stride += el.byteSize(); + + buf.stride = qMax((size_t)1, buf.stride); + + m_ModelVSIn->numRows = uint32_t((data.count + buf.stride - 1) / buf.stride); + + m_ModelVSIn->buffers.push_back(buf); + } + + UpdateMeshConfig(); + + RT_UpdateAndDisplay(r); + + GUIInvoke::call([this, vsinHoriz, vsoutHoriz, gsoutHoriz] { + m_ModelVSIn->endReset(); + m_ModelVSOut->endReset(); + m_ModelGSOut->endReset(); + + ApplyColumnWidths(m_ModelVSIn->columnCount(), ui->vsinData); + ApplyColumnWidths(m_ModelVSOut->columnCount(), ui->vsoutData); + ApplyColumnWidths(m_ModelGSOut->columnCount(), ui->gsoutData); + + int numRows = qMax(qMax(m_ModelVSIn->numRows, m_ModelVSOut->numRows), m_ModelGSOut->numRows); + + ui->rowOffset->setMaximum(qMax(0, numRows - 1)); + + ScrollToRow(m_ModelVSIn, ui->rowOffset->value()); + ScrollToRow(m_ModelVSOut, ui->rowOffset->value()); + ScrollToRow(m_ModelGSOut, ui->rowOffset->value()); + + ui->vsinData->horizontalScrollBar()->setValue(vsinHoriz); + ui->vsoutData->horizontalScrollBar()->setValue(vsoutHoriz); + ui->gsoutData->horizontalScrollBar()->setValue(gsoutHoriz); + }); + }); +} + +void BufferViewer::RT_FetchMeshData(IReplayRenderer *r) +{ + const FetchDrawcall *draw = m_Ctx->CurDrawcall(); + + ResourceId ib; + uint64_t ioffset = 0; + m_Ctx->CurPipelineState.GetIBuffer(ib, ioffset); + + QVector vbs = m_Ctx->CurPipelineState.GetVBuffers(); + + rdctype::array idata; + if(ib != ResourceId() && draw) + r->GetBufferData(ib, ioffset + draw->indexOffset * draw->indexByteWidth, + draw->numIndices * draw->indexByteWidth, &idata); + + uint32_t *indices = NULL; + m_ModelVSIn->indices = BufferData(); + if(draw && draw->indexByteWidth != 0 && idata.count != 0) + { + indices = new uint32_t[draw->numIndices]; + m_ModelVSIn->indices.data = (byte *)indices; + m_ModelVSIn->indices.end = (byte *)(indices + draw->numIndices); + } + + uint32_t maxIndex = qMax(1U, draw->numIndices) - 1; + + if(idata.count > 0) + { + maxIndex = 0; + if(draw->indexByteWidth == 1) + { + for(size_t i = 0; i < (size_t)idata.count && (uint32_t)i < draw->numIndices; i++) + { + indices[i] = (uint32_t)idata.elems[i]; + maxIndex = qMax(maxIndex, indices[i]); + } + } + else if(draw->indexByteWidth == 2) + { + uint16_t *src = (uint16_t *)idata.elems; + for(size_t i = 0; + i < (size_t)idata.count / sizeof(uint16_t) && (uint32_t)i < draw->numIndices; i++) + { + indices[i] = (uint32_t)src[i]; + maxIndex = qMax(maxIndex, indices[i]); + } + } + else if(draw->indexByteWidth == 4) + { + memcpy(indices, idata.elems, qMin((size_t)idata.count, draw->numIndices * sizeof(uint32_t))); + + for(uint32_t i = 0; i < draw->numIndices; i++) + maxIndex = qMax(maxIndex, indices[i]); + } + } + + int vbIdx = 0; + for(BoundVBuffer vb : vbs) + { + bool used = false; + bool pi = false; + bool pv = false; + + for(const FormatElement &col : m_ModelVSIn->columns) + { + if(col.buffer == vbIdx) + { + used = true; + + if(col.perinstance) + pi = true; + else + pv = true; + } + } + + vbIdx++; + + uint32_t maxIdx = 0; + uint32_t offset = 0; + + if(used && draw) + { + if(pi) + { + maxIdx = qMax(1U, draw->numInstances) - 1; + offset = draw->instanceOffset; + } + if(pv) + { + maxIdx = qMax(maxIndex, maxIdx); + offset = draw->vertexOffset; + + if(draw->baseVertex > 0) + maxIdx += (uint32_t)draw->baseVertex; + } + + if(pi && pv) + qCritical() << "Buffer used for both instance and vertex rendering!"; + } + + BufferData buf = {}; + if(used) + { + rdctype::array bufdata; + r->GetBufferData(vb.Buffer, vb.ByteOffset + offset * vb.ByteStride, + (maxIdx + 1) * vb.ByteStride, &bufdata); + + buf.data = new byte[bufdata.count]; + memcpy(buf.data, bufdata.elems, bufdata.count); + buf.end = buf.data + bufdata.count; + buf.stride = vb.ByteStride; + } + m_ModelVSIn->buffers.push_back(buf); + } + + r->GetPostVSData(m_Config.curInstance, eMeshDataStage_VSOut, &m_PostVS); + + m_ModelVSOut->numRows = m_PostVS.numVerts; + + if(m_PostVS.idxbuf != ResourceId()) + r->GetBufferData(m_PostVS.idxbuf, ioffset + draw->indexOffset * draw->indexByteWidth, + draw->numIndices * draw->indexByteWidth, &idata); + + indices = NULL; + m_ModelVSOut->indices = BufferData(); + if(draw && draw->indexByteWidth != 0 && idata.count != 0) + { + indices = new uint32_t[draw->numIndices]; + m_ModelVSOut->indices.data = (byte *)indices; + m_ModelVSOut->indices.end = (byte *)(indices + draw->numIndices); + } + + if(idata.count > 0) + { + if(draw->indexByteWidth == 1) + { + for(size_t i = 0; i < (size_t)idata.count && (uint32_t)i < draw->numIndices; i++) + indices[i] = (uint32_t)idata.elems[i]; + } + else if(draw->indexByteWidth == 2) + { + uint16_t *src = (uint16_t *)idata.elems; + for(size_t i = 0; + i < (size_t)idata.count / sizeof(uint16_t) && (uint32_t)i < draw->numIndices; i++) + indices[i] = (uint32_t)src[i]; + } + else if(draw->indexByteWidth == 4) + { + memcpy(indices, idata.elems, qMin((size_t)idata.count, draw->numIndices * sizeof(uint32_t))); + } + } + + if(m_PostVS.buf != ResourceId()) + { + BufferData postvs = {}; + rdctype::array bufdata; + r->GetBufferData(m_PostVS.buf, m_PostVS.offset, 0, &bufdata); + + postvs.data = new byte[bufdata.count]; + memcpy(postvs.data, bufdata.elems, bufdata.count); + postvs.end = postvs.data + bufdata.count; + postvs.stride = m_PostVS.stride; + m_ModelVSOut->buffers.push_back(postvs); + } +} + +void BufferViewer::ConfigureMeshColumns() +{ + const FetchDrawcall *draw = m_Ctx->CurDrawcall(); + + QVector vinputs = m_Ctx->CurPipelineState.GetVertexInputs(); + m_ModelVSIn->columns.reserve(vinputs.count()); for(const VertexInputAttribute &a : vinputs) @@ -915,199 +1212,20 @@ void BufferViewer::OnEventChanged(uint32_t eventID) m_ModelVSOut->columns.insert(0, m_ModelVSOut->columns.takeAt(posidx)); } } - - m_Ctx->Renderer()->AsyncInvoke([this, draw, vbs, ib, ioffset, vsinHoriz, vsoutHoriz, - gsoutHoriz](IReplayRenderer *r) { - - rdctype::array idata; - if(ib != ResourceId() && draw) - r->GetBufferData(ib, ioffset + draw->indexOffset * draw->indexByteWidth, - draw->numIndices * draw->indexByteWidth, &idata); - - uint32_t *indices = NULL; - m_ModelVSIn->indices = BufferData(); - if(draw && draw->indexByteWidth != 0 && idata.count != 0) - { - indices = new uint32_t[draw->numIndices]; - m_ModelVSIn->indices.data = (byte *)indices; - m_ModelVSIn->indices.end = (byte *)(indices + draw->numIndices); - } - - uint32_t maxIndex = qMax(1U, draw->numIndices) - 1; - - if(idata.count > 0) - { - maxIndex = 0; - if(draw->indexByteWidth == 1) - { - for(size_t i = 0; i < (size_t)idata.count && (uint32_t)i < draw->numIndices; i++) - { - indices[i] = (uint32_t)idata.elems[i]; - maxIndex = qMax(maxIndex, indices[i]); - } - } - else if(draw->indexByteWidth == 2) - { - uint16_t *src = (uint16_t *)idata.elems; - for(size_t i = 0; - i < (size_t)idata.count / sizeof(uint16_t) && (uint32_t)i < draw->numIndices; i++) - { - indices[i] = (uint32_t)src[i]; - maxIndex = qMax(maxIndex, indices[i]); - } - } - else if(draw->indexByteWidth == 4) - { - memcpy(indices, idata.elems, qMin((size_t)idata.count, draw->numIndices * sizeof(uint32_t))); - - for(uint32_t i = 0; i < draw->numIndices; i++) - maxIndex = qMax(maxIndex, indices[i]); - } - } - - int vbIdx = 0; - for(BoundVBuffer vb : vbs) - { - bool used = false; - bool pi = false; - bool pv = false; - - for(const FormatElement &col : m_ModelVSIn->columns) - { - if(col.buffer == vbIdx) - { - used = true; - - if(col.perinstance) - pi = true; - else - pv = true; - } - } - - vbIdx++; - - uint32_t maxIdx = 0; - uint32_t offset = 0; - - if(used && draw) - { - if(pi) - { - maxIdx = qMax(1U, draw->numInstances) - 1; - offset = draw->instanceOffset; - } - if(pv) - { - maxIdx = qMax(maxIndex, maxIdx); - offset = draw->vertexOffset; - - if(draw->baseVertex > 0) - maxIdx += (uint32_t)draw->baseVertex; - } - - if(pi && pv) - qCritical() << "Buffer used for both instance and vertex rendering!"; - } - - BufferData buf = {}; - if(used) - { - rdctype::array data; - r->GetBufferData(vb.Buffer, vb.ByteOffset + offset * vb.ByteStride, - (maxIdx + 1) * vb.ByteStride, &data); - - buf.data = new byte[data.count]; - memcpy(buf.data, data.elems, data.count); - buf.end = buf.data + data.count; - buf.stride = vb.ByteStride; - } - m_ModelVSIn->buffers.push_back(buf); - } - - r->GetPostVSData(m_Config.curInstance, eMeshDataStage_VSOut, &m_PostVS); - - m_ModelVSOut->numRows = m_PostVS.numVerts; - - if(m_PostVS.idxbuf != ResourceId()) - r->GetBufferData(m_PostVS.idxbuf, ioffset + draw->indexOffset * draw->indexByteWidth, - draw->numIndices * draw->indexByteWidth, &idata); - - indices = NULL; - m_ModelVSOut->indices = BufferData(); - if(draw && draw->indexByteWidth != 0 && idata.count != 0) - { - indices = new uint32_t[draw->numIndices]; - m_ModelVSOut->indices.data = (byte *)indices; - m_ModelVSOut->indices.end = (byte *)(indices + draw->numIndices); - } - - if(idata.count > 0) - { - if(draw->indexByteWidth == 1) - { - for(size_t i = 0; i < (size_t)idata.count && (uint32_t)i < draw->numIndices; i++) - indices[i] = (uint32_t)idata.elems[i]; - } - else if(draw->indexByteWidth == 2) - { - uint16_t *src = (uint16_t *)idata.elems; - for(size_t i = 0; - i < (size_t)idata.count / sizeof(uint16_t) && (uint32_t)i < draw->numIndices; i++) - indices[i] = (uint32_t)src[i]; - } - else if(draw->indexByteWidth == 4) - { - memcpy(indices, idata.elems, qMin((size_t)idata.count, draw->numIndices * sizeof(uint32_t))); - } - } - - if(m_PostVS.buf != ResourceId()) - { - BufferData postvs = {}; - rdctype::array data; - r->GetBufferData(m_PostVS.buf, m_PostVS.offset, 0, &data); - - postvs.data = new byte[data.count]; - memcpy(postvs.data, data.elems, data.count); - postvs.end = postvs.data + data.count; - postvs.stride = m_PostVS.stride; - m_ModelVSOut->buffers.push_back(postvs); - } - - UpdateMeshConfig(); - - RT_UpdateAndDisplay(r); - - GUIInvoke::call([this, vsinHoriz, vsoutHoriz, gsoutHoriz] { - m_ModelVSIn->endReset(); - m_ModelVSOut->endReset(); - - ApplyColumnWidths(m_ModelVSIn->columnCount(), ui->vsinData); - ApplyColumnWidths(m_ModelVSOut->columnCount(), ui->vsoutData); - ApplyColumnWidths(m_ModelGSOut->columnCount(), ui->gsoutData); - - int numRows = qMax(qMax(m_ModelVSIn->numRows, m_ModelVSOut->numRows), m_ModelGSOut->numRows); - - ui->rowOffset->setMaximum(qMax(0, numRows - 1)); - - ScrollToRow(m_ModelVSIn, ui->rowOffset->value()); - ScrollToRow(m_ModelVSOut, ui->rowOffset->value()); - ScrollToRow(m_ModelGSOut, ui->rowOffset->value()); - - ui->vsinData->horizontalScrollBar()->setValue(vsinHoriz); - ui->vsoutData->horizontalScrollBar()->setValue(vsoutHoriz); - ui->gsoutData->horizontalScrollBar()->setValue(gsoutHoriz); - }); - }); } void BufferViewer::ApplyColumnWidths(int numColumns, RDTableView *view) { - view->setColumnWidth(0, m_IdxColWidth); - view->setColumnWidth(1, m_IdxColWidth); + int start = 0; - for(int i = 2; i < numColumns; i++) + if(m_MeshView) + { + view->setColumnWidth(0, m_IdxColWidth); + view->setColumnWidth(1, m_IdxColWidth); + start = 2; + } + + for(int i = start; i < numColumns; i++) view->setColumnWidth(i, m_DataColWidth); } @@ -1185,6 +1303,41 @@ void BufferViewer::ScrollToRow(BufferItemModel *model, int row) model->view->selectRow(row); } +void BufferViewer::ViewBuffer(uint64_t byteOffset, uint64_t byteSize, ResourceId id, + const QString &format) +{ + if(!m_Ctx->LogLoaded()) + return; + + m_IsBuffer = true; + m_ByteOffset = byteOffset; + m_ByteSize = byteSize; + m_BufferID = id; + + FetchBuffer *buf = m_Ctx->GetBuffer(id); + if(buf) + setWindowTitle(ToQStr(buf->name) + " - Contents"); + + processFormat(format); +} + +void BufferViewer::ViewTexture(uint32_t arrayIdx, uint32_t mip, ResourceId id, const QString &format) +{ + if(!m_Ctx->LogLoaded()) + return; + + m_IsBuffer = false; + m_TexArrayIdx = arrayIdx; + m_TexMip = mip; + m_BufferID = id; + + FetchTexture *tex = m_Ctx->GetTexture(id); + if(tex) + setWindowTitle(ToQStr(tex->name) + " - Contents"); + + processFormat(format); +} + void BufferViewer::render_mouseWheel(QWheelEvent *e) { if(m_CurrentCamera) @@ -1337,62 +1490,54 @@ void BufferViewer::CalcColumnWidth() floatFmt.compType = eCompType_UInt; floatFmt.compCount = 1; - FormatElement floatEl("ColumnSizeTest", 0, 0, false, 1, false, 1, floatFmt, false); - FormatElement xintEl("ColumnSizeTest", 1, 0, false, 1, false, 1, intFmt, true); - FormatElement uintEl("ColumnSizeTest", 2, 0, false, 1, false, 1, intFmt, false); + FormatElement("ColumnSizeTest", 0, 0, false, 1, false, 1, floatFmt, false); + FormatElement("ColumnSizeTest", 0, 0, false, 1, false, 1, intFmt, true); + FormatElement("ColumnSizeTest", 0, 0, false, 1, false, 1, intFmt, false); m_ModelVSIn->columns.clear(); - m_ModelVSIn->columns.push_back(floatEl); - m_ModelVSIn->columns.push_back(xintEl); - m_ModelVSIn->columns.push_back(uintEl); + m_ModelVSIn->columns.push_back( + FormatElement("ColumnSizeTest", 0, 0, false, 1, false, 1, floatFmt, false)); + m_ModelVSIn->columns.push_back( + FormatElement("ColumnSizeTest", 0, 4, false, 1, false, 1, floatFmt, false)); + m_ModelVSIn->columns.push_back( + FormatElement("ColumnSizeTest", 0, 8, false, 1, false, 1, floatFmt, false)); + m_ModelVSIn->columns.push_back( + FormatElement("ColumnSizeTest", 0, 12, false, 1, false, 1, intFmt, true)); + m_ModelVSIn->columns.push_back( + FormatElement("ColumnSizeTest", 0, 16, false, 1, false, 1, intFmt, false)); - m_ModelVSIn->numRows = 4; + m_ModelVSIn->numRows = 2; m_ModelVSIn->indices.stride = sizeof(uint32_t); - m_ModelVSIn->indices.data = new byte[sizeof(uint32_t) * 4]; - m_ModelVSIn->indices.end = m_ModelVSIn->indices.data + sizeof(uint32_t) * 4; + m_ModelVSIn->indices.data = new byte[sizeof(uint32_t) * 2]; + m_ModelVSIn->indices.end = m_ModelVSIn->indices.data + sizeof(uint32_t) * 2; uint32_t *indices = (uint32_t *)m_ModelVSIn->indices.data; indices[0] = 0; - indices[1] = 1; - indices[2] = 2; - indices[3] = 1000000; + indices[1] = 1000000; m_ModelVSIn->buffers.clear(); + struct TestData + { + float f[3]; + uint32_t ui[3]; + }; + BufferData bufdata; - bufdata.stride = sizeof(float); - bufdata.data = new byte[sizeof(float) * 3]; - bufdata.end = m_ModelVSIn->indices.data + sizeof(float) * 3; + bufdata.stride = sizeof(TestData); + bufdata.data = new byte[sizeof(TestData)]; + bufdata.end = m_ModelVSIn->indices.data + sizeof(TestData); m_ModelVSIn->buffers.push_back(bufdata); - float *floats = (float *)bufdata.data; + TestData *test = (TestData *)bufdata.data; - floats[0] = 1.0f; - floats[1] = 1.2345e-20f; - floats[2] = 123456.7890123456789f; + test->f[0] = 1.0f; + test->f[1] = 1.2345e-20f; + test->f[2] = 123456.7890123456789f; - bufdata.stride = sizeof(uint32_t); - bufdata.data = new byte[sizeof(uint32_t) * 3]; - bufdata.end = m_ModelVSIn->indices.data + sizeof(uint32_t) * 3; - m_ModelVSIn->buffers.push_back(bufdata); - - uint32_t *xints = (uint32_t *)bufdata.data; - - xints[0] = 0; - xints[1] = 0x12345678; - xints[2] = 0xffffffff; - - bufdata.stride = sizeof(uint32_t); - bufdata.data = new byte[sizeof(uint32_t) * 3]; - bufdata.end = m_ModelVSIn->indices.data + sizeof(uint32_t) * 3; - m_ModelVSIn->buffers.push_back(bufdata); - - uint32_t *uints = (uint32_t *)bufdata.data; - - uints[0] = 0; - uints[1] = 0x12345678; - uints[2] = 0xffffffff; + test->ui[1] = 0x12345678; + test->ui[2] = 0xffffffff; m_ModelVSIn->endReset(); @@ -1400,12 +1545,19 @@ void BufferViewer::CalcColumnWidth() ui->vsinData->resizeColumnsToContents(); // index column - m_IdxColWidth = ui->vsinData->columnWidth(1); + int col = 0; + if(m_MeshView) + { + m_IdxColWidth = ui->vsinData->columnWidth(1); + col = 2; + } - int floatColWidth = ui->vsinData->columnWidth(2); - int xintColWidth = ui->vsinData->columnWidth(2); - int uintColWidth = ui->vsinData->columnWidth(3); - m_DataColWidth = qMax(floatColWidth, qMax(xintColWidth, uintColWidth)); + m_DataColWidth = 10; + for(int c = 0; c < 5; c++) + { + int colWidth = ui->vsinData->columnWidth(col + c); + m_DataColWidth = qMax(m_DataColWidth, colWidth); + } } void BufferViewer::data_selected(const QItemSelection &selected, const QItemSelection &deselected) @@ -1468,6 +1620,23 @@ void BufferViewer::camGuess_changed(double value) INVOKE_MEMFN(RT_UpdateAndDisplay); } +void BufferViewer::processFormat(const QString &format) +{ + QString errors; + + Reset(); + + CalcColumnWidth(); + + ClearModels(); + + m_ModelVSIn->columns = FormatElement::ParseFormatString(format, 0, true, errors); + + ui->formatSpecifier->setErrors(errors); + + OnEventChanged(m_Ctx->CurEvent()); +} + void BufferViewer::SyncViews(RDTableView *primary, bool selection, bool scroll) { if(!ui->syncViews->isChecked()) diff --git a/qrenderdoc/Windows/BufferViewer.h b/qrenderdoc/Windows/BufferViewer.h index b9ed9d8b8..97bfccc56 100644 --- a/qrenderdoc/Windows/BufferViewer.h +++ b/qrenderdoc/Windows/BufferViewer.h @@ -43,14 +43,19 @@ class BufferViewer : public QFrame, public ILogViewerForm Q_OBJECT public: - explicit BufferViewer(CaptureContext *ctx, QWidget *parent = 0); + explicit BufferViewer(CaptureContext *ctx, bool meshview, QWidget *parent = 0); ~BufferViewer(); + void ViewBuffer(uint64_t byteOffset, uint64_t byteSize, ResourceId id, const QString &format = ""); + void ViewTexture(uint32_t arrayIdx, uint32_t mip, ResourceId id, const QString &format = ""); + void OnLogfileLoaded(); void OnLogfileClosed(); void OnSelectedEventChanged(uint32_t eventID) {} void OnEventChanged(uint32_t eventID); + void RT_FetchMeshData(IReplayRenderer *r); + private slots: // automatic slots void on_outputTabs_currentChanged(int index); @@ -80,6 +85,8 @@ private slots: void data_scrolled(int scroll); void camGuess_changed(double value); + void processFormat(const QString &format); + private: Ui::BufferViewer *ui; CaptureContext *m_Ctx; @@ -91,14 +98,26 @@ private: MeshDisplay m_Config; MeshDataStage m_CurStage; + + // data from mesh pipeline MeshFormat m_VSIn; MeshFormat m_PostVS; MeshFormat m_PostGS; + // data from raw buffer view + bool m_IsBuffer = true; + uint32_t m_TexArrayIdx = 0; + uint32_t m_TexMip = 0; + uint64_t m_ByteOffset = 0; + uint64_t m_ByteSize = UINT64_MAX; + ResourceId m_BufferID; + CameraWrapper *m_CurrentCamera = NULL; ArcballWrapper *m_Arcball = NULL; FlycamWrapper *m_Flycam = NULL; + bool m_MeshView; + BufferItemModel *m_ModelVSIn; BufferItemModel *m_ModelVSOut; BufferItemModel *m_ModelGSOut; @@ -110,9 +129,14 @@ private: BufferItemModel *currentBufferModel(); bool isCurrentRasterOut(); + void SetupMeshView(); + void SetupRawView(); + void Reset(); void ClearModels(); + void ConfigureMeshColumns(); + void UpdateMeshConfig(); void EnableCameraGuessControls(); diff --git a/qrenderdoc/Windows/BufferViewer.ui b/qrenderdoc/Windows/BufferViewer.ui index a774f28d9..366472b7e 100644 --- a/qrenderdoc/Windows/BufferViewer.ui +++ b/qrenderdoc/Windows/BufferViewer.ui @@ -610,7 +610,7 @@ - + Qt::Vertical @@ -666,7 +666,7 @@ - + Qt::Vertical @@ -689,13 +689,6 @@ - - - - Qt::Vertical - - - diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp index 899da09b8..f88ebedb4 100644 --- a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp @@ -1747,10 +1747,16 @@ void D3D11PipelineStateViewer::resource_itemActivated(QTreeWidgetItem *item, int { if(tex->resType == eResType_Buffer) { - // TODO Buffer viewer - // var viewer = new BufferViewer(m_Core, false); - // viewer.ViewRawBuffer(false, 0, ulong.MaxValue, tex.ID); - // viewer.Show(m_DockContent.DockPanel); + BufferViewer *viewer = new BufferViewer(m_Ctx, false, m_Ctx->mainWindow()); + + viewer->ViewTexture(0, 0, tex->ID); + + m_Ctx->setupDockWindow(viewer); + + ToolWindowManager *manager = ToolWindowManager::managerOf(this); + + ToolWindowManager::AreaReference ref(ToolWindowManager::AddTo, manager->areaOf(this)); + manager->addToolWindow(viewer, ref); } else { @@ -1822,7 +1828,7 @@ void D3D11PipelineStateViewer::resource_itemActivated(QTreeWidgetItem *item, int { format = QString("// struct %1\n{\n%2}") .arg(ToQStr(res.variableType.descriptor.name)) - .arg(formatMembers(1, "", res.variableType.members.back().type.members)); + .arg(formatMembers(1, "", res.variableType.members)); } else { @@ -1838,7 +1844,7 @@ void D3D11PipelineStateViewer::resource_itemActivated(QTreeWidgetItem *item, int if(desc.rows > 1 && desc.cols > 1) format += QString("%1x%2").arg(desc.rows).arg(desc.cols); else if(desc.cols > 1) - format += desc.cols; + format += QString::number(desc.cols); if(!desc.name.empty()) format += " " + ToQStr(desc.name); @@ -1905,17 +1911,23 @@ void D3D11PipelineStateViewer::resource_itemActivated(QTreeWidgetItem *item, int if(view.res.Flags & RawBuffer) format = "xint"; - format += fmt.compCount; + format += QString::number(fmt.compCount); } } } } { - // TODO Buffer viewer - // var viewer = new BufferViewer(m_Core, false); - // viewer.ViewRawBuffer(true, buf.offset, buf.size, buf.ID, format); - // viewer.Show(m_DockContent.DockPanel); + BufferViewer *viewer = new BufferViewer(m_Ctx, false, m_Ctx->mainWindow()); + + viewer->ViewBuffer(offs, size, view.res.Resource, format); + + m_Ctx->setupDockWindow(viewer); + + ToolWindowManager *manager = ToolWindowManager::managerOf(this); + + ToolWindowManager::AreaReference ref(ToolWindowManager::AddTo, manager->areaOf(this)); + manager->addToolWindow(viewer, ref); } } } @@ -1967,10 +1979,16 @@ void D3D11PipelineStateViewer::on_iaBuffers_itemActivated(QTreeWidgetItem *item, if(buf.id != ResourceId()) { - // TODO Buffer Viewer - // var viewer = new BufferViewer(m_Core, false); - // viewer.ViewRawBuffer(true, buf.offset, ulong.MaxValue, buf.id); - // viewer.Show(m_DockContent.DockPanel); + BufferViewer *viewer = new BufferViewer(m_Ctx, false, m_Ctx->mainWindow()); + + viewer->ViewBuffer(buf.offset, UINT64_MAX, buf.id); + + m_Ctx->setupDockWindow(viewer); + + ToolWindowManager *manager = ToolWindowManager::managerOf(this); + + ToolWindowManager::AreaReference ref(ToolWindowManager::AddTo, manager->areaOf(this)); + manager->addToolWindow(viewer, ref); } } } diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp index 56ae8241f..ede8b2b76 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -1810,7 +1810,7 @@ void D3D12PipelineStateViewer::resource_itemActivated(QTreeWidgetItem *item, int { format = QString("// struct %1\n{\n%2}") .arg(ToQStr(res.variableType.descriptor.name)) - .arg(formatMembers(1, "", res.variableType.members.back().type.members)); + .arg(formatMembers(1, "", res.variableType.members)); } else { diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index 0f153f8be..46a509339 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -39,7 +39,9 @@ #include "Dialogs/TextureSaveDialog.h" #include "Widgets/ResourcePreview.h" #include "Widgets/TextureGoto.h" +#include "BufferViewer.h" #include "FlowLayout.h" +#include "MainWindow.h" #include "ui_TextureViewer.h" float area(const QSizeF &s) @@ -1704,7 +1706,16 @@ void TextureViewer::ViewTexture(ResourceId ID, bool focus) FetchBuffer *buf = m_Ctx->GetBuffer(ID); if(buf) { - // load in BufferViewer + BufferViewer *viewer = new BufferViewer(m_Ctx, false, m_Ctx->mainWindow()); + + viewer->ViewTexture(0, 0, ID); + + m_Ctx->setupDockWindow(viewer); + + ToolWindowManager *manager = ToolWindowManager::managerOf(this); + + ToolWindowManager::AreaReference ref(ToolWindowManager::AddTo, manager->areaOf(this)); + manager->addToolWindow(viewer, ref); } } @@ -3168,6 +3179,21 @@ void TextureViewer::ShowGotoPopup() void TextureViewer::on_viewTexBuffer_clicked() { + FetchTexture *texptr = GetCurrentTexture(); + + if(texptr) + { + BufferViewer *viewer = new BufferViewer(m_Ctx, false, m_Ctx->mainWindow()); + + viewer->ViewTexture(m_TexDisplay.sliceFace, m_TexDisplay.mip, texptr->ID); + + m_Ctx->setupDockWindow(viewer); + + ToolWindowManager *manager = ToolWindowManager::managerOf(this); + + ToolWindowManager::AreaReference ref(ToolWindowManager::AddTo, manager->areaOf(this)); + manager->addToolWindow(viewer, ref); + } } void TextureViewer::on_saveTex_clicked()