summaryrefslogtreecommitdiff
path: root/src/citra_qt/debugger/graphics_vertex_shader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/citra_qt/debugger/graphics_vertex_shader.cpp')
-rw-r--r--src/citra_qt/debugger/graphics_vertex_shader.cpp214
1 files changed, 134 insertions, 80 deletions
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp
index 391666d35..0b4320da5 100644
--- a/src/citra_qt/debugger/graphics_vertex_shader.cpp
+++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp
@@ -4,7 +4,6 @@
4 4
5#include <iomanip> 5#include <iomanip>
6#include <sstream> 6#include <sstream>
7
8#include <QBoxLayout> 7#include <QBoxLayout>
9#include <QFileDialog> 8#include <QFileDialog>
10#include <QFormLayout> 9#include <QFormLayout>
@@ -15,10 +14,8 @@
15#include <QSignalMapper> 14#include <QSignalMapper>
16#include <QSpinBox> 15#include <QSpinBox>
17#include <QTreeView> 16#include <QTreeView>
18
19#include "citra_qt/debugger/graphics_vertex_shader.h" 17#include "citra_qt/debugger/graphics_vertex_shader.h"
20#include "citra_qt/util/util.h" 18#include "citra_qt/util/util.h"
21
22#include "video_core/pica.h" 19#include "video_core/pica.h"
23#include "video_core/pica_state.h" 20#include "video_core/pica_state.h"
24#include "video_core/shader/shader.h" 21#include "video_core/shader/shader.h"
@@ -28,9 +25,8 @@ using nihstro::Instruction;
28using nihstro::SourceRegister; 25using nihstro::SourceRegister;
29using nihstro::SwizzlePattern; 26using nihstro::SwizzlePattern;
30 27
31GraphicsVertexShaderModel::GraphicsVertexShaderModel(GraphicsVertexShaderWidget* parent): QAbstractTableModel(parent), par(parent) { 28GraphicsVertexShaderModel::GraphicsVertexShaderModel(GraphicsVertexShaderWidget* parent)
32 29 : QAbstractTableModel(parent), par(parent) {}
33}
34 30
35int GraphicsVertexShaderModel::columnCount(const QModelIndex& parent) const { 31int GraphicsVertexShaderModel::columnCount(const QModelIndex& parent) const {
36 return 3; 32 return 3;
@@ -40,10 +36,10 @@ int GraphicsVertexShaderModel::rowCount(const QModelIndex& parent) const {
40 return static_cast<int>(par->info.code.size()); 36 return static_cast<int>(par->info.code.size());
41} 37}
42 38
43QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, int role) const { 39QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation,
44 switch(role) { 40 int role) const {
45 case Qt::DisplayRole: 41 switch (role) {
46 { 42 case Qt::DisplayRole: {
47 if (section == 0) { 43 if (section == 0) {
48 return tr("Offset"); 44 return tr("Offset");
49 } else if (section == 1) { 45 } else if (section == 1) {
@@ -69,8 +65,8 @@ static std::string SelectorToString(u32 selector) {
69} 65}
70 66
71// e.g. "-c92[a0.x].xyzw" 67// e.g. "-c92[a0.x].xyzw"
72static void print_input(std::ostringstream& output, const SourceRegister& input, 68static void print_input(std::ostringstream& output, const SourceRegister& input, bool negate,
73 bool negate, const std::string& swizzle_mask, bool align = true, 69 const std::string& swizzle_mask, bool align = true,
74 const std::string& address_register_name = std::string()) { 70 const std::string& address_register_name = std::string()) {
75 if (align) 71 if (align)
76 output << std::setw(4) << std::right; 72 output << std::setw(4) << std::right;
@@ -83,20 +79,18 @@ static void print_input(std::ostringstream& output, const SourceRegister& input,
83 79
84QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) const { 80QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) const {
85 switch (role) { 81 switch (role) {
86 case Qt::DisplayRole: 82 case Qt::DisplayRole: {
87 {
88 switch (index.column()) { 83 switch (index.column()) {
89 case 0: 84 case 0:
90 if (par->info.HasLabel(index.row())) 85 if (par->info.HasLabel(index.row()))
91 return QString::fromStdString(par->info.GetLabel(index.row())); 86 return QString::fromStdString(par->info.GetLabel(index.row()));
92 87
93 return QString("%1").arg(4*index.row(), 4, 16, QLatin1Char('0')); 88 return QString("%1").arg(4 * index.row(), 4, 16, QLatin1Char('0'));
94 89
95 case 1: 90 case 1:
96 return QString("%1").arg(par->info.code[index.row()].hex, 8, 16, QLatin1Char('0')); 91 return QString("%1").arg(par->info.code[index.row()].hex, 8, 16, QLatin1Char('0'));
97 92
98 case 2: 93 case 2: {
99 {
100 std::ostringstream output; 94 std::ostringstream output;
101 output.flags(std::ios::uppercase); 95 output.flags(std::ios::uppercase);
102 96
@@ -117,8 +111,9 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
117 const Instruction instr = par->info.code[index.row()]; 111 const Instruction instr = par->info.code[index.row()];
118 const OpCode opcode = instr.opcode; 112 const OpCode opcode = instr.opcode;
119 const OpCode::Info opcode_info = opcode.GetInfo(); 113 const OpCode::Info opcode_info = opcode.GetInfo();
120 const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd ? 114 const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd
121 instr.mad.operand_desc_id.Value() : instr.common.operand_desc_id.Value(); 115 ? instr.mad.operand_desc_id.Value()
116 : instr.common.operand_desc_id.Value();
122 const SwizzlePattern swizzle = par->info.swizzle_info[operand_desc_id].pattern; 117 const SwizzlePattern swizzle = par->info.swizzle_info[operand_desc_id].pattern;
123 118
124 // longest known instruction name: "setemit " 119 // longest known instruction name: "setemit "
@@ -136,15 +131,14 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
136 break; 131 break;
137 132
138 case OpCode::Type::Arithmetic: 133 case OpCode::Type::Arithmetic:
139 case OpCode::Type::MultiplyAdd: 134 case OpCode::Type::MultiplyAdd: {
140 {
141 // Use custom code for special instructions 135 // Use custom code for special instructions
142 switch (opcode.EffectiveOpCode()) { 136 switch (opcode.EffectiveOpCode()) {
143 case OpCode::Id::CMP: 137 case OpCode::Id::CMP: {
144 {
145 AlignToColumn(kOpcodeColumnWidth); 138 AlignToColumn(kOpcodeColumnWidth);
146 139
147 // NOTE: CMP always writes both cc components, so we do not consider the dest mask here. 140 // NOTE: CMP always writes both cc components, so we do not consider the dest
141 // mask here.
148 output << " cc.xy"; 142 output << " cc.xy";
149 AlignToColumn(kOutputColumnWidth); 143 AlignToColumn(kOutputColumnWidth);
150 144
@@ -152,22 +146,29 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
152 SourceRegister src2 = instr.common.GetSrc2(false); 146 SourceRegister src2 = instr.common.GetSrc2(false);
153 147
154 output << ' '; 148 output << ' ';
155 print_input(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(0,1), false, instr.common.AddressRegisterName()); 149 print_input(output, src1, swizzle.negate_src1,
156 output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.x) << ' '; 150 swizzle.SelectorToString(false).substr(0, 1), false,
157 print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true).substr(0,1), false); 151 instr.common.AddressRegisterName());
152 output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.x)
153 << ' ';
154 print_input(output, src2, swizzle.negate_src2,
155 swizzle.SelectorToString(true).substr(0, 1), false);
158 156
159 output << ", "; 157 output << ", ";
160 158
161 print_input(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(1,1), false, instr.common.AddressRegisterName()); 159 print_input(output, src1, swizzle.negate_src1,
162 output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.y) << ' '; 160 swizzle.SelectorToString(false).substr(1, 1), false,
163 print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true).substr(1,1), false); 161 instr.common.AddressRegisterName());
162 output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.y)
163 << ' ';
164 print_input(output, src2, swizzle.negate_src2,
165 swizzle.SelectorToString(true).substr(1, 1), false);
164 166
165 break; 167 break;
166 } 168 }
167 169
168 case OpCode::Id::MAD: 170 case OpCode::Id::MAD:
169 case OpCode::Id::MADI: 171 case OpCode::Id::MADI: {
170 {
171 AlignToColumn(kOpcodeColumnWidth); 172 AlignToColumn(kOpcodeColumnWidth);
172 173
173 bool src_is_inverted = 0 != (opcode_info.subtype & OpCode::Info::SrcInversed); 174 bool src_is_inverted = 0 != (opcode_info.subtype & OpCode::Info::SrcInversed);
@@ -175,34 +176,42 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
175 SourceRegister src2 = instr.mad.GetSrc2(src_is_inverted); 176 SourceRegister src2 = instr.mad.GetSrc2(src_is_inverted);
176 SourceRegister src3 = instr.mad.GetSrc3(src_is_inverted); 177 SourceRegister src3 = instr.mad.GetSrc3(src_is_inverted);
177 178
178 output << std::setw(3) << std::right << instr.mad.dest.Value().GetName() << '.' << swizzle.DestMaskToString(); 179 output << std::setw(3) << std::right << instr.mad.dest.Value().GetName() << '.'
180 << swizzle.DestMaskToString();
179 AlignToColumn(kOutputColumnWidth); 181 AlignToColumn(kOutputColumnWidth);
180 print_input(output, src1, swizzle.negate_src1, SelectorToString(swizzle.src1_selector)); 182 print_input(output, src1, swizzle.negate_src1,
183 SelectorToString(swizzle.src1_selector));
181 AlignToColumn(kInputOperandColumnWidth); 184 AlignToColumn(kInputOperandColumnWidth);
182 if (src_is_inverted) { 185 if (src_is_inverted) {
183 print_input(output, src2, swizzle.negate_src2, SelectorToString(swizzle.src2_selector)); 186 print_input(output, src2, swizzle.negate_src2,
187 SelectorToString(swizzle.src2_selector));
184 } else { 188 } else {
185 print_input(output, src2, swizzle.negate_src2, SelectorToString(swizzle.src2_selector), true, instr.mad.AddressRegisterName()); 189 print_input(output, src2, swizzle.negate_src2,
190 SelectorToString(swizzle.src2_selector), true,
191 instr.mad.AddressRegisterName());
186 } 192 }
187 AlignToColumn(kInputOperandColumnWidth); 193 AlignToColumn(kInputOperandColumnWidth);
188 if (src_is_inverted) { 194 if (src_is_inverted) {
189 print_input(output, src3, swizzle.negate_src3, SelectorToString(swizzle.src3_selector), true, instr.mad.AddressRegisterName()); 195 print_input(output, src3, swizzle.negate_src3,
196 SelectorToString(swizzle.src3_selector), true,
197 instr.mad.AddressRegisterName());
190 } else { 198 } else {
191 print_input(output, src3, swizzle.negate_src3, SelectorToString(swizzle.src3_selector)); 199 print_input(output, src3, swizzle.negate_src3,
200 SelectorToString(swizzle.src3_selector));
192 } 201 }
193 AlignToColumn(kInputOperandColumnWidth); 202 AlignToColumn(kInputOperandColumnWidth);
194 break; 203 break;
195 } 204 }
196 205
197 default: 206 default: {
198 {
199 AlignToColumn(kOpcodeColumnWidth); 207 AlignToColumn(kOpcodeColumnWidth);
200 208
201 bool src_is_inverted = 0 != (opcode_info.subtype & OpCode::Info::SrcInversed); 209 bool src_is_inverted = 0 != (opcode_info.subtype & OpCode::Info::SrcInversed);
202 210
203 if (opcode_info.subtype & OpCode::Info::Dest) { 211 if (opcode_info.subtype & OpCode::Info::Dest) {
204 // e.g. "r12.xy__" 212 // e.g. "r12.xy__"
205 output << std::setw(3) << std::right << instr.common.dest.Value().GetName() << '.' << swizzle.DestMaskToString(); 213 output << std::setw(3) << std::right << instr.common.dest.Value().GetName()
214 << '.' << swizzle.DestMaskToString();
206 } else if (opcode_info.subtype == OpCode::Info::MOVA) { 215 } else if (opcode_info.subtype == OpCode::Info::MOVA) {
207 output << " a0." << swizzle.DestMaskToString(); 216 output << " a0." << swizzle.DestMaskToString();
208 } 217 }
@@ -210,14 +219,18 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
210 219
211 if (opcode_info.subtype & OpCode::Info::Src1) { 220 if (opcode_info.subtype & OpCode::Info::Src1) {
212 SourceRegister src1 = instr.common.GetSrc1(src_is_inverted); 221 SourceRegister src1 = instr.common.GetSrc1(src_is_inverted);
213 print_input(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false), true, instr.common.AddressRegisterName()); 222 print_input(output, src1, swizzle.negate_src1,
223 swizzle.SelectorToString(false), true,
224 instr.common.AddressRegisterName());
214 AlignToColumn(kInputOperandColumnWidth); 225 AlignToColumn(kInputOperandColumnWidth);
215 } 226 }
216 227
217 // TODO: In some cases, the Address Register is used as an index for SRC2 instead of SRC1 228 // TODO: In some cases, the Address Register is used as an index for SRC2
229 // instead of SRC1
218 if (opcode_info.subtype & OpCode::Info::Src2) { 230 if (opcode_info.subtype & OpCode::Info::Src2) {
219 SourceRegister src2 = instr.common.GetSrc2(src_is_inverted); 231 SourceRegister src2 = instr.common.GetSrc2(src_is_inverted);
220 print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true)); 232 print_input(output, src2, swizzle.negate_src2,
233 swizzle.SelectorToString(true));
221 AlignToColumn(kInputOperandColumnWidth); 234 AlignToColumn(kInputOperandColumnWidth);
222 } 235 }
223 break; 236 break;
@@ -228,8 +241,7 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
228 } 241 }
229 242
230 case OpCode::Type::Conditional: 243 case OpCode::Type::Conditional:
231 case OpCode::Type::UniformFlowControl: 244 case OpCode::Type::UniformFlowControl: {
232 {
233 output << ' '; 245 output << ' ';
234 246
235 switch (opcode.EffectiveOpCode()) { 247 switch (opcode.EffectiveOpCode()) {
@@ -242,7 +254,8 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
242 output << '('; 254 output << '(';
243 255
244 if (instr.flow_control.op != instr.flow_control.JustY) { 256 if (instr.flow_control.op != instr.flow_control.JustY) {
245 if (instr.flow_control.refx) output << '!'; 257 if (instr.flow_control.refx)
258 output << '!';
246 output << "cc.x"; 259 output << "cc.x";
247 } 260 }
248 261
@@ -253,7 +266,8 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
253 } 266 }
254 267
255 if (instr.flow_control.op != instr.flow_control.JustX) { 268 if (instr.flow_control.op != instr.flow_control.JustX) {
256 if (instr.flow_control.refy) output << '!'; 269 if (instr.flow_control.refy)
270 output << '!';
257 output << "cc.y"; 271 output << "cc.y";
258 } 272 }
259 273
@@ -266,17 +280,23 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
266 u32 target_addr_else = instr.flow_control.dest_offset; 280 u32 target_addr_else = instr.flow_control.dest_offset;
267 281
268 if (opcode_info.subtype & OpCode::Info::HasAlternative) { 282 if (opcode_info.subtype & OpCode::Info::HasAlternative) {
269 output << "else jump to 0x" << std::setw(4) << std::right << std::setfill('0') << std::hex << (4 * instr.flow_control.dest_offset); 283 output << "else jump to 0x" << std::setw(4) << std::right
284 << std::setfill('0') << std::hex
285 << (4 * instr.flow_control.dest_offset);
270 } else if (opcode_info.subtype & OpCode::Info::HasExplicitDest) { 286 } else if (opcode_info.subtype & OpCode::Info::HasExplicitDest) {
271 output << "jump to 0x" << std::setw(4) << std::right << std::setfill('0') << std::hex << (4 * instr.flow_control.dest_offset); 287 output << "jump to 0x" << std::setw(4) << std::right << std::setfill('0')
288 << std::hex << (4 * instr.flow_control.dest_offset);
272 } else { 289 } else {
273 // TODO: Handle other cases 290 // TODO: Handle other cases
274 output << "(unknown destination)"; 291 output << "(unknown destination)";
275 } 292 }
276 293
277 if (opcode_info.subtype & OpCode::Info::HasFinishPoint) { 294 if (opcode_info.subtype & OpCode::Info::HasFinishPoint) {
278 output << " (return on 0x" << std::setw(4) << std::right << std::setfill('0') << std::hex 295 output << " (return on 0x" << std::setw(4) << std::right
279 << (4 * instr.flow_control.dest_offset + 4 * instr.flow_control.num_instructions) << ')'; 296 << std::setfill('0') << std::hex
297 << (4 * instr.flow_control.dest_offset +
298 4 * instr.flow_control.num_instructions)
299 << ')';
280 } 300 }
281 301
282 break; 302 break;
@@ -300,8 +320,7 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
300 case Qt::FontRole: 320 case Qt::FontRole:
301 return GetMonospaceFont(); 321 return GetMonospaceFont();
302 322
303 case Qt::BackgroundRole: 323 case Qt::BackgroundRole: {
304 {
305 // Highlight current instruction 324 // Highlight current instruction
306 int current_record_index = par->cycle_index->value(); 325 int current_record_index = par->cycle_index->value();
307 if (current_record_index < static_cast<int>(par->debug_data.records.size())) { 326 if (current_record_index < static_cast<int>(par->debug_data.records.size())) {
@@ -319,10 +338,8 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
319 return QBrush(QColor(192, 192, 192)); 338 return QBrush(QColor(192, 192, 192));
320 } 339 }
321 340
322
323 // TODO: Draw arrows for each "reachable" instruction to visualize control flow 341 // TODO: Draw arrows for each "reachable" instruction to visualize control flow
324 342
325
326 default: 343 default:
327 break; 344 break;
328 } 345 }
@@ -331,23 +348,24 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
331} 348}
332 349
333void GraphicsVertexShaderWidget::DumpShader() { 350void GraphicsVertexShaderWidget::DumpShader() {
334 QString filename = QFileDialog::getSaveFileName(this, tr("Save Shader Dump"), "shader_dump.shbin", 351 QString filename = QFileDialog::getSaveFileName(
335 tr("Shader Binary (*.shbin)")); 352 this, tr("Save Shader Dump"), "shader_dump.shbin", tr("Shader Binary (*.shbin)"));
336 353
337 if (filename.isEmpty()) { 354 if (filename.isEmpty()) {
338 // If the user canceled the dialog, don't dump anything. 355 // If the user canceled the dialog, don't dump anything.
339 return; 356 return;
340 } 357 }
341 358
342 auto& setup = Pica::g_state.vs; 359 auto& setup = Pica::g_state.vs;
343 auto& config = Pica::g_state.regs.vs; 360 auto& config = Pica::g_state.regs.vs;
344 361
345 Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup, Pica::g_state.regs.vs_output_attributes); 362 Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup,
363 Pica::g_state.regs.vs_output_attributes);
346} 364}
347 365
348GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::DebugContext > debug_context, 366GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
349 QWidget* parent) 367 std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent)
350 : BreakPointObserverDock(debug_context, "Pica Vertex Shader", parent) { 368 : BreakPointObserverDock(debug_context, "Pica Vertex Shader", parent) {
351 setObjectName("PicaVertexShader"); 369 setObjectName("PicaVertexShader");
352 370
353 // Clear input vertex data so that it contains valid float values in case a debug shader 371 // Clear input vertex data so that it contains valid float values in case a debug shader
@@ -365,7 +383,8 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::De
365 input_data[i]->setValidator(new QDoubleValidator(input_data[i])); 383 input_data[i]->setValidator(new QDoubleValidator(input_data[i]));
366 } 384 }
367 385
368 breakpoint_warning = new QLabel(tr("(data only available at vertex shader invocation breakpoints)")); 386 breakpoint_warning =
387 new QLabel(tr("(data only available at vertex shader invocation breakpoints)"));
369 388
370 // TODO: Add some button for jumping to the shader entry point 389 // TODO: Add some button for jumping to the shader entry point
371 390
@@ -442,7 +461,8 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::De
442 461
443 // Set a minimum height so that the size of this label doesn't cause the rest of the bottom 462 // Set a minimum height so that the size of this label doesn't cause the rest of the bottom
444 // part of the UI to keep jumping up and down when cycling through instructions. 463 // part of the UI to keep jumping up and down when cycling through instructions.
445 instruction_description->setMinimumHeight(instruction_description->fontMetrics().lineSpacing() * 6); 464 instruction_description->setMinimumHeight(instruction_description->fontMetrics().lineSpacing() *
465 6);
446 instruction_description->setAlignment(Qt::AlignLeft | Qt::AlignTop); 466 instruction_description->setAlignment(Qt::AlignLeft | Qt::AlignTop);
447 main_layout->addWidget(instruction_description); 467 main_layout->addWidget(instruction_description);
448 468
@@ -471,7 +491,8 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
471 memcpy(&input_vertex, vertex_data, sizeof(input_vertex)); 491 memcpy(&input_vertex, vertex_data, sizeof(input_vertex));
472 for (unsigned attr = 0; attr < 16; ++attr) { 492 for (unsigned attr = 0; attr < 16; ++attr) {
473 for (unsigned comp = 0; comp < 4; ++comp) { 493 for (unsigned comp = 0; comp < 4; ++comp) {
474 input_data[4 * attr + comp]->setText(QString("%1").arg(input_vertex.attr[attr][comp].ToFloat32())); 494 input_data[4 * attr + comp]->setText(
495 QString("%1").arg(input_vertex.attr[attr][comp].ToFloat32()));
475 } 496 }
476 } 497 }
477 breakpoint_warning->hide(); 498 breakpoint_warning->hide();
@@ -498,10 +519,11 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
498 info.swizzle_info.push_back({pattern}); 519 info.swizzle_info.push_back({pattern});
499 520
500 u32 entry_point = Pica::g_state.regs.vs.main_offset; 521 u32 entry_point = Pica::g_state.regs.vs.main_offset;
501 info.labels.insert({ entry_point, "main" }); 522 info.labels.insert({entry_point, "main"});
502 523
503 // Generate debug information 524 // Generate debug information
504 debug_data = Pica::g_state.vs.ProduceDebugInfo(input_vertex, num_attributes, shader_config, shader_setup); 525 debug_data = Pica::g_state.vs.ProduceDebugInfo(input_vertex, num_attributes, shader_config,
526 shader_setup);
505 527
506 // Reload widget state 528 // Reload widget state
507 for (int attr = 0; attr < num_attributes; ++attr) { 529 for (int attr = 0; attr < num_attributes; ++attr) {
@@ -537,29 +559,60 @@ void GraphicsVertexShaderWidget::OnCycleIndexChanged(int index) {
537 559
538 auto& record = debug_data.records[index]; 560 auto& record = debug_data.records[index];
539 if (record.mask & Pica::Shader::DebugDataRecord::SRC1) 561 if (record.mask & Pica::Shader::DebugDataRecord::SRC1)
540 text += tr("SRC1: %1, %2, %3, %4\n").arg(record.src1.x.ToFloat32()).arg(record.src1.y.ToFloat32()).arg(record.src1.z.ToFloat32()).arg(record.src1.w.ToFloat32()); 562 text += tr("SRC1: %1, %2, %3, %4\n")
563 .arg(record.src1.x.ToFloat32())
564 .arg(record.src1.y.ToFloat32())
565 .arg(record.src1.z.ToFloat32())
566 .arg(record.src1.w.ToFloat32());
541 if (record.mask & Pica::Shader::DebugDataRecord::SRC2) 567 if (record.mask & Pica::Shader::DebugDataRecord::SRC2)
542 text += tr("SRC2: %1, %2, %3, %4\n").arg(record.src2.x.ToFloat32()).arg(record.src2.y.ToFloat32()).arg(record.src2.z.ToFloat32()).arg(record.src2.w.ToFloat32()); 568 text += tr("SRC2: %1, %2, %3, %4\n")
569 .arg(record.src2.x.ToFloat32())
570 .arg(record.src2.y.ToFloat32())
571 .arg(record.src2.z.ToFloat32())
572 .arg(record.src2.w.ToFloat32());
543 if (record.mask & Pica::Shader::DebugDataRecord::SRC3) 573 if (record.mask & Pica::Shader::DebugDataRecord::SRC3)
544 text += tr("SRC3: %1, %2, %3, %4\n").arg(record.src3.x.ToFloat32()).arg(record.src3.y.ToFloat32()).arg(record.src3.z.ToFloat32()).arg(record.src3.w.ToFloat32()); 574 text += tr("SRC3: %1, %2, %3, %4\n")
575 .arg(record.src3.x.ToFloat32())
576 .arg(record.src3.y.ToFloat32())
577 .arg(record.src3.z.ToFloat32())
578 .arg(record.src3.w.ToFloat32());
545 if (record.mask & Pica::Shader::DebugDataRecord::DEST_IN) 579 if (record.mask & Pica::Shader::DebugDataRecord::DEST_IN)
546 text += tr("DEST_IN: %1, %2, %3, %4\n").arg(record.dest_in.x.ToFloat32()).arg(record.dest_in.y.ToFloat32()).arg(record.dest_in.z.ToFloat32()).arg(record.dest_in.w.ToFloat32()); 580 text += tr("DEST_IN: %1, %2, %3, %4\n")
581 .arg(record.dest_in.x.ToFloat32())
582 .arg(record.dest_in.y.ToFloat32())
583 .arg(record.dest_in.z.ToFloat32())
584 .arg(record.dest_in.w.ToFloat32());
547 if (record.mask & Pica::Shader::DebugDataRecord::DEST_OUT) 585 if (record.mask & Pica::Shader::DebugDataRecord::DEST_OUT)
548 text += tr("DEST_OUT: %1, %2, %3, %4\n").arg(record.dest_out.x.ToFloat32()).arg(record.dest_out.y.ToFloat32()).arg(record.dest_out.z.ToFloat32()).arg(record.dest_out.w.ToFloat32()); 586 text += tr("DEST_OUT: %1, %2, %3, %4\n")
587 .arg(record.dest_out.x.ToFloat32())
588 .arg(record.dest_out.y.ToFloat32())
589 .arg(record.dest_out.z.ToFloat32())
590 .arg(record.dest_out.w.ToFloat32());
549 591
550 if (record.mask & Pica::Shader::DebugDataRecord::ADDR_REG_OUT) 592 if (record.mask & Pica::Shader::DebugDataRecord::ADDR_REG_OUT)
551 text += tr("Addres Registers: %1, %2\n").arg(record.address_registers[0]).arg(record.address_registers[1]); 593 text += tr("Addres Registers: %1, %2\n")
594 .arg(record.address_registers[0])
595 .arg(record.address_registers[1]);
552 if (record.mask & Pica::Shader::DebugDataRecord::CMP_RESULT) 596 if (record.mask & Pica::Shader::DebugDataRecord::CMP_RESULT)
553 text += tr("Compare Result: %1, %2\n").arg(record.conditional_code[0] ? "true" : "false").arg(record.conditional_code[1] ? "true" : "false"); 597 text += tr("Compare Result: %1, %2\n")
598 .arg(record.conditional_code[0] ? "true" : "false")
599 .arg(record.conditional_code[1] ? "true" : "false");
554 600
555 if (record.mask & Pica::Shader::DebugDataRecord::COND_BOOL_IN) 601 if (record.mask & Pica::Shader::DebugDataRecord::COND_BOOL_IN)
556 text += tr("Static Condition: %1\n").arg(record.cond_bool ? "true" : "false"); 602 text += tr("Static Condition: %1\n").arg(record.cond_bool ? "true" : "false");
557 if (record.mask & Pica::Shader::DebugDataRecord::COND_CMP_IN) 603 if (record.mask & Pica::Shader::DebugDataRecord::COND_CMP_IN)
558 text += tr("Dynamic Conditions: %1, %2\n").arg(record.cond_cmp[0] ? "true" : "false").arg(record.cond_cmp[1] ? "true" : "false"); 604 text += tr("Dynamic Conditions: %1, %2\n")
605 .arg(record.cond_cmp[0] ? "true" : "false")
606 .arg(record.cond_cmp[1] ? "true" : "false");
559 if (record.mask & Pica::Shader::DebugDataRecord::LOOP_INT_IN) 607 if (record.mask & Pica::Shader::DebugDataRecord::LOOP_INT_IN)
560 text += tr("Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4\n").arg(record.loop_int.x).arg(record.loop_int.y).arg(record.loop_int.z).arg(record.loop_int.w); 608 text += tr("Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4\n")
561 609 .arg(record.loop_int.x)
562 text += tr("Instruction offset: 0x%1").arg(4 * record.instruction_offset, 4, 16, QLatin1Char('0')); 610 .arg(record.loop_int.y)
611 .arg(record.loop_int.z)
612 .arg(record.loop_int.w);
613
614 text +=
615 tr("Instruction offset: 0x%1").arg(4 * record.instruction_offset, 4, 16, QLatin1Char('0'));
563 if (record.mask & Pica::Shader::DebugDataRecord::NEXT_INSTR) { 616 if (record.mask & Pica::Shader::DebugDataRecord::NEXT_INSTR) {
564 text += tr(" -> 0x%2").arg(4 * record.next_instruction, 4, 16, QLatin1Char('0')); 617 text += tr(" -> 0x%2").arg(4 * record.next_instruction, 4, 16, QLatin1Char('0'));
565 } else { 618 } else {
@@ -570,6 +623,7 @@ void GraphicsVertexShaderWidget::OnCycleIndexChanged(int index) {
570 623
571 // Emit model update notification and scroll to current instruction 624 // Emit model update notification and scroll to current instruction
572 QModelIndex instr_index = model->index(record.instruction_offset, 0); 625 QModelIndex instr_index = model->index(record.instruction_offset, 0);
573 emit model->dataChanged(instr_index, model->index(record.instruction_offset, model->columnCount())); 626 emit model->dataChanged(instr_index,
627 model->index(record.instruction_offset, model->columnCount()));
574 binary_list->scrollTo(instr_index, QAbstractItemView::EnsureVisible); 628 binary_list->scrollTo(instr_index, QAbstractItemView::EnsureVisible);
575} 629}