summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Tony Wasserka2015-02-11 22:17:46 +0100
committerGravatar Tony Wasserka2015-02-11 22:17:46 +0100
commitf990728ad44246e5eca0e5ace32ea47f68e280c3 (patch)
tree40b3e6837a25b8d7b8e269776df9553ad6e3bf41 /src
parentMerge pull request #558 from kevinhartman/gsp-writereg-mask (diff)
parentcitra-qt: Add a vertex shader debugger. (diff)
downloadyuzu-f990728ad44246e5eca0e5ace32ea47f68e280c3.tar.gz
yuzu-f990728ad44246e5eca0e5ace32ea47f68e280c3.tar.xz
yuzu-f990728ad44246e5eca0e5ace32ea47f68e280c3.zip
Merge pull request #384 from neobrain/vertex_shader_debugger
Vertex shader debugger
Diffstat (limited to 'src')
-rw-r--r--src/citra_qt/CMakeLists.txt4
-rw-r--r--src/citra_qt/debugger/graphics_breakpoint_observer.cpp32
-rw-r--r--src/citra_qt/debugger/graphics_breakpoint_observer.h33
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.cpp27
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.h24
-rw-r--r--src/citra_qt/debugger/graphics_vertex_shader.cpp298
-rw-r--r--src/citra_qt/debugger/graphics_vertex_shader.h51
-rw-r--r--src/citra_qt/main.cpp6
8 files changed, 425 insertions, 50 deletions
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index bbc521f8a..586bc84b0 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -8,9 +8,11 @@ set(SRCS
8 debugger/callstack.cpp 8 debugger/callstack.cpp
9 debugger/disassembler.cpp 9 debugger/disassembler.cpp
10 debugger/graphics.cpp 10 debugger/graphics.cpp
11 debugger/graphics_breakpoint_observer.cpp
11 debugger/graphics_breakpoints.cpp 12 debugger/graphics_breakpoints.cpp
12 debugger/graphics_cmdlists.cpp 13 debugger/graphics_cmdlists.cpp
13 debugger/graphics_framebuffer.cpp 14 debugger/graphics_framebuffer.cpp
15 debugger/graphics_vertex_shader.cpp
14 debugger/ramview.cpp 16 debugger/ramview.cpp
15 debugger/registers.cpp 17 debugger/registers.cpp
16 util/spinbox.cpp 18 util/spinbox.cpp
@@ -27,10 +29,12 @@ set(HEADERS
27 debugger/callstack.h 29 debugger/callstack.h
28 debugger/disassembler.h 30 debugger/disassembler.h
29 debugger/graphics.h 31 debugger/graphics.h
32 debugger/graphics_breakpoint_observer.h
30 debugger/graphics_breakpoints.h 33 debugger/graphics_breakpoints.h
31 debugger/graphics_breakpoints_p.h 34 debugger/graphics_breakpoints_p.h
32 debugger/graphics_cmdlists.h 35 debugger/graphics_cmdlists.h
33 debugger/graphics_framebuffer.h 36 debugger/graphics_framebuffer.h
37 debugger/graphics_vertex_shader.h
34 debugger/ramview.h 38 debugger/ramview.h
35 debugger/registers.h 39 debugger/registers.h
36 util/spinbox.h 40 util/spinbox.h
diff --git a/src/citra_qt/debugger/graphics_breakpoint_observer.cpp b/src/citra_qt/debugger/graphics_breakpoint_observer.cpp
new file mode 100644
index 000000000..10ac1ebad
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_breakpoint_observer.cpp
@@ -0,0 +1,32 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QMetaType>
6
7#include "graphics_breakpoint_observer.h"
8
9BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context,
10 const QString& title, QWidget* parent)
11 : QDockWidget(title, parent), BreakPointObserver(debug_context)
12{
13 qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event");
14
15 connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed()));
16
17 // NOTE: This signal is emitted from a non-GUI thread, but connect() takes
18 // care of delaying its handling to the GUI thread.
19 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)),
20 this, SLOT(OnBreakPointHit(Pica::DebugContext::Event,void*)),
21 Qt::BlockingQueuedConnection);
22}
23
24void BreakPointObserverDock::OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data)
25{
26 emit BreakPointHit(event, data);
27}
28
29void BreakPointObserverDock::OnPicaResume()
30{
31 emit Resumed();
32}
diff --git a/src/citra_qt/debugger/graphics_breakpoint_observer.h b/src/citra_qt/debugger/graphics_breakpoint_observer.h
new file mode 100644
index 000000000..f0d3361f8
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_breakpoint_observer.h
@@ -0,0 +1,33 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QDockWidget>
8
9#include "video_core/debug_utils/debug_utils.h"
10
11/**
12 * Utility class which forwards calls to OnPicaBreakPointHit and OnPicaResume to public slots.
13 * This is because the Pica breakpoint callbacks are called from a non-GUI thread, while
14 * the widget usually wants to perform reactions in the GUI thread.
15 */
16class BreakPointObserverDock : public QDockWidget, private Pica::DebugContext::BreakPointObserver {
17 Q_OBJECT
18
19public:
20 BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context, const QString& title,
21 QWidget* parent = nullptr);
22
23 void OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) override;
24 void OnPicaResume() override;
25
26private slots:
27 virtual void OnBreakPointHit(Pica::DebugContext::Event event, void* data) = 0;
28 virtual void OnResumed() = 0;
29
30signals:
31 void Resumed();
32 void BreakPointHit(Pica::DebugContext::Event event, void* data);
33};
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp
index 43c59738f..1ba60021f 100644
--- a/src/citra_qt/debugger/graphics_framebuffer.cpp
+++ b/src/citra_qt/debugger/graphics_framebuffer.cpp
@@ -6,7 +6,6 @@
6#include <QComboBox> 6#include <QComboBox>
7#include <QDebug> 7#include <QDebug>
8#include <QLabel> 8#include <QLabel>
9#include <QMetaType>
10#include <QPushButton> 9#include <QPushButton>
11#include <QSpinBox> 10#include <QSpinBox>
12 11
@@ -17,32 +16,6 @@
17 16
18#include "util/spinbox.h" 17#include "util/spinbox.h"
19 18
20BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context,
21 const QString& title, QWidget* parent)
22 : QDockWidget(title, parent), BreakPointObserver(debug_context)
23{
24 qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event");
25
26 connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed()));
27
28 // NOTE: This signal is emitted from a non-GUI thread, but connect() takes
29 // care of delaying its handling to the GUI thread.
30 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)),
31 this, SLOT(OnBreakPointHit(Pica::DebugContext::Event,void*)),
32 Qt::BlockingQueuedConnection);
33}
34
35void BreakPointObserverDock::OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data)
36{
37 emit BreakPointHit(event, data);
38}
39
40void BreakPointObserverDock::OnPicaResume()
41{
42 emit Resumed();
43}
44
45
46GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptr<Pica::DebugContext> debug_context, 19GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptr<Pica::DebugContext> debug_context,
47 QWidget* parent) 20 QWidget* parent)
48 : BreakPointObserverDock(debug_context, tr("Pica Framebuffer"), parent), 21 : BreakPointObserverDock(debug_context, tr("Pica Framebuffer"), parent),
diff --git a/src/citra_qt/debugger/graphics_framebuffer.h b/src/citra_qt/debugger/graphics_framebuffer.h
index 56215761e..c6e293bc9 100644
--- a/src/citra_qt/debugger/graphics_framebuffer.h
+++ b/src/citra_qt/debugger/graphics_framebuffer.h
@@ -6,7 +6,7 @@
6 6
7#include <QDockWidget> 7#include <QDockWidget>
8 8
9#include "video_core/debug_utils/debug_utils.h" 9#include "graphics_breakpoint_observer.h"
10 10
11class QComboBox; 11class QComboBox;
12class QLabel; 12class QLabel;
@@ -14,28 +14,6 @@ class QSpinBox;
14 14
15class CSpinBox; 15class CSpinBox;
16 16
17// Utility class which forwards calls to OnPicaBreakPointHit and OnPicaResume to public slots.
18// This is because the Pica breakpoint callbacks are called from a non-GUI thread, while
19// the widget usually wants to perform reactions in the GUI thread.
20class BreakPointObserverDock : public QDockWidget, Pica::DebugContext::BreakPointObserver {
21 Q_OBJECT
22
23public:
24 BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context, const QString& title,
25 QWidget* parent = nullptr);
26
27 void OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) override;
28 void OnPicaResume() override;
29
30private slots:
31 virtual void OnBreakPointHit(Pica::DebugContext::Event event, void* data) = 0;
32 virtual void OnResumed() = 0;
33
34signals:
35 void Resumed();
36 void BreakPointHit(Pica::DebugContext::Event event, void* data);
37};
38
39class GraphicsFramebufferWidget : public BreakPointObserverDock { 17class GraphicsFramebufferWidget : public BreakPointObserverDock {
40 Q_OBJECT 18 Q_OBJECT
41 19
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp
new file mode 100644
index 000000000..06eaf0bf0
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp
@@ -0,0 +1,298 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <iomanip>
6#include <sstream>
7
8#include <QBoxLayout>
9#include <QTreeView>
10
11#include "video_core/vertex_shader.h"
12
13#include "graphics_vertex_shader.h"
14
15using nihstro::Instruction;
16using nihstro::SourceRegister;
17using nihstro::SwizzlePattern;
18
19GraphicsVertexShaderModel::GraphicsVertexShaderModel(QObject* parent): QAbstractItemModel(parent) {
20
21}
22
23QModelIndex GraphicsVertexShaderModel::index(int row, int column, const QModelIndex& parent) const {
24 return createIndex(row, column);
25}
26
27QModelIndex GraphicsVertexShaderModel::parent(const QModelIndex& child) const {
28 return QModelIndex();
29}
30
31int GraphicsVertexShaderModel::columnCount(const QModelIndex& parent) const {
32 return 3;
33}
34
35int GraphicsVertexShaderModel::rowCount(const QModelIndex& parent) const {
36 return info.code.size();
37}
38
39QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, int role) const {
40 switch(role) {
41 case Qt::DisplayRole:
42 {
43 if (section == 0) {
44 return tr("Offset");
45 } else if (section == 1) {
46 return tr("Raw");
47 } else if (section == 2) {
48 return tr("Disassembly");
49 }
50
51 break;
52 }
53 }
54
55 return QVariant();
56}
57
58QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) const {
59 switch (role) {
60 case Qt::DisplayRole:
61 {
62 switch (index.column()) {
63 case 0:
64 if (info.HasLabel(index.row()))
65 return QString::fromStdString(info.GetLabel(index.row()));
66
67 return QString("%1").arg(4*index.row(), 4, 16, QLatin1Char('0'));
68
69 case 1:
70 return QString("%1").arg(info.code[index.row()].hex, 8, 16, QLatin1Char('0'));
71
72 case 2:
73 {
74 std::stringstream output;
75 output.flags(std::ios::hex);
76
77 Instruction instr = info.code[index.row()];
78 const SwizzlePattern& swizzle = info.swizzle_info[instr.common.operand_desc_id].pattern;
79
80 // longest known instruction name: "setemit "
81 output << std::setw(8) << std::left << instr.opcode.GetInfo().name;
82
83 // e.g. "-c92.xyzw"
84 static auto print_input = [](std::stringstream& output, const SourceRegister& input,
85 bool negate, const std::string& swizzle_mask) {
86 output << std::setw(4) << std::right << (negate ? "-" : "") + input.GetName();
87 output << "." << swizzle_mask;
88 };
89
90 // e.g. "-c92[a0.x].xyzw"
91 static auto print_input_indexed = [](std::stringstream& output, const SourceRegister& input,
92 bool negate, const std::string& swizzle_mask,
93 const std::string& address_register_name) {
94 std::string relative_address;
95 if (!address_register_name.empty())
96 relative_address = "[" + address_register_name + "]";
97
98 output << std::setw(10) << std::right << (negate ? "-" : "") + input.GetName() + relative_address;
99 output << "." << swizzle_mask;
100 };
101
102 // Use print_input or print_input_indexed depending on whether relative addressing is used or not.
103 static auto print_input_indexed_compact = [](std::stringstream& output, const SourceRegister& input,
104 bool negate, const std::string& swizzle_mask,
105 const std::string& address_register_name) {
106 if (address_register_name.empty())
107 print_input(output, input, negate, swizzle_mask);
108 else
109 print_input_indexed(output, input, negate, swizzle_mask, address_register_name);
110 };
111
112 switch (instr.opcode.GetInfo().type) {
113 case Instruction::OpCodeType::Trivial:
114 // Nothing to do here
115 break;
116
117 case Instruction::OpCodeType::Arithmetic:
118 {
119 // Use custom code for special instructions
120 switch (instr.opcode.EffectiveOpCode()) {
121 case Instruction::OpCode::CMP:
122 {
123 // NOTE: CMP always writes both cc components, so we do not consider the dest mask here.
124 output << std::setw(4) << std::right << "cc.";
125 output << "xy ";
126
127 SourceRegister src1 = instr.common.GetSrc1(false);
128 SourceRegister src2 = instr.common.GetSrc2(false);
129
130 print_input_indexed_compact(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(0,1), instr.common.AddressRegisterName());
131 output << " " << instr.common.compare_op.ToString(instr.common.compare_op.x) << " ";
132 print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(false).substr(0,1));
133
134 output << ", ";
135
136 print_input_indexed_compact(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(1,1), instr.common.AddressRegisterName());
137 output << " " << instr.common.compare_op.ToString(instr.common.compare_op.y) << " ";
138 print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(false).substr(1,1));
139
140 break;
141 }
142
143 default:
144 {
145 bool src_is_inverted = 0 != (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::SrcInversed);
146
147 if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::Dest) {
148 // e.g. "r12.xy__"
149 output << std::setw(4) << std::right << instr.common.dest.GetName() + ".";
150 output << swizzle.DestMaskToString();
151 } else if (instr.opcode.GetInfo().subtype == Instruction::OpCodeInfo::MOVA) {
152 output << std::setw(4) << std::right << "a0.";
153 output << swizzle.DestMaskToString();
154 } else {
155 output << " ";
156 }
157 output << " ";
158
159 if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::Src1) {
160 SourceRegister src1 = instr.common.GetSrc1(src_is_inverted);
161 print_input_indexed(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false), instr.common.AddressRegisterName());
162 } else {
163 output << " ";
164 }
165
166 // TODO: In some cases, the Address Register is used as an index for SRC2 instead of SRC1
167 if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::Src2) {
168 SourceRegister src2 = instr.common.GetSrc2(src_is_inverted);
169 print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(false));
170 }
171 break;
172 }
173 }
174
175 break;
176 }
177
178 case Instruction::OpCodeType::Conditional:
179 {
180 switch (instr.opcode.EffectiveOpCode()) {
181 case Instruction::OpCode::LOOP:
182 output << "(unknown instruction format)";
183 break;
184
185 default:
186 output << "if ";
187
188 if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::HasCondition) {
189 const char* ops[] = {
190 " || ", " && ", "", ""
191 };
192 if (instr.flow_control.op != instr.flow_control.JustY)
193 output << ((!instr.flow_control.refx) ? "!" : " ") << "cc.x";
194
195 output << ops[instr.flow_control.op];
196
197 if (instr.flow_control.op != instr.flow_control.JustX)
198 output << ((!instr.flow_control.refy) ? "!" : " ") << "cc.y";
199
200 output << " ";
201 } else if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::HasUniformIndex) {
202 output << "b" << instr.flow_control.bool_uniform_id << " ";
203 }
204
205 u32 target_addr = instr.flow_control.dest_offset;
206 u32 target_addr_else = instr.flow_control.dest_offset;
207
208 if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::HasAlternative) {
209 output << "else jump to 0x" << std::setw(4) << std::right << std::setfill('0') << 4 * instr.flow_control.dest_offset << " ";
210 } else if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::HasExplicitDest) {
211 output << "jump to 0x" << std::setw(4) << std::right << std::setfill('0') << 4 * instr.flow_control.dest_offset << " ";
212 } else {
213 // TODO: Handle other cases
214 }
215
216 if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::HasFinishPoint) {
217 output << "(return on " << std::setw(4) << std::right << std::setfill('0')
218 << 4 * instr.flow_control.dest_offset + 4 * instr.flow_control.num_instructions << ")";
219 }
220
221 break;
222 }
223 break;
224 }
225
226 default:
227 output << "(unknown instruction format)";
228 break;
229 }
230
231 return QString::fromLatin1(output.str().c_str());
232 }
233
234 default:
235 break;
236 }
237 }
238
239 case Qt::FontRole:
240 return QFont("monospace");
241
242 default:
243 break;
244 }
245
246 return QVariant();
247}
248
249void GraphicsVertexShaderModel::OnUpdate()
250{
251 beginResetModel();
252
253 info.Clear();
254
255 for (auto instr : Pica::VertexShader::GetShaderBinary())
256 info.code.push_back({instr});
257
258 for (auto pattern : Pica::VertexShader::GetSwizzlePatterns())
259 info.swizzle_info.push_back({pattern});
260
261 info.labels.insert({Pica::registers.vs_main_offset, "main"});
262
263 endResetModel();
264}
265
266
267GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::DebugContext > debug_context,
268 QWidget* parent)
269 : BreakPointObserverDock(debug_context, "Pica Vertex Shader", parent) {
270 setObjectName("PicaVertexShader");
271
272 auto binary_model = new GraphicsVertexShaderModel(this);
273 auto binary_list = new QTreeView;
274 binary_list->setModel(binary_model);
275 binary_list->setRootIsDecorated(false);
276 binary_list->setAlternatingRowColors(true);
277
278 connect(this, SIGNAL(Update()), binary_model, SLOT(OnUpdate()));
279
280 auto main_widget = new QWidget;
281 auto main_layout = new QVBoxLayout;
282 {
283 auto sub_layout = new QHBoxLayout;
284 sub_layout->addWidget(binary_list);
285 main_layout->addLayout(sub_layout);
286 }
287 main_widget->setLayout(main_layout);
288 setWidget(main_widget);
289}
290
291void GraphicsVertexShaderWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) {
292 emit Update();
293 widget()->setEnabled(true);
294}
295
296void GraphicsVertexShaderWidget::OnResumed() {
297 widget()->setEnabled(false);
298}
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.h b/src/citra_qt/debugger/graphics_vertex_shader.h
new file mode 100644
index 000000000..38339dc05
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_vertex_shader.h
@@ -0,0 +1,51 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QAbstractListModel>
8
9#include "graphics_breakpoint_observer.h"
10
11#include "nihstro/parser_shbin.h"
12
13class GraphicsVertexShaderModel : public QAbstractItemModel {
14 Q_OBJECT
15
16public:
17 GraphicsVertexShaderModel(QObject* parent);
18
19 QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
20 QModelIndex parent(const QModelIndex& child) const override;
21 int columnCount(const QModelIndex& parent = QModelIndex()) const override;
22 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
23 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
24 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
25
26public slots:
27 void OnUpdate();
28
29private:
30 nihstro::ShaderInfo info;
31};
32
33class GraphicsVertexShaderWidget : public BreakPointObserverDock {
34 Q_OBJECT
35
36 using Event = Pica::DebugContext::Event;
37
38public:
39 GraphicsVertexShaderWidget(std::shared_ptr<Pica::DebugContext> debug_context,
40 QWidget* parent = nullptr);
41
42private slots:
43 void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override;
44 void OnResumed() override;
45
46signals:
47 void Update();
48
49private:
50
51};
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 653ffec75..881c7d337 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -34,6 +34,7 @@
34#include "debugger/graphics_breakpoints.h" 34#include "debugger/graphics_breakpoints.h"
35#include "debugger/graphics_cmdlists.h" 35#include "debugger/graphics_cmdlists.h"
36#include "debugger/graphics_framebuffer.h" 36#include "debugger/graphics_framebuffer.h"
37#include "debugger/graphics_vertex_shader.h"
37 38
38#include "core/settings.h" 39#include "core/settings.h"
39#include "core/system.h" 40#include "core/system.h"
@@ -84,6 +85,10 @@ GMainWindow::GMainWindow()
84 addDockWidget(Qt::RightDockWidgetArea, graphicsFramebufferWidget); 85 addDockWidget(Qt::RightDockWidgetArea, graphicsFramebufferWidget);
85 graphicsFramebufferWidget->hide(); 86 graphicsFramebufferWidget->hide();
86 87
88 auto graphicsVertexShaderWidget = new GraphicsVertexShaderWidget(Pica::g_debug_context, this);
89 addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget);
90 graphicsVertexShaderWidget->hide();
91
87 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); 92 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
88 debug_menu->addAction(disasmWidget->toggleViewAction()); 93 debug_menu->addAction(disasmWidget->toggleViewAction());
89 debug_menu->addAction(registersWidget->toggleViewAction()); 94 debug_menu->addAction(registersWidget->toggleViewAction());
@@ -92,6 +97,7 @@ GMainWindow::GMainWindow()
92 debug_menu->addAction(graphicsCommandsWidget->toggleViewAction()); 97 debug_menu->addAction(graphicsCommandsWidget->toggleViewAction());
93 debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction()); 98 debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction());
94 debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction()); 99 debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction());
100 debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction());
95 101
96 // Set default UI state 102 // Set default UI state
97 // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half 103 // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half