diff options
| author | 2015-08-25 04:52:37 -0300 | |
|---|---|---|
| committer | 2015-09-07 16:46:23 -0300 | |
| commit | 9431ee330aab4d1bb622bf9250a0cc57cfe99982 (patch) | |
| tree | 29ec436c117275a6595f827dee54482b4ca011dd /src | |
| parent | Merge pull request #1117 from yuriks/fix-glad-build (diff) | |
| download | yuzu-9431ee330aab4d1bb622bf9250a0cc57cfe99982.tar.gz yuzu-9431ee330aab4d1bb622bf9250a0cc57cfe99982.tar.xz yuzu-9431ee330aab4d1bb622bf9250a0cc57cfe99982.zip | |
Shader Disassembly: Cleanup code and improve output alignment
Diffstat (limited to 'src')
| -rw-r--r-- | src/citra_qt/debugger/graphics_vertex_shader.cpp | 145 |
1 files changed, 79 insertions, 66 deletions
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp index 1d9a00e89..eaa749f30 100644 --- a/src/citra_qt/debugger/graphics_vertex_shader.cpp +++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp | |||
| @@ -65,6 +65,19 @@ QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orie | |||
| 65 | return QVariant(); | 65 | return QVariant(); |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | // e.g. "-c92[a0.x].xyzw" | ||
| 69 | static void print_input(std::ostringstream& output, const SourceRegister& input, | ||
| 70 | bool negate, const std::string& swizzle_mask, bool align = true, | ||
| 71 | const std::string& address_register_name = std::string()) { | ||
| 72 | if (align) | ||
| 73 | output << std::setw(4) << std::right; | ||
| 74 | output << ((negate ? "-" : "") + input.GetName()); | ||
| 75 | |||
| 76 | if (!address_register_name.empty()) | ||
| 77 | output << '[' << address_register_name << ']'; | ||
| 78 | output << '.' << swizzle_mask; | ||
| 79 | }; | ||
| 80 | |||
| 68 | QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) const { | 81 | QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) const { |
| 69 | switch (role) { | 82 | switch (role) { |
| 70 | case Qt::DisplayRole: | 83 | case Qt::DisplayRole: |
| @@ -81,43 +94,34 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 81 | 94 | ||
| 82 | case 2: | 95 | case 2: |
| 83 | { | 96 | { |
| 84 | std::stringstream output; | 97 | std::ostringstream output; |
| 85 | output.flags(std::ios::hex); | 98 | output.flags(std::ios::hex | std::ios::uppercase); |
| 99 | |||
| 100 | // To make the code aligning columns of assembly easier to keep track of, this function | ||
| 101 | // keeps track of the start of the start of the previous column, allowing alignment | ||
| 102 | // based on desired field widths. | ||
| 103 | int current_column = 0; | ||
| 104 | auto AlignToColumn = [&](int col_width) { | ||
| 105 | // Prints spaces to the output to pad previous column to size and advances the | ||
| 106 | // column marker. | ||
| 107 | current_column += col_width; | ||
| 108 | int to_add = std::max(1, current_column - (int)output.tellp()); | ||
| 109 | for (int i = 0; i < to_add; ++i) { | ||
| 110 | output << ' '; | ||
| 111 | } | ||
| 112 | }; | ||
| 86 | 113 | ||
| 87 | Instruction instr = par->info.code[index.row()]; | 114 | Instruction instr = par->info.code[index.row()]; |
| 88 | const SwizzlePattern& swizzle = par->info.swizzle_info[instr.common.operand_desc_id].pattern; | 115 | const SwizzlePattern& swizzle = par->info.swizzle_info[instr.common.operand_desc_id].pattern; |
| 89 | 116 | ||
| 90 | // longest known instruction name: "setemit " | 117 | // longest known instruction name: "setemit " |
| 91 | output << std::setw(8) << std::left << instr.opcode.Value().GetInfo().name; | 118 | int kOpcodeColumnWidth = 8; |
| 92 | 119 | // "rXX.xyzw " | |
| 93 | // e.g. "-c92.xyzw" | 120 | int kOutputColumnWidth = 10; |
| 94 | static auto print_input = [](std::stringstream& output, const SourceRegister& input, | 121 | // "-rXX.xyzw ", no attempt is made to align indexed inputs |
| 95 | bool negate, const std::string& swizzle_mask) { | 122 | int kInputOperandColumnWidth = 11; |
| 96 | output << std::setw(4) << std::right << (negate ? "-" : "") + input.GetName(); | ||
| 97 | output << "." << swizzle_mask; | ||
| 98 | }; | ||
| 99 | |||
| 100 | // e.g. "-c92[a0.x].xyzw" | ||
| 101 | static auto print_input_indexed = [](std::stringstream& output, const SourceRegister& input, | ||
| 102 | bool negate, const std::string& swizzle_mask, | ||
| 103 | const std::string& address_register_name) { | ||
| 104 | std::string relative_address; | ||
| 105 | if (!address_register_name.empty()) | ||
| 106 | relative_address = "[" + address_register_name + "]"; | ||
| 107 | |||
| 108 | output << std::setw(10) << std::right << (negate ? "-" : "") + input.GetName() + relative_address; | ||
| 109 | output << "." << swizzle_mask; | ||
| 110 | }; | ||
| 111 | 123 | ||
| 112 | // Use print_input or print_input_indexed depending on whether relative addressing is used or not. | 124 | output << instr.opcode.Value().GetInfo().name; |
| 113 | static auto print_input_indexed_compact = [](std::stringstream& output, const SourceRegister& input, | ||
| 114 | bool negate, const std::string& swizzle_mask, | ||
| 115 | const std::string& address_register_name) { | ||
| 116 | if (address_register_name.empty()) | ||
| 117 | print_input(output, input, negate, swizzle_mask); | ||
| 118 | else | ||
| 119 | print_input_indexed(output, input, negate, swizzle_mask, address_register_name); | ||
| 120 | }; | ||
| 121 | 125 | ||
| 122 | switch (instr.opcode.Value().GetInfo().type) { | 126 | switch (instr.opcode.Value().GetInfo().type) { |
| 123 | case OpCode::Type::Trivial: | 127 | case OpCode::Type::Trivial: |
| @@ -130,53 +134,54 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 130 | switch (instr.opcode.Value().EffectiveOpCode()) { | 134 | switch (instr.opcode.Value().EffectiveOpCode()) { |
| 131 | case OpCode::Id::CMP: | 135 | case OpCode::Id::CMP: |
| 132 | { | 136 | { |
| 137 | AlignToColumn(kOpcodeColumnWidth); | ||
| 138 | |||
| 133 | // NOTE: CMP always writes both cc components, so we do not consider the dest mask here. | 139 | // NOTE: CMP always writes both cc components, so we do not consider the dest mask here. |
| 134 | output << std::setw(4) << std::right << "cc."; | 140 | output << " cc.xy"; |
| 135 | output << "xy "; | 141 | AlignToColumn(kOutputColumnWidth); |
| 136 | 142 | ||
| 137 | SourceRegister src1 = instr.common.GetSrc1(false); | 143 | SourceRegister src1 = instr.common.GetSrc1(false); |
| 138 | SourceRegister src2 = instr.common.GetSrc2(false); | 144 | SourceRegister src2 = instr.common.GetSrc2(false); |
| 139 | 145 | ||
| 140 | print_input_indexed_compact(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(0,1), instr.common.AddressRegisterName()); | 146 | output << ' '; |
| 141 | output << " " << instr.common.compare_op.ToString(instr.common.compare_op.x) << " "; | 147 | print_input(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(0,1), false, instr.common.AddressRegisterName()); |
| 142 | print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true).substr(0,1)); | 148 | output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.x) << ' '; |
| 149 | print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true).substr(0,1), false); | ||
| 143 | 150 | ||
| 144 | output << ", "; | 151 | output << ", "; |
| 145 | 152 | ||
| 146 | print_input_indexed_compact(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(1,1), instr.common.AddressRegisterName()); | 153 | print_input(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(1,1), false, instr.common.AddressRegisterName()); |
| 147 | output << " " << instr.common.compare_op.ToString(instr.common.compare_op.y) << " "; | 154 | output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.y) << ' '; |
| 148 | print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true).substr(1,1)); | 155 | print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true).substr(1,1), false); |
| 149 | 156 | ||
| 150 | break; | 157 | break; |
| 151 | } | 158 | } |
| 152 | 159 | ||
| 153 | default: | 160 | default: |
| 154 | { | 161 | { |
| 162 | AlignToColumn(kOpcodeColumnWidth); | ||
| 163 | |||
| 155 | bool src_is_inverted = 0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed); | 164 | bool src_is_inverted = 0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed); |
| 156 | 165 | ||
| 157 | if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::Dest) { | 166 | if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::Dest) { |
| 158 | // e.g. "r12.xy__" | 167 | // e.g. "r12.xy__" |
| 159 | output << std::setw(4) << std::right << instr.common.dest.Value().GetName() + "."; | 168 | output << std::setw(3) << std::right << instr.common.dest.Value().GetName() << '.' << swizzle.DestMaskToString(); |
| 160 | output << swizzle.DestMaskToString(); | ||
| 161 | } else if (instr.opcode.Value().GetInfo().subtype == OpCode::Info::MOVA) { | 169 | } else if (instr.opcode.Value().GetInfo().subtype == OpCode::Info::MOVA) { |
| 162 | output << std::setw(4) << std::right << "a0."; | 170 | output << " a0." << swizzle.DestMaskToString(); |
| 163 | output << swizzle.DestMaskToString(); | ||
| 164 | } else { | ||
| 165 | output << " "; | ||
| 166 | } | 171 | } |
| 167 | output << " "; | 172 | AlignToColumn(kOutputColumnWidth); |
| 168 | 173 | ||
| 169 | if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::Src1) { | 174 | if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::Src1) { |
| 170 | SourceRegister src1 = instr.common.GetSrc1(src_is_inverted); | 175 | SourceRegister src1 = instr.common.GetSrc1(src_is_inverted); |
| 171 | print_input_indexed(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false), instr.common.AddressRegisterName()); | 176 | print_input(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false), true, instr.common.AddressRegisterName()); |
| 172 | } else { | 177 | AlignToColumn(kInputOperandColumnWidth); |
| 173 | output << " "; | ||
| 174 | } | 178 | } |
| 175 | 179 | ||
| 176 | // TODO: In some cases, the Address Register is used as an index for SRC2 instead of SRC1 | 180 | // TODO: In some cases, the Address Register is used as an index for SRC2 instead of SRC1 |
| 177 | if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::Src2) { | 181 | if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::Src2) { |
| 178 | SourceRegister src2 = instr.common.GetSrc2(src_is_inverted); | 182 | SourceRegister src2 = instr.common.GetSrc2(src_is_inverted); |
| 179 | print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true)); | 183 | print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true)); |
| 184 | AlignToColumn(kInputOperandColumnWidth); | ||
| 180 | } | 185 | } |
| 181 | break; | 186 | break; |
| 182 | } | 187 | } |
| @@ -187,45 +192,53 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 187 | 192 | ||
| 188 | case OpCode::Type::Conditional: | 193 | case OpCode::Type::Conditional: |
| 189 | { | 194 | { |
| 195 | output << ' '; | ||
| 196 | |||
| 190 | switch (instr.opcode.Value().EffectiveOpCode()) { | 197 | switch (instr.opcode.Value().EffectiveOpCode()) { |
| 191 | case OpCode::Id::LOOP: | 198 | case OpCode::Id::LOOP: |
| 192 | output << "(unknown instruction format)"; | 199 | output << "(unknown instruction format)"; |
| 193 | break; | 200 | break; |
| 194 | 201 | ||
| 195 | default: | 202 | default: |
| 196 | output << "if "; | ||
| 197 | |||
| 198 | if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasCondition) { | 203 | if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasCondition) { |
| 199 | const char* ops[] = { | 204 | output << '('; |
| 200 | " || ", " && ", "", "" | 205 | |
| 201 | }; | 206 | if (instr.flow_control.op != instr.flow_control.JustY) { |
| 202 | if (instr.flow_control.op != instr.flow_control.JustY) | 207 | if (instr.flow_control.refx) output << '!'; |
| 203 | output << ((!instr.flow_control.refx) ? "!" : " ") << "cc.x"; | 208 | output << "cc.x"; |
| 209 | } | ||
| 204 | 210 | ||
| 205 | output << ops[instr.flow_control.op]; | 211 | if (instr.flow_control.op == instr.flow_control.Or) { |
| 212 | output << " || "; | ||
| 213 | } else if (instr.flow_control.op == instr.flow_control.And) { | ||
| 214 | output << " && "; | ||
| 215 | } | ||
| 206 | 216 | ||
| 207 | if (instr.flow_control.op != instr.flow_control.JustX) | 217 | if (instr.flow_control.op != instr.flow_control.JustX) { |
| 208 | output << ((!instr.flow_control.refy) ? "!" : " ") << "cc.y"; | 218 | if (instr.flow_control.refy) output << '!'; |
| 219 | output << "cc.y"; | ||
| 220 | } | ||
| 209 | 221 | ||
| 210 | output << " "; | 222 | output << ") "; |
| 211 | } else if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasUniformIndex) { | 223 | } else if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasUniformIndex) { |
| 212 | output << "b" << instr.flow_control.bool_uniform_id << " "; | 224 | output << 'b' << instr.flow_control.bool_uniform_id << ' '; |
| 213 | } | 225 | } |
| 214 | 226 | ||
| 215 | u32 target_addr = instr.flow_control.dest_offset; | 227 | u32 target_addr = instr.flow_control.dest_offset; |
| 216 | u32 target_addr_else = instr.flow_control.dest_offset; | 228 | u32 target_addr_else = instr.flow_control.dest_offset; |
| 217 | 229 | ||
| 218 | if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasAlternative) { | 230 | if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasAlternative) { |
| 219 | output << "else jump to 0x" << std::setw(4) << std::right << std::setfill('0') << 4 * instr.flow_control.dest_offset << " "; | 231 | output << "else jump to 0x" << std::setw(4) << std::right << std::setfill('0') << (4 * instr.flow_control.dest_offset); |
| 220 | } else if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasExplicitDest) { | 232 | } else if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasExplicitDest) { |
| 221 | output << "jump to 0x" << std::setw(4) << std::right << std::setfill('0') << 4 * instr.flow_control.dest_offset << " "; | 233 | output << "jump to 0x" << std::setw(4) << std::right << std::setfill('0') << (4 * instr.flow_control.dest_offset); |
| 222 | } else { | 234 | } else { |
| 223 | // TODO: Handle other cases | 235 | // TODO: Handle other cases |
| 236 | output << "(unknown destination)"; | ||
| 224 | } | 237 | } |
| 225 | 238 | ||
| 226 | if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasFinishPoint) { | 239 | if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasFinishPoint) { |
| 227 | output << "(return on " << std::setw(4) << std::right << std::setfill('0') | 240 | output << " (return on " << std::setw(4) << std::right << std::setfill('0') |
| 228 | << 4 * instr.flow_control.dest_offset + 4 * instr.flow_control.num_instructions << ")"; | 241 | << (4 * instr.flow_control.dest_offset + 4 * instr.flow_control.num_instructions) << ')'; |
| 229 | } | 242 | } |
| 230 | 243 | ||
| 231 | break; | 244 | break; |
| @@ -234,7 +247,7 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 234 | } | 247 | } |
| 235 | 248 | ||
| 236 | default: | 249 | default: |
| 237 | output << "(unknown instruction format)"; | 250 | output << " (unknown instruction format)"; |
| 238 | break; | 251 | break; |
| 239 | } | 252 | } |
| 240 | 253 | ||