| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | // Copyright 2014 Citra Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <iomanip>
 | 
					
						
							|  |  |  | #include <sstream>
 | 
					
						
							|  |  |  | #include <QBoxLayout>
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | #include <QFileDialog>
 | 
					
						
							| 
									
										
										
										
											2015-08-19 05:48:22 -03:00
										 |  |  | #include <QFormLayout>
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | #include <QGroupBox>
 | 
					
						
							| 
									
										
										
										
											2015-05-27 16:20:46 +02:00
										 |  |  | #include <QLabel>
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | #include <QLineEdit>
 | 
					
						
							| 
									
										
										
										
											2015-05-27 16:20:46 +02:00
										 |  |  | #include <QPushButton>
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | #include <QSignalMapper>
 | 
					
						
							|  |  |  | #include <QSpinBox>
 | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | #include <QTreeView>
 | 
					
						
							| 
									
										
										
										
											2016-12-21 17:19:12 -05:00
										 |  |  | #include "citra_qt/debugger/graphics/graphics_vertex_shader.h"
 | 
					
						
							| 
									
										
										
										
											2015-08-19 17:00:56 -03:00
										 |  |  | #include "citra_qt/util/util.h"
 | 
					
						
							| 
									
										
										
										
											2016-03-02 22:16:38 -05:00
										 |  |  | #include "video_core/pica.h"
 | 
					
						
							|  |  |  | #include "video_core/pica_state.h"
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | #include "video_core/shader/shader.h"
 | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-08 13:52:38 -07:00
										 |  |  | using nihstro::OpCode; | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | using nihstro::Instruction; | 
					
						
							|  |  |  | using nihstro::SourceRegister; | 
					
						
							|  |  |  | using nihstro::SwizzlePattern; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  | GraphicsVertexShaderModel::GraphicsVertexShaderModel(GraphicsVertexShaderWidget* parent) | 
					
						
							| 
									
										
										
										
											2016-09-18 18:01:46 -07:00
										 |  |  |     : QAbstractTableModel(parent), par(parent) {} | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | int GraphicsVertexShaderModel::columnCount(const QModelIndex& parent) const { | 
					
						
							|  |  |  |     return 3; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int GraphicsVertexShaderModel::rowCount(const QModelIndex& parent) const { | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     return static_cast<int>(par->info.code.size()); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  | QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, | 
					
						
							|  |  |  |                                                int role) const { | 
					
						
							|  |  |  |     switch (role) { | 
					
						
							|  |  |  |     case Qt::DisplayRole: { | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |         if (section == 0) { | 
					
						
							|  |  |  |             return tr("Offset"); | 
					
						
							|  |  |  |         } else if (section == 1) { | 
					
						
							|  |  |  |             return tr("Raw"); | 
					
						
							|  |  |  |         } else if (section == 2) { | 
					
						
							|  |  |  |             return tr("Disassembly"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return QVariant(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:58 -03:00
										 |  |  | static std::string SelectorToString(u32 selector) { | 
					
						
							|  |  |  |     std::string ret; | 
					
						
							|  |  |  |     for (int i = 0; i < 4; ++i) { | 
					
						
							|  |  |  |         int component = (selector >> ((3 - i) * 2)) & 3; | 
					
						
							|  |  |  |         ret += "xyzw"[component]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  | // e.g. "-c92[a0.x].xyzw"
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  | static void print_input(std::ostringstream& output, const SourceRegister& input, bool negate, | 
					
						
							|  |  |  |                         const std::string& swizzle_mask, bool align = true, | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                         const std::string& address_register_name = std::string()) { | 
					
						
							|  |  |  |     if (align) | 
					
						
							|  |  |  |         output << std::setw(4) << std::right; | 
					
						
							|  |  |  |     output << ((negate ? "-" : "") + input.GetName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!address_register_name.empty()) | 
					
						
							|  |  |  |         output << '[' << address_register_name << ']'; | 
					
						
							|  |  |  |     output << '.' << swizzle_mask; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) const { | 
					
						
							|  |  |  |     switch (role) { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |     case Qt::DisplayRole: { | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |         switch (index.column()) { | 
					
						
							|  |  |  |         case 0: | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |             if (par->info.HasLabel(index.row())) | 
					
						
							|  |  |  |                 return QString::fromStdString(par->info.GetLabel(index.row())); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |             return QString("%1").arg(4 * index.row(), 4, 16, QLatin1Char('0')); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         case 1: | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |             return QString("%1").arg(par->info.code[index.row()].hex, 8, 16, QLatin1Char('0')); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |         case 2: { | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |             std::ostringstream output; | 
					
						
							| 
									
										
										
										
											2015-08-19 04:52:44 -03:00
										 |  |  |             output.flags(std::ios::uppercase); | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // To make the code aligning columns of assembly easier to keep track of, this function
 | 
					
						
							|  |  |  |             // keeps track of the start of the start of the previous column, allowing alignment
 | 
					
						
							|  |  |  |             // based on desired field widths.
 | 
					
						
							|  |  |  |             int current_column = 0; | 
					
						
							|  |  |  |             auto AlignToColumn = [&](int col_width) { | 
					
						
							|  |  |  |                 // Prints spaces to the output to pad previous column to size and advances the
 | 
					
						
							|  |  |  |                 // column marker.
 | 
					
						
							|  |  |  |                 current_column += col_width; | 
					
						
							|  |  |  |                 int to_add = std::max(1, current_column - (int)output.tellp()); | 
					
						
							|  |  |  |                 for (int i = 0; i < to_add; ++i) { | 
					
						
							|  |  |  |                     output << ' '; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }; | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |             const Instruction instr = par->info.code[index.row()]; | 
					
						
							|  |  |  |             const OpCode opcode = instr.opcode; | 
					
						
							|  |  |  |             const OpCode::Info opcode_info = opcode.GetInfo(); | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |             const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd | 
					
						
							|  |  |  |                                             ? instr.mad.operand_desc_id.Value() | 
					
						
							|  |  |  |                                             : instr.common.operand_desc_id.Value(); | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |             const SwizzlePattern swizzle = par->info.swizzle_info[operand_desc_id].pattern; | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // longest known instruction name: "setemit "
 | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |             int kOpcodeColumnWidth = 8; | 
					
						
							|  |  |  |             // "rXX.xyzw  "
 | 
					
						
							|  |  |  |             int kOutputColumnWidth = 10; | 
					
						
							|  |  |  |             // "-rXX.xyzw  ", no attempt is made to align indexed inputs
 | 
					
						
							|  |  |  |             int kInputOperandColumnWidth = 11; | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |             output << opcode_info.name; | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |             switch (opcode_info.type) { | 
					
						
							| 
									
										
										
										
											2015-03-08 13:52:38 -07:00
										 |  |  |             case OpCode::Type::Trivial: | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                 // Nothing to do here
 | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-08 13:52:38 -07:00
										 |  |  |             case OpCode::Type::Arithmetic: | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |             case OpCode::Type::MultiplyAdd: { | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                 // Use custom code for special instructions
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |                 switch (opcode.EffectiveOpCode()) { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                 case OpCode::Id::CMP: { | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                     AlignToColumn(kOpcodeColumnWidth); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                     // NOTE: CMP always writes both cc components, so we do not consider the dest
 | 
					
						
							|  |  |  |                     // mask here.
 | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                     output << " cc.xy"; | 
					
						
							|  |  |  |                     AlignToColumn(kOutputColumnWidth); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     SourceRegister src1 = instr.common.GetSrc1(false); | 
					
						
							|  |  |  |                     SourceRegister src2 = instr.common.GetSrc2(false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                     output << ' '; | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                     print_input(output, src1, swizzle.negate_src1, | 
					
						
							|  |  |  |                                 swizzle.SelectorToString(false).substr(0, 1), false, | 
					
						
							|  |  |  |                                 instr.common.AddressRegisterName()); | 
					
						
							|  |  |  |                     output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.x) | 
					
						
							|  |  |  |                            << ' '; | 
					
						
							|  |  |  |                     print_input(output, src2, swizzle.negate_src2, | 
					
						
							|  |  |  |                                 swizzle.SelectorToString(true).substr(0, 1), false); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     output << ", "; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                     print_input(output, src1, swizzle.negate_src1, | 
					
						
							|  |  |  |                                 swizzle.SelectorToString(false).substr(1, 1), false, | 
					
						
							|  |  |  |                                 instr.common.AddressRegisterName()); | 
					
						
							|  |  |  |                     output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.y) | 
					
						
							|  |  |  |                            << ' '; | 
					
						
							|  |  |  |                     print_input(output, src2, swizzle.negate_src2, | 
					
						
							|  |  |  |                                 swizzle.SelectorToString(true).substr(1, 1), false); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:58 -03:00
										 |  |  |                 case OpCode::Id::MAD: | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                 case OpCode::Id::MADI: { | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:58 -03:00
										 |  |  |                     AlignToColumn(kOpcodeColumnWidth); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     bool src_is_inverted = 0 != (opcode_info.subtype & OpCode::Info::SrcInversed); | 
					
						
							|  |  |  |                     SourceRegister src1 = instr.mad.GetSrc1(src_is_inverted); | 
					
						
							|  |  |  |                     SourceRegister src2 = instr.mad.GetSrc2(src_is_inverted); | 
					
						
							|  |  |  |                     SourceRegister src3 = instr.mad.GetSrc3(src_is_inverted); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                     output << std::setw(3) << std::right << instr.mad.dest.Value().GetName() << '.' | 
					
						
							|  |  |  |                            << swizzle.DestMaskToString(); | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:58 -03:00
										 |  |  |                     AlignToColumn(kOutputColumnWidth); | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                     print_input(output, src1, swizzle.negate_src1, | 
					
						
							|  |  |  |                                 SelectorToString(swizzle.src1_selector)); | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:58 -03:00
										 |  |  |                     AlignToColumn(kInputOperandColumnWidth); | 
					
						
							| 
									
										
										
										
											2016-03-09 14:48:45 +01:00
										 |  |  |                     if (src_is_inverted) { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                         print_input(output, src2, swizzle.negate_src2, | 
					
						
							|  |  |  |                                     SelectorToString(swizzle.src2_selector)); | 
					
						
							| 
									
										
										
										
											2016-03-09 14:48:45 +01:00
										 |  |  |                     } else { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                         print_input(output, src2, swizzle.negate_src2, | 
					
						
							|  |  |  |                                     SelectorToString(swizzle.src2_selector), true, | 
					
						
							|  |  |  |                                     instr.mad.AddressRegisterName()); | 
					
						
							| 
									
										
										
										
											2016-03-09 14:48:45 +01:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:58 -03:00
										 |  |  |                     AlignToColumn(kInputOperandColumnWidth); | 
					
						
							| 
									
										
										
										
											2016-03-09 14:48:45 +01:00
										 |  |  |                     if (src_is_inverted) { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                         print_input(output, src3, swizzle.negate_src3, | 
					
						
							|  |  |  |                                     SelectorToString(swizzle.src3_selector), true, | 
					
						
							|  |  |  |                                     instr.mad.AddressRegisterName()); | 
					
						
							| 
									
										
										
										
											2016-03-09 14:48:45 +01:00
										 |  |  |                     } else { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                         print_input(output, src3, swizzle.negate_src3, | 
					
						
							|  |  |  |                                     SelectorToString(swizzle.src3_selector)); | 
					
						
							| 
									
										
										
										
											2016-03-09 14:48:45 +01:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:58 -03:00
										 |  |  |                     AlignToColumn(kInputOperandColumnWidth); | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                 default: { | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                     AlignToColumn(kOpcodeColumnWidth); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |                     bool src_is_inverted = 0 != (opcode_info.subtype & OpCode::Info::SrcInversed); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |                     if (opcode_info.subtype & OpCode::Info::Dest) { | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                         // e.g. "r12.xy__"
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                         output << std::setw(3) << std::right << instr.common.dest.Value().GetName() | 
					
						
							|  |  |  |                                << '.' << swizzle.DestMaskToString(); | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |                     } else if (opcode_info.subtype == OpCode::Info::MOVA) { | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                         output << "  a0." << swizzle.DestMaskToString(); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                     AlignToColumn(kOutputColumnWidth); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |                     if (opcode_info.subtype & OpCode::Info::Src1) { | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                         SourceRegister src1 = instr.common.GetSrc1(src_is_inverted); | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                         print_input(output, src1, swizzle.negate_src1, | 
					
						
							|  |  |  |                                     swizzle.SelectorToString(false), true, | 
					
						
							|  |  |  |                                     instr.common.AddressRegisterName()); | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                         AlignToColumn(kInputOperandColumnWidth); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                     // TODO: In some cases, the Address Register is used as an index for SRC2
 | 
					
						
							|  |  |  |                     // instead of SRC1
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |                     if (opcode_info.subtype & OpCode::Info::Src2) { | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                         SourceRegister src2 = instr.common.GetSrc2(src_is_inverted); | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                         print_input(output, src2, swizzle.negate_src2, | 
					
						
							|  |  |  |                                     swizzle.SelectorToString(true)); | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                         AlignToColumn(kInputOperandColumnWidth); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                     } | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-08 13:52:38 -07:00
										 |  |  |             case OpCode::Type::Conditional: | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |             case OpCode::Type::UniformFlowControl: { | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                 output << ' '; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |                 switch (opcode.EffectiveOpCode()) { | 
					
						
							| 
									
										
										
										
											2015-03-08 13:52:38 -07:00
										 |  |  |                 case OpCode::Id::LOOP: | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                     output << "(unknown instruction format)"; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 default: | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |                     if (opcode_info.subtype & OpCode::Info::HasCondition) { | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                         output << '('; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if (instr.flow_control.op != instr.flow_control.JustY) { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                             if (instr.flow_control.refx) | 
					
						
							|  |  |  |                                 output << '!'; | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                             output << "cc.x"; | 
					
						
							|  |  |  |                         } | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                         if (instr.flow_control.op == instr.flow_control.Or) { | 
					
						
							|  |  |  |                             output << " || "; | 
					
						
							|  |  |  |                         } else if (instr.flow_control.op == instr.flow_control.And) { | 
					
						
							|  |  |  |                             output << " && "; | 
					
						
							|  |  |  |                         } | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                         if (instr.flow_control.op != instr.flow_control.JustX) { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                             if (instr.flow_control.refy) | 
					
						
							|  |  |  |                                 output << '!'; | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                             output << "cc.y"; | 
					
						
							|  |  |  |                         } | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                         output << ") "; | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |                     } else if (opcode_info.subtype & OpCode::Info::HasUniformIndex) { | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                         output << 'b' << instr.flow_control.bool_uniform_id << ' '; | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |                     if (opcode_info.subtype & OpCode::Info::HasAlternative) { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                         output << "else jump to 0x" << std::setw(4) << std::right | 
					
						
							|  |  |  |                                << std::setfill('0') << std::hex | 
					
						
							|  |  |  |                                << (4 * instr.flow_control.dest_offset); | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |                     } else if (opcode_info.subtype & OpCode::Info::HasExplicitDest) { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                         output << "jump to 0x" << std::setw(4) << std::right << std::setfill('0') | 
					
						
							|  |  |  |                                << std::hex << (4 * instr.flow_control.dest_offset); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                     } else { | 
					
						
							|  |  |  |                         // TODO: Handle other cases
 | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                         output << "(unknown destination)"; | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-19 04:39:24 -03:00
										 |  |  |                     if (opcode_info.subtype & OpCode::Info::HasFinishPoint) { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                         output << " (return on 0x" << std::setw(4) << std::right | 
					
						
							|  |  |  |                                << std::setfill('0') << std::hex | 
					
						
							|  |  |  |                                << (4 * instr.flow_control.dest_offset + | 
					
						
							|  |  |  |                                    4 * instr.flow_control.num_instructions) | 
					
						
							|  |  |  |                                << ')'; | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             default: | 
					
						
							| 
									
										
										
										
											2015-08-25 04:52:37 -03:00
										 |  |  |                 output << " (unknown instruction format)"; | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return QString::fromLatin1(output.str().c_str()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case Qt::FontRole: | 
					
						
							| 
									
										
										
										
											2015-08-19 17:00:56 -03:00
										 |  |  |         return GetMonospaceFont(); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |     case Qt::BackgroundRole: { | 
					
						
							| 
									
										
										
										
											2015-08-25 06:45:29 -03:00
										 |  |  |         // Highlight current instruction
 | 
					
						
							|  |  |  |         int current_record_index = par->cycle_index->value(); | 
					
						
							| 
									
										
										
										
											2015-10-06 21:28:19 -05:00
										 |  |  |         if (current_record_index < static_cast<int>(par->debug_data.records.size())) { | 
					
						
							| 
									
										
										
										
											2015-08-25 06:45:29 -03:00
										 |  |  |             const auto& current_record = par->debug_data.records[current_record_index]; | 
					
						
							| 
									
										
										
										
											2015-10-06 21:28:19 -05:00
										 |  |  |             if (index.row() == static_cast<int>(current_record.instruction_offset)) { | 
					
						
							| 
									
										
										
										
											2015-08-25 06:45:29 -03:00
										 |  |  |                 return QColor(255, 255, 63); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Use a grey background for instructions which have no debug data associated to them
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |         for (const auto& record : par->debug_data.records) | 
					
						
							| 
									
										
										
										
											2015-10-06 21:28:19 -05:00
										 |  |  |             if (index.row() == static_cast<int>(record.instruction_offset)) | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |                 return QVariant(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 06:45:29 -03:00
										 |  |  |         return QBrush(QColor(192, 192, 192)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // TODO: Draw arrows for each "reachable" instruction to visualize control flow
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return QVariant(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | void GraphicsVertexShaderWidget::DumpShader() { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |     QString filename = QFileDialog::getSaveFileName( | 
					
						
							|  |  |  |         this, tr("Save Shader Dump"), "shader_dump.shbin", tr("Shader Binary (*.shbin)")); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     if (filename.isEmpty()) { | 
					
						
							|  |  |  |         // If the user canceled the dialog, don't dump anything.
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |     auto& setup = Pica::g_state.vs; | 
					
						
							| 
									
										
										
										
											2015-05-27 16:20:46 +02:00
										 |  |  |     auto& config = Pica::g_state.regs.vs; | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |     Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup, | 
					
						
							|  |  |  |                                  Pica::g_state.regs.vs_output_attributes); | 
					
						
							| 
									
										
										
										
											2015-05-27 16:20:46 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-28 00:31:26 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  | GraphicsVertexShaderWidget::GraphicsVertexShaderWidget( | 
					
						
							|  |  |  |     std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent) | 
					
						
							|  |  |  |     : BreakPointObserverDock(debug_context, "Pica Vertex Shader", parent) { | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |     setObjectName("PicaVertexShader"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 05:44:59 -03:00
										 |  |  |     // Clear input vertex data so that it contains valid float values in case a debug shader
 | 
					
						
							|  |  |  |     // execution happens before the first Vertex Loaded breakpoint.
 | 
					
						
							|  |  |  |     // TODO: This makes a crash in the interpreter much less likely, but not impossible. The
 | 
					
						
							|  |  |  |     //       interpreter should guard against out-of-bounds accesses to ensure crashes in it aren't
 | 
					
						
							|  |  |  |     //       possible.
 | 
					
						
							|  |  |  |     std::memset(&input_vertex, 0, sizeof(input_vertex)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     auto input_data_mapper = new QSignalMapper(this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // TODO: Support inputting data in hexadecimal raw format
 | 
					
						
							|  |  |  |     for (unsigned i = 0; i < ARRAY_SIZE(input_data); ++i) { | 
					
						
							|  |  |  |         input_data[i] = new QLineEdit; | 
					
						
							|  |  |  |         input_data[i]->setValidator(new QDoubleValidator(input_data[i])); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |     breakpoint_warning = | 
					
						
							|  |  |  |         new QLabel(tr("(data only available at vertex shader invocation breakpoints)")); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // TODO: Add some button for jumping to the shader entry point
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     model = new GraphicsVertexShaderModel(this); | 
					
						
							|  |  |  |     binary_list = new QTreeView; | 
					
						
							|  |  |  |     binary_list->setModel(model); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |     binary_list->setRootIsDecorated(false); | 
					
						
							|  |  |  |     binary_list->setAlternatingRowColors(true); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     auto dump_shader = new QPushButton(QIcon::fromTheme("document-save"), tr("Dump")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     instruction_description = new QLabel; | 
					
						
							| 
									
										
										
										
											2015-05-27 16:20:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-15 20:13:48 +02:00
										 |  |  |     cycle_index = new QSpinBox; | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     connect(dump_shader, SIGNAL(clicked()), this, SLOT(DumpShader())); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-15 20:13:48 +02:00
										 |  |  |     connect(cycle_index, SIGNAL(valueChanged(int)), this, SLOT(OnCycleIndexChanged(int))); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (unsigned i = 0; i < ARRAY_SIZE(input_data); ++i) { | 
					
						
							|  |  |  |         connect(input_data[i], SIGNAL(textEdited(const QString&)), input_data_mapper, SLOT(map())); | 
					
						
							|  |  |  |         input_data_mapper->setMapping(input_data[i], i); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     connect(input_data_mapper, SIGNAL(mapped(int)), this, SLOT(OnInputAttributeChanged(int))); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     auto main_widget = new QWidget; | 
					
						
							|  |  |  |     auto main_layout = new QVBoxLayout; | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         auto input_data_group = new QGroupBox(tr("Input Data")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // For each vertex attribute, add a QHBoxLayout consisting of:
 | 
					
						
							|  |  |  |         // - A QLabel denoting the source attribute index
 | 
					
						
							|  |  |  |         // - Four QLineEdits for showing and manipulating attribute data
 | 
					
						
							|  |  |  |         // - A QLabel denoting the shader input attribute index
 | 
					
						
							|  |  |  |         auto sub_layout = new QVBoxLayout; | 
					
						
							|  |  |  |         for (unsigned i = 0; i < 16; ++i) { | 
					
						
							|  |  |  |             // Create an HBoxLayout to store the widgets used to specify a particular attribute
 | 
					
						
							|  |  |  |             // and store it in a QWidget to allow for easy hiding and unhiding.
 | 
					
						
							|  |  |  |             auto row_layout = new QHBoxLayout; | 
					
						
							| 
									
										
										
										
											2016-10-20 12:26:59 -02:00
										 |  |  |             // Remove unnecessary padding between rows
 | 
					
						
							| 
									
										
										
										
											2015-08-19 05:48:22 -03:00
										 |  |  |             row_layout->setContentsMargins(0, 0, 0, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |             row_layout->addWidget(new QLabel(tr("Attribute %1").arg(i, 2))); | 
					
						
							|  |  |  |             for (unsigned comp = 0; comp < 4; ++comp) | 
					
						
							|  |  |  |                 row_layout->addWidget(input_data[4 * i + comp]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             row_layout->addWidget(input_data_mapping[i] = new QLabel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             input_data_container[i] = new QWidget; | 
					
						
							|  |  |  |             input_data_container[i]->setLayout(row_layout); | 
					
						
							|  |  |  |             input_data_container[i]->hide(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             sub_layout->addWidget(input_data_container[i]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         sub_layout->addWidget(breakpoint_warning); | 
					
						
							|  |  |  |         breakpoint_warning->hide(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         input_data_group->setLayout(sub_layout); | 
					
						
							|  |  |  |         main_layout->addWidget(input_data_group); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-08-19 05:48:22 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Make program listing expand to fill available space in the dialog
 | 
					
						
							|  |  |  |     binary_list->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); | 
					
						
							|  |  |  |     main_layout->addWidget(binary_list); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-27 16:20:46 +02:00
										 |  |  |     main_layout->addWidget(dump_shader); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2015-08-19 05:48:22 -03:00
										 |  |  |         auto sub_layout = new QFormLayout; | 
					
						
							|  |  |  |         sub_layout->addRow(tr("Cycle Index:"), cycle_index); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |         main_layout->addLayout(sub_layout); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-08-19 05:48:22 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Set a minimum height so that the size of this label doesn't cause the rest of the bottom
 | 
					
						
							|  |  |  |     // part of the UI to keep jumping up and down when cycling through instructions.
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |     instruction_description->setMinimumHeight(instruction_description->fontMetrics().lineSpacing() * | 
					
						
							|  |  |  |                                               6); | 
					
						
							| 
									
										
										
										
											2015-08-19 05:48:22 -03:00
										 |  |  |     instruction_description->setAlignment(Qt::AlignLeft | Qt::AlignTop); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     main_layout->addWidget(instruction_description); | 
					
						
							| 
									
										
										
										
											2015-08-19 05:48:22 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |     main_widget->setLayout(main_layout); | 
					
						
							|  |  |  |     setWidget(main_widget); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     widget()->setEnabled(false); | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GraphicsVertexShaderWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) { | 
					
						
							| 
									
										
										
										
											2016-05-04 10:21:51 +02:00
										 |  |  |     if (event == Pica::DebugContext::Event::VertexShaderInvocation) { | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |         Reload(true, data); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         // No vertex data is retrievable => invalidate currently stored vertex data
 | 
					
						
							|  |  |  |         Reload(true, nullptr); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  |     widget()->setEnabled(true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_data) { | 
					
						
							|  |  |  |     model->beginResetModel(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (replace_vertex_data) { | 
					
						
							|  |  |  |         if (vertex_data) { | 
					
						
							|  |  |  |             memcpy(&input_vertex, vertex_data, sizeof(input_vertex)); | 
					
						
							|  |  |  |             for (unsigned attr = 0; attr < 16; ++attr) { | 
					
						
							|  |  |  |                 for (unsigned comp = 0; comp < 4; ++comp) { | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                     input_data[4 * attr + comp]->setText( | 
					
						
							|  |  |  |                         QString("%1").arg(input_vertex.attr[attr][comp].ToFloat32())); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             breakpoint_warning->hide(); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             for (unsigned attr = 0; attr < 16; ++attr) { | 
					
						
							|  |  |  |                 for (unsigned comp = 0; comp < 4; ++comp) { | 
					
						
							|  |  |  |                     input_data[4 * attr + comp]->setText(QString("???")); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             breakpoint_warning->show(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Reload shader code
 | 
					
						
							|  |  |  |     info.Clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto& shader_setup = Pica::g_state.vs; | 
					
						
							|  |  |  |     auto& shader_config = Pica::g_state.regs.vs; | 
					
						
							|  |  |  |     for (auto instr : shader_setup.program_code) | 
					
						
							|  |  |  |         info.code.push_back({instr}); | 
					
						
							| 
									
										
										
										
											2015-08-25 02:36:57 -03:00
										 |  |  |     int num_attributes = Pica::g_state.regs.vertex_attributes.GetNumTotalAttributes(); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (auto pattern : shader_setup.swizzle_data) | 
					
						
							|  |  |  |         info.swizzle_info.push_back({pattern}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     u32 entry_point = Pica::g_state.regs.vs.main_offset; | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |     info.labels.insert({entry_point, "main"}); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Generate debug information
 | 
					
						
							| 
									
										
										
										
											2016-12-16 23:21:26 -08:00
										 |  |  |     auto* shader_engine = Pica::Shader::GetEngine(); | 
					
						
							|  |  |  |     shader_engine->SetupBatch(&shader_setup); | 
					
						
							|  |  |  |     debug_data = shader_engine->ProduceDebugInfo(input_vertex, num_attributes, entry_point); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Reload widget state
 | 
					
						
							| 
									
										
										
										
											2015-10-06 21:28:19 -05:00
										 |  |  |     for (int attr = 0; attr < num_attributes; ++attr) { | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |         unsigned source_attr = shader_config.input_register_map.GetRegisterForAttribute(attr); | 
					
						
							| 
									
										
										
										
											2016-03-09 13:15:37 +01:00
										 |  |  |         input_data_mapping[attr]->setText(QString("-> v%1").arg(source_attr)); | 
					
						
							|  |  |  |         input_data_container[attr]->setVisible(true); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-08-25 02:36:57 -03:00
										 |  |  |     // Only show input attributes which are used as input to the shader
 | 
					
						
							|  |  |  |     for (unsigned int attr = num_attributes; attr < 16; ++attr) { | 
					
						
							|  |  |  |         input_data_container[attr]->setVisible(false); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-15 20:13:48 +02:00
										 |  |  |     // Initialize debug info text for current cycle count
 | 
					
						
							| 
									
										
										
										
											2016-04-25 16:10:03 -04:00
										 |  |  |     cycle_index->setMaximum(static_cast<int>(debug_data.records.size() - 1)); | 
					
						
							| 
									
										
										
										
											2015-08-15 20:13:48 +02:00
										 |  |  |     OnCycleIndexChanged(cycle_index->value()); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     model->endResetModel(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 19:24:56 +01:00
										 |  |  | void GraphicsVertexShaderWidget::OnResumed() { | 
					
						
							|  |  |  |     widget()->setEnabled(false); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | void GraphicsVertexShaderWidget::OnInputAttributeChanged(int index) { | 
					
						
							|  |  |  |     float value = input_data[index]->text().toFloat(); | 
					
						
							| 
									
										
										
										
											2015-08-25 06:46:11 -03:00
										 |  |  |     input_vertex.attr[index / 4][index % 4] = Pica::float24::FromFloat32(value); | 
					
						
							|  |  |  |     // Re-execute shader with updated value
 | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     Reload(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-15 20:13:48 +02:00
										 |  |  | void GraphicsVertexShaderWidget::OnCycleIndexChanged(int index) { | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     QString text; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto& record = debug_data.records[index]; | 
					
						
							|  |  |  |     if (record.mask & Pica::Shader::DebugDataRecord::SRC1) | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |         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()); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     if (record.mask & Pica::Shader::DebugDataRecord::SRC2) | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |         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()); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     if (record.mask & Pica::Shader::DebugDataRecord::SRC3) | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |         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()); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     if (record.mask & Pica::Shader::DebugDataRecord::DEST_IN) | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |         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()); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     if (record.mask & Pica::Shader::DebugDataRecord::DEST_OUT) | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |         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()); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (record.mask & Pica::Shader::DebugDataRecord::ADDR_REG_OUT) | 
					
						
							| 
									
										
										
										
											2016-10-20 12:26:59 -02:00
										 |  |  |         text += tr("Address Registers: %1, %2\n") | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |                     .arg(record.address_registers[0]) | 
					
						
							|  |  |  |                     .arg(record.address_registers[1]); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     if (record.mask & Pica::Shader::DebugDataRecord::CMP_RESULT) | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |         text += tr("Compare Result: %1, %2\n") | 
					
						
							|  |  |  |                     .arg(record.conditional_code[0] ? "true" : "false") | 
					
						
							|  |  |  |                     .arg(record.conditional_code[1] ? "true" : "false"); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (record.mask & Pica::Shader::DebugDataRecord::COND_BOOL_IN) | 
					
						
							|  |  |  |         text += tr("Static Condition: %1\n").arg(record.cond_bool ? "true" : "false"); | 
					
						
							|  |  |  |     if (record.mask & Pica::Shader::DebugDataRecord::COND_CMP_IN) | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |         text += tr("Dynamic Conditions: %1, %2\n") | 
					
						
							|  |  |  |                     .arg(record.cond_cmp[0] ? "true" : "false") | 
					
						
							|  |  |  |                     .arg(record.cond_cmp[1] ? "true" : "false"); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     if (record.mask & Pica::Shader::DebugDataRecord::LOOP_INT_IN) | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |         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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     text += | 
					
						
							|  |  |  |         tr("Instruction offset: 0x%1").arg(4 * record.instruction_offset, 4, 16, QLatin1Char('0')); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     if (record.mask & Pica::Shader::DebugDataRecord::NEXT_INSTR) { | 
					
						
							|  |  |  |         text += tr(" -> 0x%2").arg(4 * record.next_instruction, 4, 16, QLatin1Char('0')); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         text += tr(" (last instruction)"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     instruction_description->setText(text); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 06:45:29 -03:00
										 |  |  |     // Emit model update notification and scroll to current instruction
 | 
					
						
							| 
									
										
										
										
											2015-08-25 06:16:21 -03:00
										 |  |  |     QModelIndex instr_index = model->index(record.instruction_offset, 0); | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |     emit model->dataChanged(instr_index, | 
					
						
							|  |  |  |                             model->index(record.instruction_offset, model->columnCount())); | 
					
						
							| 
									
										
										
										
											2015-07-12 01:57:59 +02:00
										 |  |  |     binary_list->scrollTo(instr_index, QAbstractItemView::EnsureVisible); | 
					
						
							|  |  |  | } |