From 6ef7dbb3561452d678347d4f7213ab3c34aa3a64 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 24 Nov 2016 17:32:17 +0100 Subject: [PATCH] Add pipeline state viewer and implement vulkan viewer * Minus interactions with as-yet-unimplemented windows like buffer and shader viewers. * Also missing HTML export --- qrenderdoc/Code/CaptureContext.cpp | 46 + qrenderdoc/Code/CaptureContext.h | 10 + qrenderdoc/Windows/MainWindow.cpp | 25 + qrenderdoc/Windows/MainWindow.h | 7 + .../D3D11PipelineStateViewer.cpp | 49 + .../PipelineState/D3D11PipelineStateViewer.h | 50 + .../PipelineState/D3D11PipelineStateViewer.ui | 33 + .../D3D12PipelineStateViewer.cpp | 49 + .../PipelineState/D3D12PipelineStateViewer.h | 50 + .../PipelineState/D3D12PipelineStateViewer.ui | 33 + .../PipelineState/GLPipelineStateViewer.cpp | 49 + .../PipelineState/GLPipelineStateViewer.h | 50 + .../PipelineState/GLPipelineStateViewer.ui | 33 + .../PipelineState/PipelineStateViewer.cpp | 183 + .../PipelineState/PipelineStateViewer.h | 72 + .../PipelineState/PipelineStateViewer.ui | 36 + .../VulkanPipelineStateViewer.cpp | 2318 ++++++++++ .../PipelineState/VulkanPipelineStateViewer.h | 120 + .../VulkanPipelineStateViewer.ui | 3741 +++++++++++++++++ qrenderdoc/qrenderdoc.pro | 17 +- qrenderdoc/qrenderdoc_local.vcxproj | 25 + qrenderdoc/qrenderdoc_local.vcxproj.filters | 78 + 22 files changed, 7073 insertions(+), 1 deletion(-) create mode 100644 qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp create mode 100644 qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.h create mode 100644 qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.ui create mode 100644 qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp create mode 100644 qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h create mode 100644 qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.ui create mode 100644 qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp create mode 100644 qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.h create mode 100644 qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.ui create mode 100644 qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp create mode 100644 qrenderdoc/Windows/PipelineState/PipelineStateViewer.h create mode 100644 qrenderdoc/Windows/PipelineState/PipelineStateViewer.ui create mode 100644 qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp create mode 100644 qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.h create mode 100644 qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.ui diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index 8beb0df3d..a86f63fa3 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -38,6 +38,7 @@ #include "Windows/Dialogs/LiveCapture.h" #include "Windows/EventBrowser.h" #include "Windows/MainWindow.h" +#include "Windows/PipelineState/PipelineStateViewer.h" #include "Windows/TextureViewer.h" #include "QRDUtils.h" @@ -454,6 +455,18 @@ TextureViewer *CaptureContext::textureViewer() return m_TextureViewer; } +PipelineStateViewer *CaptureContext::pipelineViewer() +{ + if(m_PipelineViewer) + return m_PipelineViewer; + + m_PipelineViewer = new PipelineStateViewer(this, m_MainWindow); + m_PipelineViewer->setObjectName("pipelineViewer"); + m_PipelineViewer->setWindowIcon(*m_Icon); + + return m_PipelineViewer; +} + CaptureDialog *CaptureContext::captureDialog() { if(m_CaptureDialog) @@ -474,6 +487,31 @@ CaptureDialog *CaptureContext::captureDialog() return m_CaptureDialog; } +void CaptureContext::showEventBrowser() +{ + m_MainWindow->showEventBrowser(); +} + +void CaptureContext::showAPIInspector() +{ + m_MainWindow->showAPIInspector(); +} + +void CaptureContext::showTextureViewer() +{ + m_MainWindow->showTextureViewer(); +} + +void CaptureContext::showPipelineViewer() +{ + m_MainWindow->showPipelineViewer(); +} + +void CaptureContext::showCaptureDialog() +{ + m_MainWindow->showCaptureDialog(); +} + QWidget *CaptureContext::createToolWindow(const QString &objectName) { if(objectName == "textureViewer") @@ -484,6 +522,10 @@ QWidget *CaptureContext::createToolWindow(const QString &objectName) { return eventBrowser(); } + else if(objectName == "pipelineViewer") + { + return pipelineViewer(); + } else if(objectName == "apiInspector") { return apiInspector(); @@ -504,6 +546,10 @@ void CaptureContext::windowClosed(QWidget *window) m_TextureViewer = NULL; else if((QWidget *)m_CaptureDialog == window) m_CaptureDialog = NULL; + else if((QWidget *)m_APIInspector == window) + m_APIInspector = NULL; + else if((QWidget *)m_PipelineViewer == window) + m_PipelineViewer = NULL; else qCritical() << "Unrecognised window being closed: " << window; } diff --git a/qrenderdoc/Code/CaptureContext.h b/qrenderdoc/Code/CaptureContext.h index 3cce6388b..168a54a79 100644 --- a/qrenderdoc/Code/CaptureContext.h +++ b/qrenderdoc/Code/CaptureContext.h @@ -48,6 +48,7 @@ struct ILogViewerForm class MainWindow; class EventBrowser; class APIInspector; +class PipelineStateViewer; class TextureViewer; class CaptureDialog; class QProgressDialog; @@ -129,12 +130,20 @@ public: EventBrowser *eventBrowser(); APIInspector *apiInspector(); TextureViewer *textureViewer(); + PipelineStateViewer *pipelineViewer(); CaptureDialog *captureDialog(); bool hasEventBrowser() { return m_EventBrowser != NULL; } bool hasAPIInspector() { return m_APIInspector != NULL; } bool hasTextureViewer() { return m_TextureViewer != NULL; } + bool hasPipelineViewer() { return m_PipelineViewer != NULL; } bool hasCaptureDialog() { return m_CaptureDialog != NULL; } + void showEventBrowser(); + void showAPIInspector(); + void showTextureViewer(); + void showPipelineViewer(); + void showCaptureDialog(); + QWidget *createToolWindow(const QString &objectName); void windowClosed(QWidget *window); @@ -202,5 +211,6 @@ private: EventBrowser *m_EventBrowser = NULL; APIInspector *m_APIInspector = NULL; TextureViewer *m_TextureViewer = NULL; + PipelineStateViewer *m_PipelineViewer = NULL; CaptureDialog *m_CaptureDialog = NULL; }; diff --git a/qrenderdoc/Windows/MainWindow.cpp b/qrenderdoc/Windows/MainWindow.cpp index f863cd4b6..4ccd2fcc1 100644 --- a/qrenderdoc/Windows/MainWindow.cpp +++ b/qrenderdoc/Windows/MainWindow.cpp @@ -30,6 +30,7 @@ #include #include "Code/CaptureContext.h" #include "Code/QRDUtils.h" +#include "PipelineState/PipelineStateViewer.h" #include "Resources/resource.h" #include "Windows/Dialogs/AboutDialog.h" #include "Windows/Dialogs/CaptureDialog.h" @@ -147,6 +148,12 @@ MainWindow::MainWindow(CaptureContext *ctx) : QMainWindow(NULL), ui(new Ui::Main ToolWindowManager::AreaReference(ToolWindowManager::RightOf, ui->toolWindowManager->areaOf(eventBrowser), 0.75f)); + PipelineStateViewer *pipe = m_Ctx->pipelineViewer(); + + ui->toolWindowManager->addToolWindow( + pipe, ToolWindowManager::AreaReference(ToolWindowManager::AddTo, + ui->toolWindowManager->areaOf(textureViewer))); + CaptureDialog *capDialog = m_Ctx->captureDialog(); ui->toolWindowManager->addToolWindow( @@ -696,6 +703,10 @@ ToolWindowManager::AreaReference MainWindow::mainToolArea() ui->toolWindowManager->toolWindows().contains(m_Ctx->textureViewer())) return ToolWindowManager::AreaReference(ToolWindowManager::AddTo, ui->toolWindowManager->areaOf(m_Ctx->textureViewer())); + else if(m_Ctx->hasPipelineViewer() && + ui->toolWindowManager->toolWindows().contains(m_Ctx->pipelineViewer())) + return ToolWindowManager::AreaReference(ToolWindowManager::AddTo, + ui->toolWindowManager->areaOf(m_Ctx->pipelineViewer())); else if(m_Ctx->hasCaptureDialog() && ui->toolWindowManager->toolWindows().contains(m_Ctx->captureDialog())) return ToolWindowManager::AreaReference(ToolWindowManager::AddTo, @@ -712,6 +723,10 @@ ToolWindowManager::AreaReference MainWindow::leftToolArea() ui->toolWindowManager->toolWindows().contains(m_Ctx->textureViewer())) return ToolWindowManager::AreaReference(ToolWindowManager::LeftOf, ui->toolWindowManager->areaOf(m_Ctx->textureViewer())); + else if(m_Ctx->hasPipelineViewer() && + ui->toolWindowManager->toolWindows().contains(m_Ctx->pipelineViewer())) + return ToolWindowManager::AreaReference(ToolWindowManager::LeftOf, + ui->toolWindowManager->areaOf(m_Ctx->pipelineViewer())); else if(m_Ctx->hasCaptureDialog() && ui->toolWindowManager->toolWindows().contains(m_Ctx->captureDialog())) return ToolWindowManager::AreaReference(ToolWindowManager::LeftOf, @@ -972,6 +987,16 @@ void MainWindow::on_action_Texture_Viewer_triggered() ui->toolWindowManager->addToolWindow(textureViewer, mainToolArea()); } +void MainWindow::on_action_Pipeline_State_triggered() +{ + PipelineStateViewer *pipelineViewer = m_Ctx->pipelineViewer(); + + if(ui->toolWindowManager->toolWindows().contains(pipelineViewer)) + ToolWindowManager::raiseToolWindow(pipelineViewer); + else + ui->toolWindowManager->addToolWindow(pipelineViewer, mainToolArea()); +} + void MainWindow::on_action_Capture_Log_triggered() { CaptureDialog *capDialog = m_Ctx->captureDialog(); diff --git a/qrenderdoc/Windows/MainWindow.h b/qrenderdoc/Windows/MainWindow.h index f1c105f27..bb223c430 100644 --- a/qrenderdoc/Windows/MainWindow.h +++ b/qrenderdoc/Windows/MainWindow.h @@ -71,6 +71,12 @@ public: void ShowLiveCapture(LiveCapture *live); void LiveCaptureClosed(LiveCapture *live); + void showEventBrowser() { on_action_Event_Browser_triggered(); } + void showAPIInspector() { on_action_API_Inspector_triggered(); } + void showMeshOutput() { on_action_Mesh_Output_triggered(); } + void showTextureViewer() { on_action_Texture_Viewer_triggered(); } + void showPipelineViewer() { on_action_Pipeline_State_triggered(); } + void showCaptureDialog() { on_action_Capture_Log_triggered(); } private slots: // automatic slots void on_action_Exit_triggered(); @@ -81,6 +87,7 @@ private slots: void on_action_API_Inspector_triggered(); void on_action_Event_Browser_triggered(); void on_action_Texture_Viewer_triggered(); + void on_action_Pipeline_State_triggered(); void on_action_Capture_Log_triggered(); void on_action_Inject_into_Process_triggered(); void on_action_Resolve_Symbols_triggered(); diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp new file mode 100644 index 000000000..578c09b4b --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp @@ -0,0 +1,49 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * 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. + ******************************************************************************/ + +#include "D3D11PipelineStateViewer.h" +#include "ui_D3D11PipelineStateViewer.h" + +D3D11PipelineStateViewer::D3D11PipelineStateViewer(CaptureContext *ctx, QWidget *parent) + : QFrame(parent), ui(new Ui::D3D11PipelineStateViewer), m_Ctx(ctx) +{ + ui->setupUi(this); +} + +D3D11PipelineStateViewer::~D3D11PipelineStateViewer() +{ + delete ui; +} + +void D3D11PipelineStateViewer::OnLogfileLoaded() +{ +} + +void D3D11PipelineStateViewer::OnLogfileClosed() +{ +} + +void D3D11PipelineStateViewer::OnEventSelected(uint32_t eventID) +{ +} diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.h new file mode 100644 index 000000000..4596092ef --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * 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. + ******************************************************************************/ + +#pragma once + +#include +#include "Code/CaptureContext.h" + +namespace Ui +{ +class D3D11PipelineStateViewer; +} + +class D3D11PipelineStateViewer : public QFrame, public ILogViewerForm +{ + Q_OBJECT + +public: + explicit D3D11PipelineStateViewer(CaptureContext *ctx, QWidget *parent = 0); + ~D3D11PipelineStateViewer(); + + void OnLogfileLoaded(); + void OnLogfileClosed(); + void OnEventSelected(uint32_t eventID); + +private: + Ui::D3D11PipelineStateViewer *ui; + CaptureContext *m_Ctx; +}; diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.ui b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.ui new file mode 100644 index 000000000..6374e60ac --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.ui @@ -0,0 +1,33 @@ + + + D3D11PipelineStateViewer + + + + 0 + 0 + 400 + 300 + + + + + + + + 22 + + + + D3D11 - TODO + + + Qt::AlignCenter + + + + + + + + diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp new file mode 100644 index 000000000..c0b1a78c7 --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -0,0 +1,49 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * 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. + ******************************************************************************/ + +#include "D3D12PipelineStateViewer.h" +#include "ui_D3D12PipelineStateViewer.h" + +D3D12PipelineStateViewer::D3D12PipelineStateViewer(CaptureContext *ctx, QWidget *parent) + : QFrame(parent), ui(new Ui::D3D12PipelineStateViewer), m_Ctx(ctx) +{ + ui->setupUi(this); +} + +D3D12PipelineStateViewer::~D3D12PipelineStateViewer() +{ + delete ui; +} + +void D3D12PipelineStateViewer::OnLogfileLoaded() +{ +} + +void D3D12PipelineStateViewer::OnLogfileClosed() +{ +} + +void D3D12PipelineStateViewer::OnEventSelected(uint32_t eventID) +{ +} diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h new file mode 100644 index 000000000..7bca922ac --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * 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. + ******************************************************************************/ + +#pragma once + +#include +#include "Code/CaptureContext.h" + +namespace Ui +{ +class D3D12PipelineStateViewer; +} + +class D3D12PipelineStateViewer : public QFrame, public ILogViewerForm +{ + Q_OBJECT + +public: + explicit D3D12PipelineStateViewer(CaptureContext *ctx, QWidget *parent = 0); + ~D3D12PipelineStateViewer(); + + void OnLogfileLoaded(); + void OnLogfileClosed(); + void OnEventSelected(uint32_t eventID); + +private: + Ui::D3D12PipelineStateViewer *ui; + CaptureContext *m_Ctx; +}; diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.ui b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.ui new file mode 100644 index 000000000..907c3d130 --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.ui @@ -0,0 +1,33 @@ + + + D3D12PipelineStateViewer + + + + 0 + 0 + 400 + 300 + + + + + + + + 22 + + + + D3D12 - TODO + + + Qt::AlignCenter + + + + + + + + diff --git a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp new file mode 100644 index 000000000..79f0bf993 --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp @@ -0,0 +1,49 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * 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. + ******************************************************************************/ + +#include "GLPipelineStateViewer.h" +#include "ui_GLPipelineStateViewer.h" + +GLPipelineStateViewer::GLPipelineStateViewer(CaptureContext *ctx, QWidget *parent) + : QFrame(parent), ui(new Ui::GLPipelineStateViewer), m_Ctx(ctx) +{ + ui->setupUi(this); +} + +GLPipelineStateViewer::~GLPipelineStateViewer() +{ + delete ui; +} + +void GLPipelineStateViewer::OnLogfileLoaded() +{ +} + +void GLPipelineStateViewer::OnLogfileClosed() +{ +} + +void GLPipelineStateViewer::OnEventSelected(uint32_t eventID) +{ +} diff --git a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.h new file mode 100644 index 000000000..a173cd897 --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * 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. + ******************************************************************************/ + +#pragma once + +#include +#include "Code/CaptureContext.h" + +namespace Ui +{ +class GLPipelineStateViewer; +} + +class GLPipelineStateViewer : public QFrame, public ILogViewerForm +{ + Q_OBJECT + +public: + explicit GLPipelineStateViewer(CaptureContext *ctx, QWidget *parent = 0); + ~GLPipelineStateViewer(); + + void OnLogfileLoaded(); + void OnLogfileClosed(); + void OnEventSelected(uint32_t eventID); + +private: + Ui::GLPipelineStateViewer *ui; + CaptureContext *m_Ctx; +}; diff --git a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.ui b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.ui new file mode 100644 index 000000000..5dec68deb --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.ui @@ -0,0 +1,33 @@ + + + GLPipelineStateViewer + + + + 0 + 0 + 400 + 300 + + + + + + + + 22 + + + + OpenGL - TODO + + + Qt::AlignCenter + + + + + + + + diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp new file mode 100644 index 000000000..056b05e98 --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp @@ -0,0 +1,183 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * 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. + ******************************************************************************/ + +#include "PipelineStateViewer.h" +#include "D3D11PipelineStateViewer.h" +#include "D3D12PipelineStateViewer.h" +#include "GLPipelineStateViewer.h" +#include "VulkanPipelineStateViewer.h" +#include "ui_PipelineStateViewer.h" + +PipelineStateViewer::PipelineStateViewer(CaptureContext *ctx, QWidget *parent) + : QFrame(parent), ui(new Ui::PipelineStateViewer), m_Ctx(ctx) +{ + ui->setupUi(this); + + m_D3D11 = NULL; + m_D3D12 = NULL; + m_GL = NULL; + m_Vulkan = NULL; + + m_Current = NULL; + + m_Ctx->AddLogViewer(this); + + setToD3D11(); +} + +PipelineStateViewer::~PipelineStateViewer() +{ + reset(); + + m_Ctx->windowClosed(this); + m_Ctx->RemoveLogViewer(this); + + delete ui; +} + +void PipelineStateViewer::OnLogfileLoaded() +{ + if(m_Ctx->APIProps().pipelineType == eGraphicsAPI_D3D11) + setToD3D11(); + else if(m_Ctx->APIProps().pipelineType == eGraphicsAPI_D3D12) + setToD3D12(); + else if(m_Ctx->APIProps().pipelineType == eGraphicsAPI_OpenGL) + setToGL(); + else if(m_Ctx->APIProps().pipelineType == eGraphicsAPI_Vulkan) + setToVulkan(); + + if(m_Current) + m_Current->OnLogfileLoaded(); +} + +void PipelineStateViewer::OnLogfileClosed() +{ + if(m_Current) + m_Current->OnLogfileClosed(); +} + +void PipelineStateViewer::OnEventSelected(uint32_t eventID) +{ + if(m_Current) + m_Current->OnEventSelected(eventID); +} + +QVariant PipelineStateViewer::persistData() +{ + QVariantMap state; + + if(m_Current == m_D3D11) + state["type"] = "D3D11"; + else if(m_Current == m_D3D12) + state["type"] = "D3D12"; + else if(m_Current == m_GL) + state["type"] = "GL"; + else if(m_Current == m_Vulkan) + state["type"] = "Vulkan"; + else + state["type"] = ""; + + return state; +} + +void PipelineStateViewer::setPersistData(const QVariant &persistData) +{ + QString str = persistData.toMap()["type"].toString(); + + if(str == "D3D11") + setToD3D11(); + else if(str == "D3D12") + setToD3D12(); + else if(str == "GL") + setToGL(); + else if(str == "Vulkan") + setToVulkan(); +} + +void PipelineStateViewer::reset() +{ + delete m_D3D11; + delete m_D3D12; + delete m_GL; + delete m_Vulkan; + + m_D3D11 = NULL; + m_D3D12 = NULL; + m_GL = NULL; + m_Vulkan = NULL; + + m_Current = NULL; +} + +void PipelineStateViewer::setToD3D11() +{ + if(m_D3D11) + return; + + reset(); + + m_D3D11 = new D3D11PipelineStateViewer(m_Ctx, this); + ui->layout->addWidget(m_D3D11); + m_Current = m_D3D11; + m_Ctx->CurPipelineState.DefaultType = eGraphicsAPI_D3D11; +} + +void PipelineStateViewer::setToD3D12() +{ + if(m_D3D12) + return; + + reset(); + + m_D3D12 = new D3D12PipelineStateViewer(m_Ctx, this); + ui->layout->addWidget(m_D3D12); + m_Current = m_D3D12; + m_Ctx->CurPipelineState.DefaultType = eGraphicsAPI_D3D12; +} + +void PipelineStateViewer::setToGL() +{ + if(m_GL) + return; + + reset(); + + m_GL = new GLPipelineStateViewer(m_Ctx, this); + ui->layout->addWidget(m_GL); + m_Current = m_GL; + m_Ctx->CurPipelineState.DefaultType = eGraphicsAPI_OpenGL; +} + +void PipelineStateViewer::setToVulkan() +{ + if(m_Vulkan) + return; + + reset(); + + m_Vulkan = new VulkanPipelineStateViewer(m_Ctx, this); + ui->layout->addWidget(m_Vulkan); + m_Current = m_Vulkan; + m_Ctx->CurPipelineState.DefaultType = eGraphicsAPI_Vulkan; +} diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h new file mode 100644 index 000000000..96141aded --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h @@ -0,0 +1,72 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * 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. + ******************************************************************************/ + +#pragma once + +#include +#include "Code/CaptureContext.h" + +namespace Ui +{ +class PipelineStateViewer; +} + +class D3D11PipelineStateViewer; +class D3D12PipelineStateViewer; +class GLPipelineStateViewer; +class VulkanPipelineStateViewer; + +class PipelineStateViewer : public QFrame, public ILogViewerForm +{ + Q_OBJECT + + Q_PROPERTY(QVariant persistData READ persistData WRITE setPersistData DESIGNABLE false SCRIPTABLE false) + +public: + explicit PipelineStateViewer(CaptureContext *ctx, QWidget *parent = 0); + ~PipelineStateViewer(); + + void OnLogfileLoaded(); + void OnLogfileClosed(); + void OnEventSelected(uint32_t eventID); + + QVariant persistData(); + void setPersistData(const QVariant &persistData); + +private: + Ui::PipelineStateViewer *ui; + CaptureContext *m_Ctx; + + void setToD3D11(); + void setToD3D12(); + void setToGL(); + void setToVulkan(); + void reset(); + + D3D11PipelineStateViewer *m_D3D11; + D3D12PipelineStateViewer *m_D3D12; + GLPipelineStateViewer *m_GL; + VulkanPipelineStateViewer *m_Vulkan; + ILogViewerForm *m_Current; +}; diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.ui b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.ui new file mode 100644 index 000000000..457dd8595 --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.ui @@ -0,0 +1,36 @@ + + + PipelineStateViewer + + + + 0 + 0 + 400 + 300 + + + + Pipeline State + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp new file mode 100644 index 000000000..68a8cfc28 --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -0,0 +1,2318 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * 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. + ******************************************************************************/ + +#include "VulkanPipelineStateViewer.h" +#include +#include "Windows/TextureViewer.h" +#include "ui_VulkanPipelineStateViewer.h" + +Q_DECLARE_METATYPE(ResourceId); +Q_DECLARE_METATYPE(SamplerData); + +struct VBIBTag +{ + VBIBTag() { offset = 0; } + VBIBTag(ResourceId i, uint64_t offs) + { + id = i; + offset = offs; + } + + ResourceId id; + uint64_t offset; +}; + +Q_DECLARE_METATYPE(VBIBTag); + +struct CBufferTag +{ + CBufferTag() { slotIdx = arrayIdx = 0; } + CBufferTag(uint32_t s, uint32_t i) + { + slotIdx = s; + arrayIdx = i; + } + uint32_t slotIdx; + uint32_t arrayIdx; +}; + +Q_DECLARE_METATYPE(CBufferTag); + +struct BufferTag +{ + BufferTag() + { + rwRes = false; + bindPoint = 0; + offset = size = 0; + } + BufferTag(bool rw, uint32_t b, ResourceId id, uint64_t offs, uint64_t sz) + { + rwRes = rw; + bindPoint = b; + ID = id; + offset = offs; + size = sz; + } + bool rwRes; + uint32_t bindPoint; + ResourceId ID; + uint64_t offset; + uint64_t size; +}; + +Q_DECLARE_METATYPE(BufferTag); + +VulkanPipelineStateViewer::VulkanPipelineStateViewer(CaptureContext *ctx, QWidget *parent) + : QFrame(parent), ui(new Ui::VulkanPipelineStateViewer), m_Ctx(ctx) +{ + ui->setupUi(this); + + QToolButton *viewButtons[] = { + ui->vsShaderViewButton, ui->tcsShaderViewButton, ui->tesShaderViewButton, + ui->gsShaderViewButton, ui->fsShaderViewButton, ui->csShaderViewButton, + }; + + QToolButton *editButtons[] = { + ui->vsShaderEditButton, ui->tcsShaderEditButton, ui->tesShaderEditButton, + ui->gsShaderEditButton, ui->fsShaderEditButton, ui->csShaderEditButton, + }; + + QToolButton *saveButtons[] = { + ui->vsShaderSaveButton, ui->tcsShaderSaveButton, ui->tesShaderSaveButton, + ui->gsShaderSaveButton, ui->fsShaderSaveButton, ui->csShaderSaveButton, + }; + + RDTreeWidget *resources[] = { + ui->vsResources, ui->tcsResources, ui->tesResources, + ui->gsResources, ui->fsResources, ui->csResources, + }; + + RDTreeWidget *ubos[] = { + ui->vsUBOs, ui->tcsUBOs, ui->tesUBOs, ui->gsUBOs, ui->fsUBOs, ui->csUBOs, + }; + + for(QToolButton *b : viewButtons) + QObject::connect(b, &QToolButton::clicked, this, &VulkanPipelineStateViewer::shaderView_clicked); + + for(QToolButton *b : editButtons) + QObject::connect(b, &QToolButton::clicked, this, &VulkanPipelineStateViewer::shaderEdit_clicked); + + for(QToolButton *b : saveButtons) + QObject::connect(b, &QToolButton::clicked, this, &VulkanPipelineStateViewer::shaderSave_clicked); + + QObject::connect(ui->viAttrs, &RDTreeWidget::leave, this, &VulkanPipelineStateViewer::vertex_leave); + QObject::connect(ui->viBuffers, &RDTreeWidget::leave, this, + &VulkanPipelineStateViewer::vertex_leave); + + QObject::connect(ui->framebuffer, &RDTreeWidget::itemActivated, this, + &VulkanPipelineStateViewer::resource_itemActivated); + + for(RDTreeWidget *res : resources) + QObject::connect(res, &RDTreeWidget::itemActivated, this, + &VulkanPipelineStateViewer::resource_itemActivated); + + addGridLines(ui->rasterizerGridLayout); + addGridLines(ui->MSAAGridLayout); + addGridLines(ui->blendStateGridLayout); + addGridLines(ui->depthStateGridLayout); + + // no way to set this up in the UI :( + { + // Index | Name | Location | Binding | Format | Offset | Go + ui->viAttrs->header()->resizeSection(0, 75); + ui->viAttrs->header()->setSectionResizeMode(0, QHeaderView::Interactive); + ui->viAttrs->header()->setSectionResizeMode(1, QHeaderView::Stretch); + ui->viAttrs->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); + ui->viAttrs->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents); + ui->viAttrs->header()->setSectionResizeMode(4, QHeaderView::ResizeToContents); + ui->viAttrs->header()->setSectionResizeMode(5, QHeaderView::ResizeToContents); + ui->viAttrs->header()->setSectionResizeMode(6, QHeaderView::ResizeToContents); + + ui->viAttrs->setHoverIconColumn(6); + } + + { + // Slot | Buffer | Rate | Offset | Stride | Byte Length | Go + ui->viBuffers->header()->resizeSection(0, 75); + ui->viBuffers->header()->setSectionResizeMode(0, QHeaderView::Interactive); + ui->viBuffers->header()->setSectionResizeMode(1, QHeaderView::Stretch); + ui->viBuffers->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); + ui->viBuffers->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents); + ui->viBuffers->header()->setSectionResizeMode(4, QHeaderView::ResizeToContents); + ui->viBuffers->header()->setSectionResizeMode(5, QHeaderView::ResizeToContents); + ui->viBuffers->header()->setSectionResizeMode(6, QHeaderView::ResizeToContents); + + ui->viBuffers->setHoverIconColumn(6); + } + + for(RDTreeWidget *res : resources) + { + // | Set | Binding | Type | Resource | Contents | cont.d | Go + res->header()->resizeSection(0, 30); + res->header()->setSectionResizeMode(0, QHeaderView::Fixed); + res->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); + res->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); + res->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents); + res->header()->setSectionResizeMode(4, QHeaderView::Stretch); + res->header()->setSectionResizeMode(5, QHeaderView::Stretch); + res->header()->setSectionResizeMode(6, QHeaderView::Stretch); + res->header()->setSectionResizeMode(7, QHeaderView::ResizeToContents); + + res->setHoverIconColumn(7); + res->setDefaultHoverColor(ui->framebuffer->palette().color(QPalette::Window)); + } + + for(RDTreeWidget *ubo : ubos) + { + // | Set | Binding | Buffer | Byte Range | Size | Go + ubo->header()->resizeSection(0, 30); + ubo->header()->setSectionResizeMode(0, QHeaderView::Fixed); + ubo->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); + ubo->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); + ubo->header()->setSectionResizeMode(3, QHeaderView::Stretch); + ubo->header()->setSectionResizeMode(4, QHeaderView::Stretch); + ubo->header()->setSectionResizeMode(5, QHeaderView::Stretch); + ubo->header()->setSectionResizeMode(6, QHeaderView::ResizeToContents); + + ubo->setHoverIconColumn(6); + ubo->setDefaultHoverColor(ui->framebuffer->palette().color(QPalette::Window)); + } + + { + // Slot | X | Y | Width | Height | MinDepth | MaxDepth + ui->viewports->header()->resizeSection(0, 75); + ui->viewports->header()->setSectionResizeMode(0, QHeaderView::Interactive); + ui->viewports->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); + ui->viewports->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); + ui->viewports->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents); + ui->viewports->header()->setSectionResizeMode(4, QHeaderView::ResizeToContents); + ui->viewports->header()->setSectionResizeMode(5, QHeaderView::ResizeToContents); + ui->viewports->header()->setSectionResizeMode(6, QHeaderView::ResizeToContents); + } + + { + // Slot | X | Y | Width | Height + ui->scissors->header()->resizeSection(0, 100); + ui->scissors->header()->setSectionResizeMode(0, QHeaderView::Interactive); + ui->scissors->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); + ui->scissors->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); + ui->scissors->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents); + ui->scissors->header()->setSectionResizeMode(4, QHeaderView::ResizeToContents); + } + + { + // Slot | Resource | Type | Width | Height | Depth | Array Size | Format | Go + ui->framebuffer->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + ui->framebuffer->header()->setSectionResizeMode(1, QHeaderView::Stretch); + ui->framebuffer->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); + ui->framebuffer->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents); + ui->framebuffer->header()->setSectionResizeMode(4, QHeaderView::ResizeToContents); + ui->framebuffer->header()->setSectionResizeMode(5, QHeaderView::ResizeToContents); + ui->framebuffer->header()->setSectionResizeMode(6, QHeaderView::ResizeToContents); + ui->framebuffer->header()->setSectionResizeMode(7, QHeaderView::ResizeToContents); + ui->framebuffer->header()->setSectionResizeMode(8, QHeaderView::ResizeToContents); + + ui->framebuffer->setHoverIconColumn(8); + ui->framebuffer->setDefaultHoverColor(ui->framebuffer->palette().color(QPalette::Window)); + } + + { + // Slot | Enabled | Col Src | Col Dst | Col Op | Alpha Src | Alpha Dst | Alpha Op | Write Mask + ui->blends->header()->resizeSection(0, 75); + ui->blends->header()->setSectionResizeMode(0, QHeaderView::Interactive); + ui->blends->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); + ui->blends->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); + ui->blends->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents); + ui->blends->header()->setSectionResizeMode(4, QHeaderView::ResizeToContents); + ui->blends->header()->setSectionResizeMode(5, QHeaderView::ResizeToContents); + ui->blends->header()->setSectionResizeMode(6, QHeaderView::ResizeToContents); + ui->blends->header()->setSectionResizeMode(7, QHeaderView::ResizeToContents); + ui->blends->header()->setSectionResizeMode(8, QHeaderView::ResizeToContents); + } + + { + // Face | Func | Fail Op | Depth Fail Op | Pass Op | Write Mask | Comp Mask | Ref + ui->stencils->header()->resizeSection(0, 50); + ui->stencils->header()->setSectionResizeMode(0, QHeaderView::Interactive); + ui->stencils->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); + ui->stencils->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); + ui->stencils->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents); + ui->stencils->header()->setSectionResizeMode(4, QHeaderView::ResizeToContents); + ui->stencils->header()->setSectionResizeMode(5, QHeaderView::ResizeToContents); + ui->stencils->header()->setSectionResizeMode(6, QHeaderView::ResizeToContents); + ui->stencils->header()->setSectionResizeMode(7, QHeaderView::Stretch); + } + + // this is often changed just because we're changing some tab in the designer. + ui->stagesTabs->setCurrentIndex(0); + + // reset everything back to defaults + clearState(); +} + +VulkanPipelineStateViewer::~VulkanPipelineStateViewer() +{ + delete ui; +} + +void VulkanPipelineStateViewer::OnLogfileLoaded() +{ + OnEventSelected(m_Ctx->CurEvent()); +} + +void VulkanPipelineStateViewer::OnLogfileClosed() +{ + clearState(); +} + +void VulkanPipelineStateViewer::OnEventSelected(uint32_t eventID) +{ + setState(); +} + +void VulkanPipelineStateViewer::on_showDisabled_toggled(bool checked) +{ + setState(); +} + +void VulkanPipelineStateViewer::on_showEmpty_toggled(bool checked) +{ + setState(); +} + +void VulkanPipelineStateViewer::setInactiveRow(QTreeWidgetItem *node) +{ + for(int i = 0; i < node->columnCount(); i++) + { + QFont f = node->font(i); + f.setItalic(true); + node->setFont(i, f); + } +} + +void VulkanPipelineStateViewer::setEmptyRow(QTreeWidgetItem *node) +{ + for(int i = 0; i < node->columnCount(); i++) + node->setBackgroundColor(i, QColor(255, 70, 70)); +} + +template +void VulkanPipelineStateViewer::setViewDetails(QTreeWidgetItem *node, const bindType &view, + FetchTexture *tex) +{ + if(tex == NULL) + return; + + QString text; + + bool viewdetails = false; + + { + for(const VulkanPipelineState::ImageData &im : m_Ctx->CurVulkanPipelineState.images) + { + if(im.image == tex->ID) + { + text += tr("Texture is in the '%1' layout\n\n").arg(ToQStr(im.layouts[0].name)); + break; + } + } + + if(view.viewfmt != tex->format) + { + text += tr("The texture is format %1, the view treats it as %2.\n") + .arg(ToQStr(tex->format.strname)) + .arg(ToQStr(view.viewfmt.strname)); + + viewdetails = true; + } + + if(tex->mips > 1 && (tex->mips != view.numMip || view.baseMip > 0)) + { + if(view.numMip == 1) + text += + tr("The texture has %1 mips, the view covers mip %2.\n").arg(tex->mips).arg(view.baseMip); + else + text += tr("The texture has %1 mips, the view covers mips %2-%3.\n") + .arg(tex->mips) + .arg(view.baseMip) + .arg(view.baseMip + view.numMip - 1); + + viewdetails = true; + } + + if(tex->arraysize > 1 && (tex->arraysize != view.numLayer || view.baseLayer > 0)) + { + if(view.numLayer == 1) + text += tr("The texture has %1 array slices, the view covers slice %2.\n") + .arg(tex->arraysize) + .arg(view.baseLayer); + else + text += tr("The texture has %1 array slices, the view covers slices %2-%3.\n") + .arg(tex->arraysize) + .arg(view.baseLayer) + .arg(view.baseLayer + view.numLayer); + + viewdetails = true; + } + } + + text = text.trimmed(); + + for(int i = 0; i < node->columnCount(); i++) + { + node->setToolTip(i, text); + + if(viewdetails) + { + node->setBackgroundColor(i, QColor(127, 255, 212)); + node->setForeground(i, QBrush(QColor(0, 0, 0))); + } + } +} + +template +void VulkanPipelineStateViewer::setViewDetails(QTreeWidgetItem *node, const bindType &view, + FetchBuffer *buf) +{ + if(buf == NULL) + return; + + QString text; + + if(view.offset > 0 || view.size < buf->length) + { + text += tr("The view covers bytes %1-%2.\nThe buffer is %3 bytes in length.") + .arg(view.offset) + .arg(view.size) + .arg(buf->length); + } + else + { + return; + } + + for(int i = 0; i < node->columnCount(); i++) + { + node->setToolTip(i, text); + node->setBackgroundColor(i, QColor(127, 255, 212)); + node->setForeground(i, QBrush(QColor(0, 0, 0))); + } +} + +QTreeWidgetItem *VulkanPipelineStateViewer::makeNode(const std::initializer_list &values) +{ + QTreeWidgetItem *ret = new QTreeWidgetItem(); + + int i = 0; + for(const QVariant &v : values) + ret->setData(i++, Qt::DisplayRole, v); + + return ret; +} + +QTreeWidgetItem *VulkanPipelineStateViewer::makeNode(const QVariantList &values) +{ + QTreeWidgetItem *ret = new QTreeWidgetItem(); + + int i = 0; + for(const QVariant &v : values) + ret->setData(i++, Qt::DisplayRole, v); + + return ret; +} + +bool VulkanPipelineStateViewer::showNode(bool usedSlot, bool filledSlot) +{ + const bool showDisabled = ui->showDisabled->isChecked(); + const bool showEmpty = ui->showEmpty->isChecked(); + + // show if it's referenced by the shader - regardless of empty or not + if(usedSlot) + return true; + + // it's bound, but not referenced, and we have "show disabled" + if(showDisabled && !usedSlot && filledSlot) + return true; + + // it's empty, and we have "show empty" + if(showEmpty && !filledSlot) + return true; + + return false; +} + +const VulkanPipelineState::ShaderStage *VulkanPipelineStateViewer::stageForSender(QWidget *widget) +{ + if(!m_Ctx->LogLoaded()) + return NULL; + + while(widget) + { + if(widget == ui->stagesTabs->widget(0)) + return &m_Ctx->CurVulkanPipelineState.VS; + if(widget == ui->stagesTabs->widget(1)) + return &m_Ctx->CurVulkanPipelineState.VS; + if(widget == ui->stagesTabs->widget(2)) + return &m_Ctx->CurVulkanPipelineState.TCS; + if(widget == ui->stagesTabs->widget(3)) + return &m_Ctx->CurVulkanPipelineState.TES; + if(widget == ui->stagesTabs->widget(4)) + return &m_Ctx->CurVulkanPipelineState.GS; + if(widget == ui->stagesTabs->widget(5)) + return &m_Ctx->CurVulkanPipelineState.FS; + if(widget == ui->stagesTabs->widget(6)) + return &m_Ctx->CurVulkanPipelineState.FS; + if(widget == ui->stagesTabs->widget(7)) + return &m_Ctx->CurVulkanPipelineState.FS; + if(widget == ui->stagesTabs->widget(8)) + return &m_Ctx->CurVulkanPipelineState.CS; + + widget = widget->parentWidget(); + } + + qCritical() << "Unrecognised control calling event handler"; + + return NULL; +} + +void VulkanPipelineStateViewer::clearShaderState(QLabel *shader, RDTreeWidget *resources, + RDTreeWidget *cbuffers) +{ + shader->setText(tr("Unbound Shader")); + resources->clear(); + cbuffers->clear(); +} + +void VulkanPipelineStateViewer::clearState() +{ + m_VBNodes.clear(); + m_BindNodes.clear(); + + ui->viAttrs->clear(); + ui->viBuffers->clear(); + ui->topology->setText(""); + ui->primRestart->setVisible(false); + ui->topologyDiagram->setPixmap(QPixmap()); + + clearShaderState(ui->vsShader, ui->vsResources, ui->vsUBOs); + clearShaderState(ui->tcsShader, ui->tcsResources, ui->tcsUBOs); + clearShaderState(ui->tesShader, ui->tesResources, ui->tesUBOs); + clearShaderState(ui->gsShader, ui->gsResources, ui->gsUBOs); + clearShaderState(ui->fsShader, ui->fsResources, ui->fsUBOs); + clearShaderState(ui->csShader, ui->csResources, ui->csUBOs); + + QPixmap tick(QString::fromUtf8(":/Resources/tick.png")); + + ui->fillMode->setText(tr("Solid", "Fill Mode")); + ui->cullMode->setText(tr("Front", "Cull Mode")); + ui->frontCCW->setPixmap(tick); + + ui->depthBias->setText("0.0"); + ui->depthBiasClamp->setText("0.0"); + ui->slopeScaledBias->setText("0.0"); + + ui->depthClamp->setPixmap(tick); + ui->rasterizerDiscard->setPixmap(tick); + ui->lineWidth->setText("1.0"); + + ui->sampleCount->setText("1"); + ui->sampleShading->setPixmap(tick); + ui->minSampleShading->setText("0.0"); + ui->sampleMask->setText("FFFFFFFF"); + + ui->viewports->clear(); + ui->scissors->clear(); + + ui->framebuffer->clear(); + ui->blends->clear(); + + ui->blendFactor->setText("0.00, 0.00, 0.00, 0.00"); + ui->logicOp->setText("-"); + ui->alphaToOne->setPixmap(tick); + + ui->depthEnabled->setPixmap(tick); + ui->depthFunc->setText("GREATER_EQUAL"); + ui->depthWrite->setPixmap(tick); + + ui->depthBounds->setText("0.0-1.0"); + ui->depthBounds->setPixmap(QPixmap()); + + ui->stencils->clear(); +} + +QVariantList VulkanPipelineStateViewer::makeSampler( + const QString &bindset, const QString &slotname, + const VulkanPipelineState::Pipeline::DescriptorSet::DescriptorBinding::BindingElement &descriptor) +{ + QString addressing = ""; + QString addPrefix = ""; + QString addVal = ""; + + QString filter = ""; + QString filtPrefix = ""; + QString filtVal = ""; + + QString addr[] = {ToQStr(descriptor.addrU), ToQStr(descriptor.addrV), ToQStr(descriptor.addrW)}; + + // arrange like either UVW: WRAP or UV: WRAP, W: CLAMP + for(int a = 0; a < 3; a++) + { + QString prefix = QChar("UVW"[a]); + + if(a == 0 || addr[a] == addr[a - 1]) + { + addPrefix += prefix; + } + else + { + addressing += addPrefix + ": " + addVal + ", "; + + addPrefix = prefix; + } + addVal = addr[a]; + } + + addressing += addPrefix + ": " + addVal; + + if(descriptor.borderEnable) + addressing += " " + ToQStr(descriptor.border); + + if(descriptor.unnormalized) + addressing += " (Un-norm)"; + + QString filters[] = {ToQStr(descriptor.min), ToQStr(descriptor.mag), ToQStr(descriptor.mip)}; + QString filterPrefixes[] = {"Min", "Mag", "Mip"}; + + // arrange as addressing above + for(int a = 0; a < 3; a++) + { + if(a == 0 || filters[a] == filters[a - 1]) + { + if(filtPrefix != "") + filtPrefix += "/"; + filtPrefix += filterPrefixes[a]; + } + else + { + filter += filtPrefix + ": " + filtVal + ", "; + + filtPrefix = filterPrefixes[a]; + } + filtVal = filters[a]; + } + + filter += filtPrefix + ": " + filtVal; + + if(descriptor.maxAniso > 1.0f) + filter += QString(" Aniso %1x").arg(descriptor.maxAniso); + + if(descriptor.compareEnable) + filter += QString(" (%1)").arg(ToQStr(descriptor.comparison)); + + QString lod = "LODs: " + + (descriptor.minlod == -FLT_MAX ? "0" : QString::number(descriptor.minlod)) + " - " + + (descriptor.maxlod == FLT_MAX ? "FLT_MAX" : QString::number(descriptor.maxlod)); + + if(descriptor.mipBias != 0.0f) + lod += QString(" Bias %1").arg(descriptor.mipBias); + + return {"", + bindset, + slotname, + descriptor.immutableSampler ? "Immutable Sampler" : "Sampler", + ToQStr(descriptor.SamplerName), + addressing, + filter + ", " + lod}; +} + +void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, + const VulkanPipelineState::ShaderStage &stage, + int bindset, int bind, + const VulkanPipelineState::Pipeline &pipe, + RDTreeWidget *resources, + QMap &samplers) +{ + const ShaderResource *shaderRes = NULL; + const BindpointMap *bindMap = NULL; + + QIcon action(QPixmap(QString::fromUtf8(":/Resources/action.png"))); + QIcon action_hover(QPixmap(QString::fromUtf8(":/Resources/action_hover.png"))); + + bool isrw = false; + uint bindPoint = 0; + + if(shaderDetails != NULL) + { + for(int i = 0; i < shaderDetails->ReadOnlyResources.count; i++) + { + const ShaderResource &ro = shaderDetails->ReadOnlyResources[i]; + + if(stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bindset == bindset && + stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bind == bind) + { + bindPoint = (uint)i; + shaderRes = &ro; + bindMap = &stage.BindpointMapping.ReadOnlyResources[ro.bindPoint]; + } + } + + for(int i = 0; i < shaderDetails->ReadWriteResources.count; i++) + { + const ShaderResource &rw = shaderDetails->ReadWriteResources[i]; + + if(stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bindset == bindset && + stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bind == bind) + { + bindPoint = (uint)i; + isrw = true; + shaderRes = &rw; + bindMap = &stage.BindpointMapping.ReadWriteResources[rw.bindPoint]; + } + } + } + + const rdctype::array + *slotBinds = NULL; + ShaderBindType bindType = eBindType_Unknown; + ShaderStageBits stageBits = (ShaderStageBits)0; + + if(bindset < pipe.DescSets.count && bind < pipe.DescSets[bindset].bindings.count) + { + slotBinds = &pipe.DescSets[bindset].bindings[bind].binds; + bindType = pipe.DescSets[bindset].bindings[bind].type; + stageBits = pipe.DescSets[bindset].bindings[bind].stageFlags; + } + else + { + if(shaderRes->IsSampler) + bindType = eBindType_Sampler; + else if(shaderRes->IsSampler && shaderRes->IsTexture) + bindType = eBindType_ImageSampler; + else if(shaderRes->resType == eResType_Buffer) + bindType = eBindType_ReadOnlyTBuffer; + else + bindType = eBindType_ReadOnlyImage; + } + + bool usedSlot = bindMap != NULL && bindMap->used; + bool stageBitsIncluded = stageBits & ((ShaderStageBits)(1 << (int)stage.stage)); + + // skip descriptors that aren't for this shader stage + if(!usedSlot && !stageBitsIncluded) + return; + + if(bindType == eBindType_ConstantBuffer) + return; + + // TODO - check compatibility between bindType and shaderRes.resType ? + + // consider it filled if any array element is filled + bool filledSlot = false; + for(int idx = 0; slotBinds != NULL && idx < slotBinds->count; idx++) + { + filledSlot |= (*slotBinds)[idx].res != ResourceId(); + if(bindType == eBindType_Sampler || bindType == eBindType_ImageSampler) + filledSlot |= (*slotBinds)[idx].sampler != ResourceId(); + } + + // if it's masked out by stage bits, act as if it's not filled, so it's marked in red + if(!stageBitsIncluded) + filledSlot = false; + + if(showNode(usedSlot, filledSlot)) + { + QTreeWidgetItem *parentNode = resources->invisibleRootItem(); + + QString setname = QString::number(bindset); + + QString slotname = QString::number(bind); + if(shaderRes != NULL && shaderRes->name.count > 0) + slotname += ": " + ToQStr(shaderRes->name); + + int arrayLength = 0; + if(slotBinds != NULL) + arrayLength = slotBinds->count; + else + arrayLength = (int)bindMap->arraySize; + + // for arrays, add a parent element that we add the real cbuffers below + if(arrayLength > 1) + { + QTreeWidgetItem *node = + makeNode({"", setname, slotname, tr("Array[%1]").arg(arrayLength), "", "", "", ""}); + + if(!filledSlot) + setEmptyRow(node); + + if(!usedSlot) + setInactiveRow(node); + + resources->addTopLevelItem(node); + + // show the tree column + resources->showColumn(0); + parentNode = node; + } + + for(int idx = 0; idx < arrayLength; idx++) + { + const VulkanPipelineState::Pipeline::DescriptorSet::DescriptorBinding::BindingElement *descriptorBind = + NULL; + if(slotBinds != NULL) + descriptorBind = &(*slotBinds)[idx]; + + if(arrayLength > 1) + { + if(shaderRes != NULL && shaderRes->name.count > 0) + slotname = QString("%1[%2]: %3").arg(bind).arg(idx).arg(ToQStr(shaderRes->name)); + else + slotname = QString("%1[%2]").arg(bind).arg(idx); + } + + bool isbuf = false; + uint32_t w = 1, h = 1, d = 1; + uint32_t a = 1; + uint32_t samples = 1; + uint64_t len = 0; + QString format = "Unknown"; + QString name = "Empty"; + ShaderResourceType restype = eResType_None; + QVariant tag; + + FetchTexture *tex = NULL; + FetchBuffer *buf = NULL; + + if(filledSlot && descriptorBind != NULL) + { + name = "Object " + ToQStr(descriptorBind->res); + + format = ToQStr(descriptorBind->viewfmt.strname); + + // check to see if it's a texture + tex = m_Ctx->GetTexture(descriptorBind->res); + if(tex) + { + w = tex->width; + h = tex->height; + d = tex->depth; + a = tex->arraysize; + name = tex->name; + restype = tex->resType; + samples = tex->msSamp; + + tag = QVariant::fromValue(descriptorBind->res); + } + + // if not a texture, it must be a buffer + buf = m_Ctx->GetBuffer(descriptorBind->res); + if(buf) + { + len = buf->length; + w = 0; + h = 0; + d = 0; + a = 0; + name = buf->name; + restype = eResType_Buffer; + + ulong descriptorLen = descriptorBind->size; + + if(descriptorLen == 0xFFFFFFFFFFFFFFFFULL) + descriptorLen = len - descriptorBind->offset; + + tag = QVariant::fromValue( + BufferTag(isrw, bindPoint, buf->ID, descriptorBind->offset, descriptorLen)); + + isbuf = true; + } + } + else + { + name = "Empty"; + format = "-"; + w = h = d = a = 0; + } + + QTreeWidgetItem *node = NULL; + QTreeWidgetItem *samplerNode = NULL; + + if(bindType == eBindType_ReadWriteBuffer || bindType == eBindType_ReadOnlyTBuffer || + bindType == eBindType_ReadWriteTBuffer) + { + if(!isbuf) + { + node = makeNode({ + "", bindset, slotname, ToQStr(bindType), "-", "-", "", + }); + + setEmptyRow(node); + } + else + { + QString range = "-"; + if(descriptorBind != NULL) + range = QString("%1 - %2").arg(descriptorBind->offset).arg(descriptorBind->size); + + node = makeNode({ + "", bindset, slotname, ToQStr(bindType), name, QString("%1 bytes").arg(len), range, + }); + + resources->setHoverIcons(node, action, action_hover); + + node->setData(0, Qt::UserRole, tag); + + if(!filledSlot) + setEmptyRow(node); + + if(!usedSlot) + setInactiveRow(node); + } + } + else if(bindType == eBindType_Sampler) + { + if(descriptorBind == NULL || descriptorBind->sampler == ResourceId()) + { + node = makeNode({ + "", bindset, slotname, ToQStr(bindType), "-", "-", "", + }); + + setEmptyRow(node); + } + else + { + node = makeNode(makeSampler(QString::number(bindset), slotname, *descriptorBind)); + + if(!filledSlot) + setEmptyRow(node); + + if(!usedSlot) + setInactiveRow(node); + + SamplerData sampData; + sampData.node = node; + node->setData(0, Qt::UserRole, QVariant::fromValue(sampData)); + + if(!samplers.contains(descriptorBind->sampler)) + samplers.insert(descriptorBind->sampler, sampData); + } + } + else + { + if(descriptorBind == NULL || descriptorBind->res == ResourceId()) + { + node = makeNode({ + "", bindset, slotname, ToQStr(bindType), "-", "-", "", + }); + + setEmptyRow(node); + } + else + { + QString typeName = ToQStr(restype) + " " + ToQStr(bindType); + + QString dim; + + if(restype == eResType_Texture3D) + dim = QString("%1x%2x%3").arg(w).arg(h).arg(d); + else if(restype == eResType_Texture1D || restype == eResType_Texture1DArray) + dim = QString::number(w); + else + dim = QString("%1x%2").arg(w).arg(h); + + if(descriptorBind->swizzle[0] != eSwizzle_Red || + descriptorBind->swizzle[1] != eSwizzle_Green || + descriptorBind->swizzle[2] != eSwizzle_Blue || + descriptorBind->swizzle[3] != eSwizzle_Alpha) + { + format += tr(" swizzle[%1%2%3%4]") + .arg(ToQStr(descriptorBind->swizzle[0])) + .arg(ToQStr(descriptorBind->swizzle[1])) + .arg(ToQStr(descriptorBind->swizzle[2])) + .arg(ToQStr(descriptorBind->swizzle[3])); + } + + if(restype == eResType_Texture1DArray || restype == eResType_Texture2DArray || + restype == eResType_Texture2DMSArray || restype == eResType_TextureCubeArray) + { + dim += QString(" %1[%2]").arg(ToQStr(restype)).arg(a); + } + + if(restype == eResType_Texture2DMS || restype == eResType_Texture2DMSArray) + dim += QString(", %1x MSAA").arg(samples); + + node = makeNode({ + "", bindset, slotname, typeName, name, dim, format, + }); + + resources->setHoverIcons(node, action, action_hover); + + node->setData(0, Qt::UserRole, tag); + + if(!filledSlot) + setEmptyRow(node); + + if(!usedSlot) + setInactiveRow(node); + } + + if(bindType == eBindType_ImageSampler) + { + if(descriptorBind == NULL || descriptorBind->sampler == ResourceId()) + { + samplerNode = makeNode({ + "", bindset, slotname, bindType, "-", "-", "", + }); + + setEmptyRow(node); + } + else + { + if(!samplers.contains(descriptorBind->sampler)) + { + samplerNode = makeNode(makeSampler("", "", *descriptorBind)); + + if(!filledSlot) + setEmptyRow(samplerNode); + + if(!usedSlot) + setInactiveRow(samplerNode); + + SamplerData sampData; + sampData.node = samplerNode; + samplerNode->setData(0, Qt::UserRole, QVariant::fromValue(sampData)); + + samplers.insert(descriptorBind->sampler, sampData); + } + + if(node != NULL) + { + m_CombinedImageSamplers[node] = samplers[descriptorBind->sampler].node; + samplers[descriptorBind->sampler].images.push_back(node); + } + } + } + } + + if(descriptorBind && tex) + setViewDetails(node, *descriptorBind, tex); + else if(descriptorBind && buf) + setViewDetails(node, *descriptorBind, buf); + + parentNode->addChild(node); + + if(samplerNode) + parentNode->addChild(samplerNode); + } + } +} + +void VulkanPipelineStateViewer::addConstantBlockRow(ShaderReflection *shaderDetails, + const VulkanPipelineState::ShaderStage &stage, + int bindset, int bind, + const VulkanPipelineState::Pipeline &pipe, + RDTreeWidget *ubos) +{ + const ConstantBlock *cblock = NULL; + const BindpointMap *bindMap = NULL; + + QIcon action(QPixmap(QString::fromUtf8(":/Resources/action.png"))); + QIcon action_hover(QPixmap(QString::fromUtf8(":/Resources/action_hover.png"))); + + uint32_t slot = ~0U; + if(shaderDetails != NULL) + { + for(slot = 0; slot < (uint)shaderDetails->ConstantBlocks.count; slot++) + { + ConstantBlock cb = shaderDetails->ConstantBlocks[slot]; + if(stage.BindpointMapping.ConstantBlocks[cb.bindPoint].bindset == bindset && + stage.BindpointMapping.ConstantBlocks[cb.bindPoint].bind == bind) + { + cblock = &cb; + bindMap = &stage.BindpointMapping.ConstantBlocks[cb.bindPoint]; + break; + } + } + + if(slot >= (uint)shaderDetails->ConstantBlocks.count) + slot = ~0U; + } + + const rdctype::array + *slotBinds = NULL; + ShaderBindType bindType = eBindType_ConstantBuffer; + ShaderStageBits stageBits = (ShaderStageBits)0; + + if(bindset < pipe.DescSets.count && bind < pipe.DescSets[bindset].bindings.count) + { + slotBinds = &pipe.DescSets[bindset].bindings[bind].binds; + bindType = pipe.DescSets[bindset].bindings[bind].type; + stageBits = pipe.DescSets[bindset].bindings[bind].stageFlags; + } + + bool usedSlot = bindMap != NULL && bindMap->used; + bool stageBitsIncluded = stageBits & ((ShaderStageBits)(1 << (int)stage.stage)); + + // skip descriptors that aren't for this shader stage + if(!usedSlot && !stageBitsIncluded) + return; + + if(bindType != eBindType_ConstantBuffer) + return; + + // consider it filled if any array element is filled (or it's push constants) + bool filledSlot = cblock != NULL && !cblock->bufferBacked; + for(int idx = 0; slotBinds != NULL && idx < slotBinds->count; idx++) + filledSlot |= (*slotBinds)[idx].res != ResourceId(); + + // if it's masked out by stage bits, act as if it's not filled, so it's marked in red + if(!stageBitsIncluded) + filledSlot = false; + + if(showNode(usedSlot, filledSlot)) + { + QTreeWidgetItem *parentNode = ubos->invisibleRootItem(); + + QString setname = QString::number(bindset); + + QString slotname = QString::number(bind); + if(cblock != NULL && cblock->name.count > 0) + slotname += ": " + ToQStr(cblock->name); + + int arrayLength = 0; + if(slotBinds != NULL) + arrayLength = slotBinds->count; + else + arrayLength = (int)bindMap->arraySize; + + // for arrays, add a parent element that we add the real cbuffers below + if(arrayLength > 1) + { + QTreeWidgetItem *node = + makeNode({"", setname, slotname, tr("Array[%1]").arg(arrayLength), "", ""}); + + if(!filledSlot) + setEmptyRow(node); + + if(!usedSlot) + setInactiveRow(node); + + parentNode = node; + + ubos->showColumn(0); + } + + for(int idx = 0; idx < arrayLength; idx++) + { + const VulkanPipelineState::Pipeline::DescriptorSet::DescriptorBinding::BindingElement *descriptorBind = + NULL; + if(slotBinds != NULL) + descriptorBind = &(*slotBinds)[idx]; + + if(arrayLength > 1) + { + if(cblock != NULL && cblock->name.count > 0) + slotname = QString("%1[%2]: %3").arg(bind).arg(idx).arg(ToQStr(cblock->name)); + else + slotname = QString("%1[%2]").arg(bind).arg(idx); + } + + QString name = "Empty"; + uint64_t length = 0; + int numvars = cblock != NULL ? cblock->variables.count : 0; + uint64_t byteSize = cblock != NULL ? cblock->byteSize : 0; + + QString vecrange = "-"; + + if(filledSlot && descriptorBind != NULL) + { + name = ""; + length = descriptorBind->size; + + FetchBuffer *buf = m_Ctx->GetBuffer(descriptorBind->res); + if(buf) + { + name = buf->name; + if(length == 0xFFFFFFFFFFFFFFFFULL) + length = buf->length - descriptorBind->offset; + } + + if(name == "") + name = "UBO " + ToQStr(descriptorBind->res); + + vecrange = + QString("%1 - %2").arg(descriptorBind->offset).arg(descriptorBind->offset + length); + } + + QString sizestr; + + // push constants or specialization constants + if(cblock != NULL && !cblock->bufferBacked) + { + setname = ""; + slotname = cblock->name; + name = "Push constants"; + vecrange = ""; + sizestr = tr("%1 Variables").arg(numvars); + + // could maybe get range from ShaderVariable.reg if it's filled out + // from SPIR-V side. + } + else + { + if(length == byteSize) + sizestr = tr("%1 Variables, %2 bytes").arg(numvars).arg(length); + else + sizestr = + tr("%1 Variables, %2 bytes needed, %3 provided").arg(numvars).arg(byteSize).arg(length); + + if(length < byteSize) + filledSlot = false; + } + + QTreeWidgetItem *node = makeNode({"", setname, slotname, name, vecrange, sizestr}); + + ubos->setHoverIcons(node, action, action_hover); + + node->setData(0, Qt::UserRole, QVariant::fromValue(CBufferTag(slot, (uint)idx))); + + if(!filledSlot) + setEmptyRow(node); + + if(!usedSlot) + setInactiveRow(node); + + parentNode->addChild(node); + } + } +} + +void VulkanPipelineStateViewer::setShaderState(const VulkanPipelineState::ShaderStage &stage, + const VulkanPipelineState::Pipeline &pipe, + QLabel *shader, RDTreeWidget *resources, + RDTreeWidget *ubos) +{ + ShaderReflection *shaderDetails = stage.ShaderDetails; + + QIcon action(QPixmap(QString::fromUtf8(":/Resources/action.png"))); + QIcon action_hover(QPixmap(QString::fromUtf8(":/Resources/action_hover.png"))); + + if(stage.Shader == ResourceId()) + shader->setText(tr("Unbound Shader")); + else + shader->setText(ToQStr(stage.ShaderName)); + + if(shaderDetails != NULL && shaderDetails->DebugInfo.entryFunc.count > 0) + { + QString entryFunc = ToQStr(shaderDetails->DebugInfo.entryFunc); + if(shaderDetails->DebugInfo.files.count > 0 || entryFunc != "main") + shader->setText(entryFunc + "()"); + + if(shaderDetails->DebugInfo.files.count > 0) + { + QString shaderfn = ""; + + int entryFile = shaderDetails->DebugInfo.entryFile; + if(entryFile < 0 || entryFile >= shaderDetails->DebugInfo.files.count) + entryFile = 0; + + shaderfn = ToQStr(shaderDetails->DebugInfo.files[entryFile].first); + + shader->setText(entryFunc + "() - " + shaderfn); + } + } + + int vs = 0; + + // hide the tree columns. The functions below will add it + // if any array bindings are present + resources->hideColumn(0); + ubos->hideColumn(0); + + vs = resources->verticalScrollBar()->value(); + resources->setUpdatesEnabled(false); + resources->clear(); + + QMap samplers; + + for(int bindset = 0; bindset < pipe.DescSets.count; bindset++) + { + for(int bind = 0; bind < pipe.DescSets[bindset].bindings.count; bind++) + { + addResourceRow(shaderDetails, stage, bindset, bind, pipe, resources, samplers); + } + + // if we have a shader bound, go through and add rows for any resources it wants for binds that + // aren't + // in this descriptor set (e.g. if layout mismatches) + if(shaderDetails != NULL) + { + for(int i = 0; i < shaderDetails->ReadOnlyResources.count; i++) + { + const ShaderResource &ro = shaderDetails->ReadOnlyResources[i]; + + if(stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bindset == bindset && + stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bind >= + pipe.DescSets[bindset].bindings.count) + { + addResourceRow(shaderDetails, stage, bindset, + stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bind, pipe, + resources, samplers); + } + } + + for(int i = 0; i < shaderDetails->ReadWriteResources.count; i++) + { + const ShaderResource &rw = shaderDetails->ReadWriteResources[i]; + + if(stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bindset == bindset && + stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bind >= + pipe.DescSets[bindset].bindings.count) + { + addResourceRow(shaderDetails, stage, bindset, + stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bind, pipe, + resources, samplers); + } + } + } + } + + // if we have a shader bound, go through and add rows for any resources it wants for descriptor + // sets that aren't + // bound at all + if(shaderDetails != NULL) + { + for(int i = 0; i < shaderDetails->ReadOnlyResources.count; i++) + { + const ShaderResource &ro = shaderDetails->ReadOnlyResources[i]; + + if(stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bindset >= pipe.DescSets.count) + { + addResourceRow( + shaderDetails, stage, stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bindset, + stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bind, pipe, resources, samplers); + } + } + + for(int i = 0; i < shaderDetails->ReadWriteResources.count; i++) + { + const ShaderResource &rw = shaderDetails->ReadWriteResources[i]; + + if(stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bindset >= pipe.DescSets.count) + { + addResourceRow( + shaderDetails, stage, stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bindset, + stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bind, pipe, resources, samplers); + } + } + } + + resources->clearSelection(); + resources->setUpdatesEnabled(true); + resources->verticalScrollBar()->setValue(vs); + + vs = ubos->verticalScrollBar()->value(); + ubos->setUpdatesEnabled(false); + ubos->clear(); + for(int bindset = 0; bindset < pipe.DescSets.count; bindset++) + { + for(int bind = 0; bind < pipe.DescSets[bindset].bindings.count; bind++) + { + addConstantBlockRow(shaderDetails, stage, bindset, bind, pipe, ubos); + } + + // if we have a shader bound, go through and add rows for any cblocks it wants for binds that + // aren't + // in this descriptor set (e.g. if layout mismatches) + if(shaderDetails != NULL) + { + for(int i = 0; i < shaderDetails->ConstantBlocks.count; i++) + { + ConstantBlock &cb = shaderDetails->ConstantBlocks[i]; + + if(stage.BindpointMapping.ConstantBlocks[cb.bindPoint].bindset == bindset && + stage.BindpointMapping.ConstantBlocks[cb.bindPoint].bind >= + pipe.DescSets[bindset].bindings.count) + { + addConstantBlockRow(shaderDetails, stage, bindset, + stage.BindpointMapping.ConstantBlocks[cb.bindPoint].bind, pipe, ubos); + } + } + } + } + + // if we have a shader bound, go through and add rows for any resources it wants for descriptor + // sets that aren't + // bound at all + if(shaderDetails != NULL) + { + for(int i = 0; i < shaderDetails->ConstantBlocks.count; i++) + { + ConstantBlock &cb = shaderDetails->ConstantBlocks[i]; + + if(stage.BindpointMapping.ConstantBlocks[cb.bindPoint].bindset >= pipe.DescSets.count && + cb.bufferBacked) + { + addConstantBlockRow(shaderDetails, stage, + stage.BindpointMapping.ConstantBlocks[cb.bindPoint].bindset, + stage.BindpointMapping.ConstantBlocks[cb.bindPoint].bind, pipe, ubos); + } + } + } + + // search for push constants and add them last + if(shaderDetails != NULL) + { + for(int cb = 0; cb < shaderDetails->ConstantBlocks.count; cb++) + { + ConstantBlock &cblock = shaderDetails->ConstantBlocks[cb]; + if(cblock.bufferBacked == false) + { + // could maybe get range from ShaderVariable.reg if it's filled out + // from SPIR-V side. + + QTreeWidgetItem *node = makeNode({"", "", ToQStr(cblock.name), "Push constants", "", + tr("%1 Variable(s)", "", cblock.variables.count)}); + + ubos->setHoverIcons(node, action, action_hover); + node->setData(0, Qt::UserRole, QVariant::fromValue(CBufferTag(cb, 0))); + + ubos->addTopLevelItem(node); + } + } + } + ubos->clearSelection(); + ubos->setUpdatesEnabled(true); + ubos->verticalScrollBar()->setValue(vs); +} + +void VulkanPipelineStateViewer::setState() +{ + if(!m_Ctx->LogLoaded()) + { + clearState(); + return; + } + + m_CombinedImageSamplers.clear(); + + const VulkanPipelineState &state = m_Ctx->CurVulkanPipelineState; + const FetchDrawcall *draw = m_Ctx->CurDrawcall(); + + bool showDisabled = ui->showDisabled->isChecked(); + bool showEmpty = ui->showEmpty->isChecked(); + + QPixmap tick(QString::fromUtf8(":/Resources/tick.png")); + QPixmap cross(QString::fromUtf8(":/Resources/cross.png")); + + QIcon action(QPixmap(QString::fromUtf8(":/Resources/action.png"))); + QIcon action_hover(QPixmap(QString::fromUtf8(":/Resources/action_hover.png"))); + + bool usedBindings[128] = {}; + + //////////////////////////////////////////////// + // Vertex Input + + int vs = 0; + + vs = ui->viAttrs->verticalScrollBar()->value(); + ui->viAttrs->setUpdatesEnabled(false); + ui->viAttrs->clear(); + { + int i = 0; + for(const VulkanPipelineState::VertexInput::Attribute &a : state.VI.attrs) + { + bool filledSlot = true; + bool usedSlot = false; + + QString name = tr("Attribute %1").arg(i); + + if(state.VS.Shader != ResourceId()) + { + int attrib = -1; + if((int32_t)a.location < state.VS.BindpointMapping.InputAttributes.count) + attrib = state.VS.BindpointMapping.InputAttributes[a.location]; + + if(attrib >= 0 && attrib < state.VS.ShaderDetails->InputSig.count) + { + name = state.VS.ShaderDetails->InputSig[attrib].varName; + usedSlot = true; + } + } + + if(showNode(usedSlot, filledSlot)) + { + QTreeWidgetItem *node = + makeNode({i, name, a.location, a.binding, ToQStr(a.format.strname), a.byteoffset}); + + usedBindings[a.binding] = true; + + ui->viAttrs->setHoverIcons(node, action, action_hover); + + if(!usedSlot) + setInactiveRow(node); + + ui->viAttrs->addTopLevelItem(node); + } + + i++; + } + } + ui->viAttrs->clearSelection(); + ui->viAttrs->setUpdatesEnabled(true); + ui->viAttrs->verticalScrollBar()->setValue(vs); + + m_BindNodes.clear(); + + PrimitiveTopology topo = draw != NULL ? draw->topology : eTopology_Unknown; + + if(topo > eTopology_PatchList) + { + int numCPs = (int)topo - (int)eTopology_PatchList_1CPs + 1; + + ui->topology->setText(QString("PatchList (%1 Control Points)").arg(numCPs)); + } + else + { + ui->topology->setText(ToQStr(topo)); + } + + ui->primRestart->setVisible(state.IA.primitiveRestartEnable); + + switch(topo) + { + case eTopology_PointList: + ui->topologyDiagram->setPixmap( + QPixmap(QString::fromUtf8(":/Resources/topologies/topo_pointlist.png"))); + break; + case eTopology_LineList: + ui->topologyDiagram->setPixmap( + QPixmap(QString::fromUtf8(":/Resources/topologies/topo_linelist.png"))); + break; + case eTopology_LineStrip: + ui->topologyDiagram->setPixmap( + QPixmap(QString::fromUtf8(":/Resources/topologies/topo_linestrip.png"))); + break; + case eTopology_TriangleList: + ui->topologyDiagram->setPixmap( + QPixmap(QString::fromUtf8(":/Resources/topologies/topo_trilist.png"))); + break; + case eTopology_TriangleStrip: + ui->topologyDiagram->setPixmap( + QPixmap(QString::fromUtf8(":/Resources/topologies/topo_tristrip.png"))); + break; + case eTopology_LineList_Adj: + ui->topologyDiagram->setPixmap( + QPixmap(QString::fromUtf8(":/Resources/topologies/topo_linelist_adj.png"))); + break; + case eTopology_LineStrip_Adj: + ui->topologyDiagram->setPixmap( + QPixmap(QString::fromUtf8(":/Resources/topologies/topo_linestrip_adj.png"))); + break; + case eTopology_TriangleList_Adj: + ui->topologyDiagram->setPixmap( + QPixmap(QString::fromUtf8(":/Resources/topologies/topo_trilist_adj.png"))); + break; + case eTopology_TriangleStrip_Adj: + ui->topologyDiagram->setPixmap( + QPixmap(QString::fromUtf8(":/Resources/topologies/topo_tristrip_adj.png"))); + break; + default: + ui->topologyDiagram->setPixmap( + QPixmap(QString::fromUtf8(":/Resources/topologies/topo_patch.png"))); + break; + } + + vs = ui->viBuffers->verticalScrollBar()->value(); + ui->viBuffers->setUpdatesEnabled(false); + ui->viBuffers->clear(); + + bool ibufferUsed = draw != NULL && (draw->flags & eDraw_UseIBuffer); + + if(state.IA.ibuffer.buf != ResourceId()) + { + if(ibufferUsed || showDisabled) + { + QString name = "Buffer " + ToQStr(state.IA.ibuffer.buf); + uint64_t length = 1; + + if(!ibufferUsed) + length = 0; + + FetchBuffer *buf = m_Ctx->GetBuffer(state.IA.ibuffer.buf); + + if(buf) + { + name = buf->name; + length = buf->length; + } + + QTreeWidgetItem *node = makeNode( + {"Index", name, "Index", state.IA.ibuffer.offs, draw->indexByteWidth, length, ""}); + + ui->viBuffers->setHoverIcons(node, action, action_hover); + + node->setData( + 0, Qt::UserRole, + QVariant::fromValue(VBIBTag(state.IA.ibuffer.buf, draw != NULL ? draw->indexOffset : 0))); + + if(!ibufferUsed) + setInactiveRow(node); + + if(state.IA.ibuffer.buf == ResourceId()) + setEmptyRow(node); + + ui->viBuffers->addTopLevelItem(node); + } + } + else + { + if(ibufferUsed || showEmpty) + { + QTreeWidgetItem *node = makeNode({"Index", tr("No Buffer Set"), "Index", "-", "-", "-", ""}); + + ui->viBuffers->setHoverIcons(node, action, action_hover); + + node->setData( + 0, Qt::UserRole, + QVariant::fromValue(VBIBTag(state.IA.ibuffer.buf, draw != NULL ? draw->indexOffset : 0))); + + setEmptyRow(node); + + if(!ibufferUsed) + setInactiveRow(node); + + ui->viBuffers->addTopLevelItem(node); + } + } + + m_VBNodes.clear(); + + { + int i = 0; + for(; i < qMax(state.VI.vbuffers.count, state.VI.binds.count); i++) + { + const VulkanPipelineState::VertexInput::VertexBuffer *vbuff = + (i < state.VI.vbuffers.count ? &state.VI.vbuffers[i] : NULL); + const VulkanPipelineState::VertexInput::Binding *bind = NULL; + + for(int b = 0; b < state.VI.binds.count; b++) + { + if(state.VI.binds[b].vbufferBinding == (uint32_t)i) + bind = &state.VI.binds[b]; + } + + bool filledSlot = ((vbuff != NULL && vbuff->buffer != ResourceId()) || bind != NULL); + bool usedSlot = (usedBindings[i]); + + if(showNode(usedSlot, filledSlot)) + { + QString name = tr("No Buffer"); + QString rate = "-"; + uint64_t length = 1; + uint64_t offset = 0; + uint32_t stride = 0; + + if(vbuff != NULL) + { + name = "Buffer " + ToQStr(vbuff->buffer); + offset = vbuff->offset; + + FetchBuffer *buf = m_Ctx->GetBuffer(vbuff->buffer); + if(buf) + { + name = buf->name; + length = buf->length; + } + } + + if(bind != NULL) + { + stride = bind->bytestride; + rate = bind->perInstance ? "Instance" : "Vertex"; + } + else + { + name += ", No Binding"; + } + + QTreeWidgetItem *node = NULL; + + if(filledSlot) + node = makeNode({i, name, rate, offset, stride, length, ""}); + else + node = makeNode({i, tr("No Binding"), "-", "-", "-", "-", ""}); + + ui->viBuffers->setHoverIcons(node, action, action_hover); + + node->setData(0, Qt::UserRole, + QVariant::fromValue(VBIBTag(vbuff != NULL ? vbuff->buffer : ResourceId(), + vbuff != NULL ? vbuff->offset : 0))); + + if(!filledSlot || bind == NULL || vbuff == NULL) + setEmptyRow(node); + + if(!usedSlot) + setInactiveRow(node); + + m_VBNodes.push_back(node); + + ui->viBuffers->addTopLevelItem(node); + } + } + + for(; i < ARRAY_COUNT(usedBindings); i++) + { + if(usedBindings[i]) + { + QTreeWidgetItem *node = makeNode({i, tr("No Binding"), "-", "-", "-", "-", ""}); + + ui->viBuffers->setHoverIcons(node, action, action_hover); + + node->setData(0, Qt::UserRole, QVariant::fromValue(VBIBTag(ResourceId(), 0))); + + setEmptyRow(node); + + setInactiveRow(node); + + ui->viBuffers->addTopLevelItem(node); + + m_VBNodes.push_back(node); + } + } + } + ui->viBuffers->clearSelection(); + ui->viBuffers->setUpdatesEnabled(true); + ui->viBuffers->verticalScrollBar()->setValue(vs); + + setShaderState(state.VS, state.graphics, ui->vsShader, ui->vsResources, ui->vsUBOs); + setShaderState(state.GS, state.graphics, ui->gsShader, ui->gsResources, ui->gsUBOs); + setShaderState(state.TCS, state.graphics, ui->tcsShader, ui->tcsResources, ui->tcsUBOs); + setShaderState(state.TES, state.graphics, ui->tesShader, ui->tesResources, ui->tesUBOs); + setShaderState(state.FS, state.graphics, ui->fsShader, ui->fsResources, ui->fsUBOs); + setShaderState(state.CS, state.compute, ui->csShader, ui->csResources, ui->csUBOs); + + //////////////////////////////////////////////// + // Rasterizer + + vs = ui->viewports->verticalScrollBar()->value(); + ui->viewports->setUpdatesEnabled(false); + ui->viewports->clear(); + + int vs2 = ui->scissors->verticalScrollBar()->value(); + ui->scissors->setUpdatesEnabled(false); + ui->scissors->clear(); + + if(state.Pass.renderpass.obj != ResourceId()) + { + ui->scissors->addTopLevelItem( + makeNode({"Render Area", state.Pass.renderArea.x, state.Pass.renderArea.y, + state.Pass.renderArea.width, state.Pass.renderArea.height})); + } + + { + int i = 0; + for(const VulkanPipelineState::ViewState::ViewportScissor &v : state.VP.viewportScissors) + { + QTreeWidgetItem *node = + makeNode({i, v.vp.x, v.vp.y, v.vp.width, v.vp.height, v.vp.minDepth, v.vp.maxDepth}); + ui->viewports->addTopLevelItem(node); + + if(v.vp.width == 0 || v.vp.height == 0) + setEmptyRow(node); + + node = makeNode({i, v.scissor.x, v.scissor.y, v.scissor.width, v.scissor.height}); + ui->scissors->addTopLevelItem(node); + + if(v.scissor.width == 0 || v.scissor.height == 0) + setEmptyRow(node); + + i++; + } + } + + ui->viewports->verticalScrollBar()->setValue(vs); + ui->viewports->clearSelection(); + ui->scissors->clearSelection(); + ui->scissors->verticalScrollBar()->setValue(vs2); + + ui->viewports->setUpdatesEnabled(true); + ui->scissors->setUpdatesEnabled(true); + + ui->fillMode->setText(ToQStr(state.RS.FillMode)); + ui->cullMode->setText(ToQStr(state.RS.CullMode)); + ui->frontCCW->setPixmap(state.RS.FrontCCW ? tick : cross); + + ui->depthBias->setText(Formatter::Format(state.RS.depthBias)); + ui->depthBiasClamp->setText(Formatter::Format(state.RS.depthBiasClamp)); + ui->slopeScaledBias->setText(Formatter::Format(state.RS.slopeScaledDepthBias)); + + ui->depthClamp->setPixmap(state.RS.depthClampEnable ? tick : cross); + ui->rasterizerDiscard->setPixmap(state.RS.rasterizerDiscardEnable ? tick : cross); + ui->lineWidth->setText(Formatter::Format(state.RS.lineWidth)); + + ui->sampleCount->setText(QString::number(state.MSAA.rasterSamples)); + ui->sampleShading->setPixmap(state.MSAA.sampleShadingEnable ? tick : cross); + ui->minSampleShading->setText(Formatter::Format(state.MSAA.minSampleShading)); + ui->sampleMask->setText(QString("%1").arg(state.MSAA.sampleMask, 8, 16, QChar('0'))); + + //////////////////////////////////////////////// + // Output Merger + + bool targets[32] = {}; + + vs = ui->framebuffer->verticalScrollBar()->value(); + ui->framebuffer->setUpdatesEnabled(false); + ui->framebuffer->clear(); + { + int i = 0; + for(const VulkanPipelineState::CurrentPass::Framebuffer::Attachment &p : + state.Pass.framebuffer.attachments) + { + int colIdx = -1; + for(int c = 0; c < state.Pass.renderpass.colorAttachments.count; c++) + { + if(state.Pass.renderpass.colorAttachments[c] == (uint)i) + { + colIdx = c; + break; + } + } + + bool filledSlot = (p.img != ResourceId()); + bool usedSlot = (colIdx >= 0 || state.Pass.renderpass.depthstencilAttachment == i); + + if(showNode(usedSlot, filledSlot)) + { + uint32_t w = 1, h = 1, d = 1; + uint32_t a = 1; + QString format = ToQStr(p.viewfmt.strname); + QString name = "Texture " + ToQStr(p.img); + QString typeName = "Unknown"; + + if(p.img == ResourceId()) + { + name = "Empty"; + format = "-"; + typeName = "-"; + w = h = d = a = 0; + } + + FetchTexture *tex = m_Ctx->GetTexture(p.img); + if(tex) + { + w = tex->width; + h = tex->height; + d = tex->depth; + a = tex->arraysize; + name = tex->name; + typeName = ToQStr(tex->resType); + + if(!tex->customName && state.FS.ShaderDetails != NULL) + { + for(int s = 0; s < state.FS.ShaderDetails->OutputSig.count; s++) + { + if(state.FS.ShaderDetails->OutputSig[s].regIndex == (uint32_t)colIdx && + (state.FS.ShaderDetails->OutputSig[s].systemValue == eAttr_None || + state.FS.ShaderDetails->OutputSig[s].systemValue == eAttr_ColourOutput)) + { + name = QString("<%1>").arg(ToQStr(state.FS.ShaderDetails->OutputSig[s].varName)); + } + } + } + } + + if(p.swizzle[0] != eSwizzle_Red || p.swizzle[1] != eSwizzle_Green || + p.swizzle[2] != eSwizzle_Blue || p.swizzle[3] != eSwizzle_Alpha) + { + format += tr(" swizzle[%1%2%3%4]") + .arg(ToQStr(p.swizzle[0])) + .arg(ToQStr(p.swizzle[1])) + .arg(ToQStr(p.swizzle[2])) + .arg(ToQStr(p.swizzle[3])); + } + + QTreeWidgetItem *node = makeNode({i, name, typeName, w, h, d, a, format, ""}); + + ui->framebuffer->setHoverIcons(node, action, action_hover); + + if(tex) + node->setData(0, Qt::UserRole, QVariant::fromValue(p.img)); + + if(p.img == ResourceId()) + { + setEmptyRow(node); + } + else if(!usedSlot) + { + setInactiveRow(node); + } + else + { + targets[i] = true; + } + + setViewDetails(node, p, tex); + + ui->framebuffer->addTopLevelItem(node); + } + + i++; + } + } + + ui->framebuffer->clearSelection(); + ui->framebuffer->setUpdatesEnabled(true); + ui->framebuffer->verticalScrollBar()->setValue(vs); + + vs = ui->blends->verticalScrollBar()->value(); + ui->blends->setUpdatesEnabled(false); + ui->blends->clear(); + { + int i = 0; + for(const VulkanPipelineState::ColorBlend::Attachment &blend : state.CB.attachments) + { + bool filledSlot = true; + bool usedSlot = (targets[i]); + + if(showNode(usedSlot, filledSlot)) + { + QTreeWidgetItem *node = + makeNode({i, blend.blendEnable, + + ToQStr(blend.blend.Source), ToQStr(blend.blend.Destination), + ToQStr(blend.blend.Operation), + + ToQStr(blend.alphaBlend.Source), ToQStr(blend.alphaBlend.Destination), + ToQStr(blend.alphaBlend.Operation), + + QString("%1%2%3%4") + .arg((blend.writeMask & 0x1) == 0 ? "_" : "R") + .arg((blend.writeMask & 0x2) == 0 ? "_" : "G") + .arg((blend.writeMask & 0x4) == 0 ? "_" : "B") + .arg((blend.writeMask & 0x8) == 0 ? "_" : "A")}); + + if(!filledSlot) + setEmptyRow(node); + + if(!usedSlot) + setInactiveRow(node); + + ui->blends->addTopLevelItem(node); + } + + i++; + } + } + ui->blends->clearSelection(); + ui->blends->setUpdatesEnabled(true); + ui->blends->verticalScrollBar()->setValue(vs); + + ui->blendFactor->setText(QString("%1, %2, %3, %4") + .arg(state.CB.blendConst[0], 2) + .arg(state.CB.blendConst[1], 2) + .arg(state.CB.blendConst[2], 2) + .arg(state.CB.blendConst[3], 2)); + ui->logicOp->setText(state.CB.logicOpEnable ? ToQStr(state.CB.logicOp) : "-"); + ui->alphaToOne->setPixmap(state.CB.alphaToOneEnable ? tick : cross); + + ui->depthEnabled->setPixmap(state.DS.depthTestEnable ? tick : cross); + ui->depthFunc->setText(ToQStr(state.DS.depthCompareOp)); + ui->depthWrite->setPixmap(state.DS.depthWriteEnable ? tick : cross); + + if(state.DS.depthBoundsEnable) + { + ui->depthBounds->setText(Formatter::Format(state.DS.minDepthBounds) + "-" + + Formatter::Format(state.DS.maxDepthBounds)); + ui->depthBounds->setPixmap(QPixmap()); + } + else + { + ui->depthBounds->setText(""); + ui->depthBounds->setPixmap(cross); + } + + ui->stencils->setUpdatesEnabled(false); + ui->stencils->clear(); + if(state.DS.stencilTestEnable) + { + ui->stencils->addTopLevelItems( + {makeNode({"Front", ToQStr(state.DS.front.func), ToQStr(state.DS.front.failOp), + ToQStr(state.DS.front.depthFailOp), ToQStr(state.DS.front.passOp), + QString("%1").arg(state.DS.front.writeMask, 2, 16, QChar('0')), + QString("%1").arg(state.DS.front.compareMask, 2, 16, QChar('0')), + QString("%1").arg(state.DS.front.ref, 2, 16, QChar('0'))}), + makeNode({"Back", ToQStr(state.DS.back.func), ToQStr(state.DS.back.failOp), + ToQStr(state.DS.back.depthFailOp), ToQStr(state.DS.back.passOp), + QString("%1").arg(state.DS.back.writeMask, 2, 16, QChar('0')), + QString("%1").arg(state.DS.back.compareMask, 2, 16, QChar('0')), + QString("%1").arg(state.DS.back.ref, 2, 16, QChar('0'))})}); + } + else + { + ui->stencils->addTopLevelItems({makeNode({"Front", "-", "-", "-", "-", "-", "-", "-"}), + makeNode({"Back", "-", "-", "-", "-", "-", "-", "-"})}); + } + ui->stencils->clearSelection(); + ui->stencils->setUpdatesEnabled(true); + +// highlight the appropriate stages in the flowchart +#if 0 + if(draw == null) + { + pipeFlow.SetStagesEnabled(new bool[] { true, true, true, true, true, true, true, true, true }); + } + else if((draw.flags & DrawcallFlags.Dispatch) != 0) + { + pipeFlow.SetStagesEnabled(new bool[] { false, false, false, false, false, false, false, false, true }); + } + else + { + pipeFlow.SetStagesEnabled(new bool[] { + true, + true, + state.TCS.Shader != ResourceId(), + state.TES.Shader != ResourceId(), + state.GS.Shader != ResourceId(), + true, + state.FS.Shader != ResourceId(), + true, + false + }); + + // if(streamout only) + //{ + // pipeFlow.Rasterizer = false; + // pipeFlow.OutputMerger = false; + //} + } +#endif +} + +QString VulkanPipelineStateViewer::formatMembers(int indent, const QString &nameprefix, + const rdctype::array &vars) +{ + QString indentstr(indent * 4, QChar(' ')); + + QString ret = ""; + + int i = 0; + + for(const ShaderConstant &v : vars) + { + if(v.type.members.count > 0) + { + if(i > 0) + ret += "\n"; + ret += indentstr + QString("// struct %1\n").arg(ToQStr(v.type.descriptor.name)); + ret += indentstr + "{\n" + formatMembers(indent + 1, ToQStr(v.name) + "_", v.type.members) + + indentstr + "}\n"; + if(i < vars.count - 1) + ret += "\n"; + } + else + { + QString arr = ""; + if(v.type.descriptor.elements > 1) + arr = QString("[%1]").arg(v.type.descriptor.elements); + ret += indentstr + ToQStr(v.type.descriptor.name) + " " + nameprefix + v.name + arr + ";\n"; + } + + i++; + } + + return ret; +} + +void VulkanPipelineStateViewer::resource_itemActivated(QTreeWidgetItem *item, int column) +{ + const VulkanPipelineState::ShaderStage *stage = stageForSender(item->treeWidget()); + + if(stage == NULL) + return; + + QVariant tag = item->data(0, Qt::UserRole); + + if(tag.canConvert()) + { + FetchTexture *tex = m_Ctx->GetTexture(tag.value()); + + if(tex) + { + 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); + } + else + { + if(!m_Ctx->hasTextureViewer()) + m_Ctx->showTextureViewer(); + TextureViewer *viewer = m_Ctx->textureViewer(); + viewer->ViewTexture(tex->ID, true); + } + + return; + } + } + else if(tag.canConvert()) + { + BufferTag buf = tag.value(); + + const ShaderResource &shaderRes = buf.rwRes + ? stage->ShaderDetails->ReadWriteResources[buf.bindPoint] + : stage->ShaderDetails->ReadOnlyResources[buf.bindPoint]; + + QString format = QString("// struct %1\n").arg(ToQStr(shaderRes.variableType.descriptor.name)); + + if(shaderRes.variableType.members.count > 1) + { + format += "// members skipped as they are fixed size:\n"; + for(int i = 0; i < shaderRes.variableType.members.count - 1; i++) + format += QString("%1 %2;\n") + .arg(ToQStr(shaderRes.variableType.members[i].type.descriptor.name)) + .arg(ToQStr(shaderRes.variableType.members[i].name)); + } + + if(shaderRes.variableType.members.count > 0) + { + format += + "{\n" + formatMembers(1, "", shaderRes.variableType.members.back().type.members) + "}"; + } + else + { + const auto &desc = shaderRes.variableType.descriptor; + + format = ""; + if(desc.rowMajorStorage) + format += "row_major "; + + format += ToQStr(desc.type); + 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; + + if(desc.name.count > 0) + format += " " + ToQStr(desc.name); + + if(desc.elements > 1) + format += QString("[%1]").arg(desc.elements); + } + + if(buf.ID != ResourceId()) + { + // 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); + } + } +} + +void VulkanPipelineStateViewer::on_viAttrs_itemActivated(QTreeWidgetItem *item, int column) +{ + // TODO Buffer Viewer + // if(!m_Ctx->hasMeshOutput()) + // m_Ctx->showMeshOutput(); + // ToolWindowManager::raiseToolWindow(m_Ctx->meshOutput()); +} + +void VulkanPipelineStateViewer::on_viBuffers_itemActivated(QTreeWidgetItem *item, int column) +{ + QVariant tag = item->data(0, Qt::UserRole); + + if(tag.canConvert()) + { + VBIBTag buf = tag.value(); + + 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); + } + } +} + +void VulkanPipelineStateViewer::highlightIABind(int slot) +{ + int idx = ((slot + 1) * 21) % 32; // space neighbouring colours reasonably distinctly + + const VulkanPipelineState::VertexInput &VI = m_Ctx->CurVulkanPipelineState.VI; + + QColor col = QColor::fromHslF(float(idx) / 32.0f, 1.0f, 0.95f); + + if(slot < m_VBNodes.count()) + { + QTreeWidgetItem *item = m_VBNodes[(int)slot]; + + for(int c = 0; c < item->columnCount(); c++) + item->setBackground(c, QBrush(col)); + } + + if(slot < m_BindNodes.count()) + { + QTreeWidgetItem *item = m_BindNodes[(int)slot]; + + for(int c = 0; c < item->columnCount(); c++) + item->setBackground(c, QBrush(col)); + } + + for(int i = 0; i < ui->viAttrs->topLevelItemCount(); i++) + { + QTreeWidgetItem *item = ui->viAttrs->topLevelItem(i); + + QBrush itemBrush = QBrush(col); + + if((int)VI.attrs[i].binding != slot) + itemBrush = QBrush(); + + for(int c = 0; c < item->columnCount(); c++) + item->setBackground(c, itemBrush); + } +} + +void VulkanPipelineStateViewer::on_viAttrs_mouseMove(QMouseEvent *e) +{ + if(!m_Ctx->LogLoaded()) + return; + + QModelIndex idx = ui->viAttrs->indexAt(e->pos()); + + vertex_leave(NULL); + + const VulkanPipelineState::VertexInput &VI = m_Ctx->CurVulkanPipelineState.VI; + + if(idx.isValid()) + { + if(idx.row() >= 0 && idx.row() < VI.attrs.count) + { + uint32_t binding = VI.attrs[idx.row()].binding; + + highlightIABind((int)binding); + } + } +} + +void VulkanPipelineStateViewer::on_viBuffers_mouseMove(QMouseEvent *e) +{ + if(!m_Ctx->LogLoaded()) + return; + + QTreeWidgetItem *item = ui->viBuffers->itemAt(e->pos()); + + vertex_leave(NULL); + + if(item) + { + int idx = m_VBNodes.indexOf(item); + if(idx >= 0) + { + highlightIABind(idx); + } + else + { + for(int c = 0; c < item->columnCount(); c++) + item->setBackground(c, QBrush(ui->viBuffers->palette().color(QPalette::Window))); + } + } +} + +void VulkanPipelineStateViewer::vertex_leave(QEvent *e) +{ + for(int i = 0; i < ui->viAttrs->topLevelItemCount(); i++) + { + QTreeWidgetItem *item = ui->viAttrs->topLevelItem(i); + for(int c = 0; c < item->columnCount(); c++) + item->setBackground(c, QBrush()); + } + + for(int i = 0; i < ui->viBuffers->topLevelItemCount(); i++) + { + QTreeWidgetItem *item = ui->viBuffers->topLevelItem(i); + for(int c = 0; c < item->columnCount(); c++) + item->setBackground(c, QBrush()); + } +} + +void VulkanPipelineStateViewer::shaderView_clicked() +{ +} + +void VulkanPipelineStateViewer::shaderEdit_clicked() +{ +} + +void VulkanPipelineStateViewer::shaderSave_clicked() +{ + const VulkanPipelineState::ShaderStage *stage = + stageForSender(qobject_cast(QObject::sender())); + + if(stage == NULL) + return; + + ShaderReflection *shaderDetails = stage->ShaderDetails; + + if(stage->Shader == ResourceId()) + return; + + QString filename = + RDDialog::getSaveFileName(this, tr("Save Shader As"), QString(), "SPIR-V files (*.spv)"); + + if(filename != "") + { + QDir dirinfo = QFileInfo(filename).dir(); + if(dirinfo.exists()) + { + QFile f(filename); + if(f.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + f.write((const char *)shaderDetails->RawBytes.elems, (qint64)shaderDetails->RawBytes.count); + } + else + { + RDDialog::critical( + this, tr("Error saving shader"), + tr("Couldn't open path %1 for write.\n%2").arg(filename).arg(f.errorString())); + } + } + else + { + RDDialog::critical(this, tr("Invalid directory"), + tr("Cannot find target directory to save to")); + } + } +} + +void VulkanPipelineStateViewer::on_exportHTML_clicked() +{ +} + +void VulkanPipelineStateViewer::on_meshView_clicked() +{ +} diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.h new file mode 100644 index 000000000..8c9b26061 --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.h @@ -0,0 +1,120 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * 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. + ******************************************************************************/ + +#pragma once + +#include +#include "Code/CaptureContext.h" + +namespace Ui +{ +class VulkanPipelineStateViewer; +} + +class RDTreeWidget; +class QTreeWidgetItem; + +struct SamplerData +{ + SamplerData() : node(NULL) {} + QList images; + QTreeWidgetItem *node; +}; + +class VulkanPipelineStateViewer : public QFrame, public ILogViewerForm +{ + Q_OBJECT + +public: + explicit VulkanPipelineStateViewer(CaptureContext *ctx, QWidget *parent = 0); + ~VulkanPipelineStateViewer(); + + void OnLogfileLoaded(); + void OnLogfileClosed(); + void OnEventSelected(uint32_t eventID); + +private slots: + // automatic slots + void on_showDisabled_toggled(bool checked); + void on_showEmpty_toggled(bool checked); + void on_exportHTML_clicked(); + void on_meshView_clicked(); + void on_viAttrs_itemActivated(QTreeWidgetItem *item, int column); + void on_viBuffers_itemActivated(QTreeWidgetItem *item, int column); + void on_viAttrs_mouseMove(QMouseEvent *event); + void on_viBuffers_mouseMove(QMouseEvent *event); + + // manual slots + void shaderView_clicked(); + void shaderEdit_clicked(); + void shaderSave_clicked(); + void resource_itemActivated(QTreeWidgetItem *item, int column); + void vertex_leave(QEvent *e); + +private: + Ui::VulkanPipelineStateViewer *ui; + CaptureContext *m_Ctx; + + QVariantList makeSampler( + const QString &bindset, const QString &slotname, + const VulkanPipelineState::Pipeline::DescriptorSet::DescriptorBinding::BindingElement &descriptor); + void addResourceRow(ShaderReflection *shaderDetails, const VulkanPipelineState::ShaderStage &stage, + int bindset, int bind, const VulkanPipelineState::Pipeline &pipe, + RDTreeWidget *resources, QMap &samplers); + void addConstantBlockRow(ShaderReflection *shaderDetails, + const VulkanPipelineState::ShaderStage &stage, int bindset, int bind, + const VulkanPipelineState::Pipeline &pipe, RDTreeWidget *ubos); + + void setShaderState(const VulkanPipelineState::ShaderStage &stage, + const VulkanPipelineState::Pipeline &pipe, QLabel *shader, RDTreeWidget *res, + RDTreeWidget *ubo); + void clearShaderState(QLabel *shader, RDTreeWidget *res, RDTreeWidget *ubo); + void setState(); + void clearState(); + + void setInactiveRow(QTreeWidgetItem *node); + void setEmptyRow(QTreeWidgetItem *node); + void highlightIABind(int slot); + + QString formatMembers(int indent, const QString &nameprefix, + const rdctype::array &vars); + const VulkanPipelineState::ShaderStage *stageForSender(QWidget *widget); + + template + void setViewDetails(QTreeWidgetItem *node, const viewType &view, FetchTexture *tex); + + template + void setViewDetails(QTreeWidgetItem *node, const viewType &view, FetchBuffer *buf); + + QTreeWidgetItem *makeNode(const std::initializer_list &values); + QTreeWidgetItem *makeNode(const QVariantList &values); + bool showNode(bool usedSlot, bool filledSlot); + + // keep track of the VB nodes (we want to be able to highlight them easily on hover) + QList m_VBNodes; + QList m_BindNodes; + + // from an combined image to its sampler (since we de-duplicate) + QMap m_CombinedImageSamplers; +}; diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.ui b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.ui new file mode 100644 index 000000000..3b04966dc --- /dev/null +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.ui @@ -0,0 +1,3741 @@ + + + VulkanPipelineStateViewer + + + + 0 + 0 + 1009 + 572 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + 2 + + + + + Display Controls + + + 4 + + + + + + + Qt::Vertical + + + + + + + Show Disabled Items + + + + :/Resources/page_white_delete.png:/Resources/page_white_delete.png + + + true + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Show Empty Items + + + + :/Resources/page_white_database.png:/Resources/page_white_database.png + + + true + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Export + + + + :/Resources/save.png:/Resources/save.png + + + false + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + + + true + + + + Vertex Input + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Attributes + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + 0 + + + false + + + false + + + true + + + false + + + false + + + + Index + + + + + Name + + + + + Location + + + + + Binding + + + + + Format + + + + + Offset + + + + + Go + + + + + + + + + + + + 0 + 0 + + + + Buffers + + + + 2 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + 0 + + + false + + + false + + + true + + + false + + + false + + + + Slot + + + + + Buffer + + + + + Rate + + + + + Offset + + + + + Stride + + + + + Byte Length + + + + + Go + + + + + + + + + + + + 0 + 0 + + + + Mesh View + + + + + + + + + + :/Resources/wireframe_mesh.png:/Resources/wireframe_mesh.png + + + + 158 + 191 + + + + true + + + + + + + + + + + 0 + 0 + + + + Primitive Topology + + + + + + + 14 + + + + Triangle List + + + Qt::AlignHCenter|Qt::AlignTop + + + + + + + + 0 + 0 + + + + + 256 + 0 + + + + + + + :/Resources/topologies/topo_trilist.png + + + Qt::AlignCenter + + + + + + + + 14 + + + + Primitive Restart Enabled + + + Qt::AlignBottom|Qt::AlignHCenter + + + + + + + + + + + Vertex Shader + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + Shader + + + + 0 + + + 0 + + + 4 + + + + + + 250 + 0 + + + + PointingHandCursor + + + Open Shader Source + + + border: 1px solid black; +background-color: rgb(255, 255, 191); +padding: 0px; + + + + + + + + + + PointingHandCursor + + + Open Shader Source + + + View + + + + :/Resources/action.png:/Resources/action.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Edit Shader + + + Edit + + + + :/Resources/page_white_edit.png:/Resources/page_white_edit.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Save Shader SPIR-V + + + Save + + + + :/Resources/save.png:/Resources/save.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Qt::Horizontal + + + + 576 + 20 + + + + + + + + + + + + 0 + 0 + + + + Resources + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + true + + + false + + + + + + + + + Set + + + + + Binding + + + + + Type + + + + + Resource + + + + + Contents + + + + + + + + + + Go + + + + + + + + + + + + 0 + 0 + + + + Uniform Buffers + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + true + + + false + + + + + + + + + Set + + + + + Binding + + + + + Buffer + + + + + Byte Range + + + + + Size + + + + + Go + + + + + + + + + + + + Tess Control Shader + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + Shader + + + + 0 + + + 0 + + + 4 + + + + + + 250 + 0 + + + + PointingHandCursor + + + Open Shader Source + + + border: 1px solid black; +background-color: rgb(255, 255, 191); +padding: 0px; + + + + + + + + + + PointingHandCursor + + + Open Shader Source + + + View + + + + :/Resources/action.png:/Resources/action.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Edit Shader + + + Edit + + + + :/Resources/page_white_edit.png:/Resources/page_white_edit.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Save Shader SPIR-V + + + Save + + + + :/Resources/save.png:/Resources/save.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Qt::Horizontal + + + + 576 + 20 + + + + + + + + + + + + 0 + 0 + + + + Resources + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + true + + + false + + + + + + + + + Set + + + + + Binding + + + + + Type + + + + + Resource + + + + + Contents + + + + + + + + + + Go + + + + + + + + + + + + 0 + 0 + + + + Uniform Buffers + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + true + + + false + + + + + + + + + Set + + + + + Binding + + + + + Buffer + + + + + Byte Range + + + + + Size + + + + + Go + + + + + + + + + + + + Tess Eval Shader + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + Shader + + + + 0 + + + 0 + + + 4 + + + + + + 250 + 0 + + + + PointingHandCursor + + + Open Shader Source + + + border: 1px solid black; +background-color: rgb(255, 255, 191); +padding: 0px; + + + + + + + + + + PointingHandCursor + + + Open Shader Source + + + View + + + + :/Resources/action.png:/Resources/action.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Edit Shader + + + Edit + + + + :/Resources/page_white_edit.png:/Resources/page_white_edit.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Save Shader SPIR-V + + + Save + + + + :/Resources/save.png:/Resources/save.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Qt::Horizontal + + + + 576 + 20 + + + + + + + + + + + + 0 + 0 + + + + Resources + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + true + + + false + + + + + + + + + Set + + + + + Binding + + + + + Type + + + + + Resource + + + + + Contents + + + + + + + + + + Go + + + + + + + + + + + + 0 + 0 + + + + Uniform Buffers + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + true + + + false + + + + + + + + + Set + + + + + Binding + + + + + Buffer + + + + + Byte Range + + + + + Size + + + + + Go + + + + + + + + + + + + Geometry Shader + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + Shader + + + + 0 + + + 0 + + + 4 + + + + + + 250 + 0 + + + + PointingHandCursor + + + Open Shader Source + + + border: 1px solid black; +background-color: rgb(255, 255, 191); +padding: 0px; + + + + + + + + + + PointingHandCursor + + + Open Shader Source + + + View + + + + :/Resources/action.png:/Resources/action.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Edit Shader + + + Edit + + + + :/Resources/page_white_edit.png:/Resources/page_white_edit.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Save Shader SPIR-V + + + Save + + + + :/Resources/save.png:/Resources/save.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Qt::Horizontal + + + + 576 + 20 + + + + + + + + + + + + 0 + 0 + + + + Resources + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + true + + + false + + + + + + + + + Set + + + + + Binding + + + + + Type + + + + + Resource + + + + + Contents + + + + + + + + + + Go + + + + + + + + + + + + 0 + 0 + + + + Uniform Buffers + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + true + + + false + + + + + + + + + Set + + + + + Binding + + + + + Buffer + + + + + Byte Range + + + + + Size + + + + + Go + + + + + + + + + + + + Rasterizer + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + Rasterizer State + + + + 2 + + + 2 + + + 2 + + + 2 + + + 0 + + + + + Depth Bias Clamp: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Fill Mode: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 12 + + + + 0.00 + + + Qt::AlignCenter + + + 4 + + + + + + + Slope-Scaled Bias: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 12 + + + + Solid + + + Qt::AlignCenter + + + 4 + + + + + + + + + + :/Resources/cross.png + + + Qt::AlignCenter + + + 4 + + + + + + + Front CCW: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Cull Mode: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Depth Bias: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Line Width: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 12 + + + + None + + + Qt::AlignCenter + + + 4 + + + + + + + + 12 + + + + 0.00 + + + Qt::AlignCenter + + + 4 + + + + + + + + + + :/Resources/cross.png + + + Qt::AlignCenter + + + 4 + + + + + + + Rasterizer Discard: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Depth Clamp: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + :/Resources/cross.png + + + Qt::AlignCenter + + + 4 + + + + + + + + 12 + + + + 0.00 + + + Qt::AlignCenter + + + 4 + + + + + + + + 12 + + + + 0.00 + + + Qt::AlignCenter + + + 4 + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 0 + 0 + + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + Scissor Regions + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + 0 + + + false + + + true + + + 50 + + + + Slot + + + + + X + + + + + Y + + + + + Width + + + + + Height + + + + + + + + + + + + 0 + 0 + + + + Viewports + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + 0 + + + false + + + true + + + 50 + + + + Slot + + + + + X + + + + + Y + + + + + Width + + + + + Height + + + + + MinDepth + + + + + MaxDepth + + + + + + + + + + + Multisample State + + + + 2 + + + 2 + + + 2 + + + 2 + + + 0 + + + + + Min Sample Shading: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 12 + + + + 0 + + + Qt::AlignCenter + + + 4 + + + + + + + Sample Mask: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Sample Shading: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 12 + + + + 0.00 + + + Qt::AlignCenter + + + 4 + + + + + + + Sample Count: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 12 + + + + FFFFFFFF + + + Qt::AlignCenter + + + 4 + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 0 + 0 + + + + + + + + + + + :/Resources/cross.png + + + Qt::AlignCenter + + + 4 + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 0 + 0 + + + + + + + + + + + + Fragment Shader + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + Shader + + + + 0 + + + 0 + + + 4 + + + + + + 250 + 0 + + + + PointingHandCursor + + + Open Shader Source + + + border: 1px solid black; +background-color: rgb(255, 255, 191); +padding: 0px; + + + + + + + + + + PointingHandCursor + + + Open Shader Source + + + View + + + + :/Resources/action.png:/Resources/action.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Edit Shader + + + Edit + + + + :/Resources/page_white_edit.png:/Resources/page_white_edit.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Save Shader SPIR-V + + + Save + + + + :/Resources/save.png:/Resources/save.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Qt::Horizontal + + + + 576 + 20 + + + + + + + + + + + + 0 + 0 + + + + Resources + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + true + + + false + + + + + + + + + Set + + + + + Binding + + + + + Type + + + + + Resource + + + + + Contents + + + + + + + + + + Go + + + + + + + + + + + + 0 + 0 + + + + Uniform Buffers + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + true + + + false + + + + + + + + + Set + + + + + Binding + + + + + Buffer + + + + + Byte Range + + + + + Size + + + + + Go + + + + + + + + + + + + Framebuffer + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + Framebuffer Attachments + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + 0 + + + false + + + false + + + true + + + false + + + false + + + + Slot + + + + + Resource + + + + + Type + + + + + Width + + + + + Height + + + + + Depth + + + + + Array Size + + + + + Format + + + + + Go + + + + + + + + + + + + 0 + 0 + + + + Target Blends + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractScrollArea::AdjustToContents + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + 0 + + + false + + + false + + + true + + + false + + + + Slot + + + + + Enabled + + + + + Colour Src + + + + + Colour Dst + + + + + Colour Op + + + + + Alpha Src + + + + + Alpha Dst + + + + + Alpha Op + + + + + Write Mask + + + + + + + + + + + + 0 + 0 + + + + Blend State + + + + 2 + + + 2 + + + 2 + + + 2 + + + 0 + + + + + Blend Factor: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 12 + + + + 0.00, 0.00, 0.00, 0.00 + + + Qt::AlignCenter + + + 4 + + + + + + + Logic Op: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 12 + + + + - + + + Qt::AlignCenter + + + 4 + + + + + + + Alpha to 1: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + :/Resources/cross.png + + + Qt::AlignCenter + + + 4 + + + + + + + + + + + 0 + 0 + + + + Depth State + + + + 2 + + + 2 + + + 2 + + + 2 + + + 0 + + + + + Enabled: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + :/Resources/cross.png + + + Qt::AlignCenter + + + 4 + + + + + + + Bounds: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + :/Resources/cross.png + + + Qt::AlignCenter + + + 4 + + + + + + + Write: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + :/Resources/cross.png + + + Qt::AlignCenter + + + 4 + + + + + + + Func: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 12 + + + + GREATER_EQUAL + + + Qt::AlignCenter + + + 4 + + + + + + + + + + + 0 + 0 + + + + Stencil State + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + 0 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + QFrame::Box + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustToContents + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + QAbstractItemView::NoSelection + + + 0 + + + false + + + false + + + true + + + false + + + false + + + + Face + + + + + Func + + + + + Fail Op + + + + + Depth Fail Op + + + + + Pass Op + + + + + Write + + + + + Comp + + + + + Ref + + + + + + + + + + + + Compute Shader + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + Shader + + + + 0 + + + 0 + + + 4 + + + + + + 250 + 0 + + + + PointingHandCursor + + + Open Shader Source + + + border: 1px solid black; +background-color: rgb(255, 255, 191); +padding: 0px; + + + + + + + + + + PointingHandCursor + + + Open Shader Source + + + View + + + + :/Resources/action.png:/Resources/action.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Edit Shader + + + Edit + + + + :/Resources/page_white_edit.png:/Resources/page_white_edit.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Save Shader SPIR-V + + + Save + + + + :/Resources/save.png:/Resources/save.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Qt::Horizontal + + + + 576 + 20 + + + + + + + + + + + + 0 + 0 + + + + Resources + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + true + + + false + + + + + + + + + Set + + + + + Binding + + + + + Type + + + + + Resource + + + + + Contents + + + + + + + + + + Go + + + + + + + + + + + + 0 + 0 + + + + Uniform Buffers + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + true + + + false + + + + + + + + + Set + + + + + Binding + + + + + Buffer + + + + + Byte Range + + + + + Size + + + + + Go + + + + + + + + + + + + + + + + RDTreeWidget + QTreeWidget +
Widgets/Extended/RDTreeWidget.h
+
+
+ + + + +
diff --git a/qrenderdoc/qrenderdoc.pro b/qrenderdoc/qrenderdoc.pro index 29208018b..04cdc871c 100644 --- a/qrenderdoc/qrenderdoc.pro +++ b/qrenderdoc/qrenderdoc.pro @@ -112,6 +112,11 @@ SOURCES += 3rdparty/toolwindowmanager/ToolWindowManager.cpp \ Windows/Dialogs/LiveCapture.cpp \ Widgets/Extended/RDListWidget.cpp \ Windows/APIInspector.cpp \ + Windows/PipelineState/PipelineStateViewer.cpp \ + Windows/PipelineState/VulkanPipelineStateViewer.cpp \ + Windows/PipelineState/D3D11PipelineStateViewer.cpp \ + Windows/PipelineState/D3D12PipelineStateViewer.cpp \ + Windows/PipelineState/GLPipelineStateViewer.cpp \ Widgets/Extended/RDTreeWidget.cpp HEADERS += 3rdparty/toolwindowmanager/ToolWindowManager.h \ @@ -142,6 +147,11 @@ HEADERS += 3rdparty/toolwindowmanager/ToolWindowManager.h \ Windows/Dialogs/LiveCapture.h \ Widgets/Extended/RDListWidget.h \ Windows/APIInspector.h \ + Windows/PipelineState/PipelineStateViewer.h \ + Windows/PipelineState/VulkanPipelineStateViewer.h \ + Windows/PipelineState/D3D11PipelineStateViewer.h \ + Windows/PipelineState/D3D12PipelineStateViewer.h \ + Windows/PipelineState/GLPipelineStateViewer.h \ Widgets/Extended/RDTreeWidget.h FORMS += Windows/Dialogs/AboutDialog.ui \ @@ -153,7 +163,12 @@ FORMS += Windows/Dialogs/AboutDialog.ui \ Windows/Dialogs/TextureSaveDialog.ui \ Windows/Dialogs/CaptureDialog.ui \ Windows/Dialogs/LiveCapture.ui \ - Windows/APIInspector.ui + Windows/APIInspector.ui \ + Windows/PipelineState/PipelineStateViewer.ui \ + Windows/PipelineState/VulkanPipelineStateViewer.ui \ + Windows/PipelineState/D3D11PipelineStateViewer.ui \ + Windows/PipelineState/D3D12PipelineStateViewer.ui \ + Windows/PipelineState/GLPipelineStateViewer.ui RESOURCES += \ resources.qrc diff --git a/qrenderdoc/qrenderdoc_local.vcxproj b/qrenderdoc/qrenderdoc_local.vcxproj index 32777bd0c..042e9b777 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj +++ b/qrenderdoc/qrenderdoc_local.vcxproj @@ -288,8 +288,12 @@ + + + + @@ -307,6 +311,7 @@ + @@ -331,6 +336,11 @@ + + + + + Level3 @@ -351,13 +361,18 @@ + + + + + @@ -380,6 +395,11 @@ + + + + + @@ -395,6 +415,11 @@ + + + + + diff --git a/qrenderdoc/qrenderdoc_local.vcxproj.filters b/qrenderdoc/qrenderdoc_local.vcxproj.filters index acc233404..13e4c459f 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj.filters +++ b/qrenderdoc/qrenderdoc_local.vcxproj.filters @@ -41,6 +41,9 @@ {42a491e9-4e18-4220-8de2-e07b7cde26bc} + + {7ba076e7-3417-4e91-be51-9e7f17a19c24} + @@ -199,6 +202,36 @@ Windows + + Generated Files + + + Generated Files + + + Generated Files + + + Generated Files + + + Generated Files + + + Windows\PipelineState + + + Windows\PipelineState + + + Windows\PipelineState + + + Windows\PipelineState + + + Windows\PipelineState + Widgets\Extended @@ -312,6 +345,36 @@ Windows + + Generated Files + + + Generated Files + + + Generated Files + + + Generated Files + + + Generated Files + + + Windows\PipelineState + + + Windows\PipelineState + + + Windows\PipelineState + + + Windows\PipelineState + + + Windows\PipelineState + Widgets\Extended @@ -518,6 +581,21 @@ Windows + + Windows\PipelineState + + + Windows\PipelineState + + + Windows\PipelineState + + + Windows\PipelineState + + + Windows\PipelineState + Resources\Files