diff options
| author | 2016-12-15 22:30:43 -0800 | |
|---|---|---|
| committer | 2016-12-15 23:08:05 -0800 | |
| commit | d27cb1dedca7ff5e977668160bf3e24b75beb092 (patch) | |
| tree | 985bf71a0d2996872f52837e5cb48b93d94ae162 /src | |
| parent | Merge pull request #2260 from Subv/scheduling (diff) | |
| download | yuzu-d27cb1dedca7ff5e977668160bf3e24b75beb092.tar.gz yuzu-d27cb1dedca7ff5e977668160bf3e24b75beb092.tar.xz yuzu-d27cb1dedca7ff5e977668160bf3e24b75beb092.zip | |
VideoCore/Shader: Move DebugData to a separate file
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/video_core/shader/debug_data.h | 186 | ||||
| -rw-r--r-- | src/video_core/shader/shader.h | 173 | ||||
| -rw-r--r-- | src/video_core/shader/shader_interpreter.cpp | 1 |
4 files changed, 189 insertions, 172 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 9aa446a8f..6ca319b59 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -39,6 +39,7 @@ set(HEADERS | |||
| 39 | rasterizer.h | 39 | rasterizer.h |
| 40 | rasterizer_interface.h | 40 | rasterizer_interface.h |
| 41 | renderer_base.h | 41 | renderer_base.h |
| 42 | shader/debug_data.h | ||
| 42 | shader/shader.h | 43 | shader/shader.h |
| 43 | shader/shader_interpreter.h | 44 | shader/shader_interpreter.h |
| 44 | swrasterizer.h | 45 | swrasterizer.h |
diff --git a/src/video_core/shader/debug_data.h b/src/video_core/shader/debug_data.h new file mode 100644 index 000000000..b0ccf437d --- /dev/null +++ b/src/video_core/shader/debug_data.h | |||
| @@ -0,0 +1,186 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/vector_math.h" | ||
| 10 | #include "video_core/pica_types.h" | ||
| 11 | |||
| 12 | namespace Pica { | ||
| 13 | namespace Shader { | ||
| 14 | |||
| 15 | /// Helper structure used to keep track of data useful for inspection of shader emulation | ||
| 16 | template <bool full_debugging> | ||
| 17 | struct DebugData; | ||
| 18 | |||
| 19 | template <> | ||
| 20 | struct DebugData<false> { | ||
| 21 | // TODO: Hide these behind and interface and move them to DebugData<true> | ||
| 22 | u32 max_offset; ///< maximum program counter ever reached | ||
| 23 | u32 max_opdesc_id; ///< maximum swizzle pattern index ever used | ||
| 24 | }; | ||
| 25 | |||
| 26 | template <> | ||
| 27 | struct DebugData<true> { | ||
| 28 | /// Records store the input and output operands of a particular instruction. | ||
| 29 | struct Record { | ||
| 30 | enum Type { | ||
| 31 | // Floating point arithmetic operands | ||
| 32 | SRC1 = 0x1, | ||
| 33 | SRC2 = 0x2, | ||
| 34 | SRC3 = 0x4, | ||
| 35 | |||
| 36 | // Initial and final output operand value | ||
| 37 | DEST_IN = 0x8, | ||
| 38 | DEST_OUT = 0x10, | ||
| 39 | |||
| 40 | // Current and next instruction offset (in words) | ||
| 41 | CUR_INSTR = 0x20, | ||
| 42 | NEXT_INSTR = 0x40, | ||
| 43 | |||
| 44 | // Output address register value | ||
| 45 | ADDR_REG_OUT = 0x80, | ||
| 46 | |||
| 47 | // Result of a comparison instruction | ||
| 48 | CMP_RESULT = 0x100, | ||
| 49 | |||
| 50 | // Input values for conditional flow control instructions | ||
| 51 | COND_BOOL_IN = 0x200, | ||
| 52 | COND_CMP_IN = 0x400, | ||
| 53 | |||
| 54 | // Input values for a loop | ||
| 55 | LOOP_INT_IN = 0x800, | ||
| 56 | }; | ||
| 57 | |||
| 58 | Math::Vec4<float24> src1; | ||
| 59 | Math::Vec4<float24> src2; | ||
| 60 | Math::Vec4<float24> src3; | ||
| 61 | |||
| 62 | Math::Vec4<float24> dest_in; | ||
| 63 | Math::Vec4<float24> dest_out; | ||
| 64 | |||
| 65 | s32 address_registers[2]; | ||
| 66 | bool conditional_code[2]; | ||
| 67 | bool cond_bool; | ||
| 68 | bool cond_cmp[2]; | ||
| 69 | Math::Vec4<u8> loop_int; | ||
| 70 | |||
| 71 | u32 instruction_offset; | ||
| 72 | u32 next_instruction; | ||
| 73 | |||
| 74 | /// set of enabled fields (as a combination of Type flags) | ||
| 75 | unsigned mask = 0; | ||
| 76 | }; | ||
| 77 | |||
| 78 | u32 max_offset; ///< maximum program counter ever reached | ||
| 79 | u32 max_opdesc_id; ///< maximum swizzle pattern index ever used | ||
| 80 | |||
| 81 | /// List of records for each executed shader instruction | ||
| 82 | std::vector<DebugData<true>::Record> records; | ||
| 83 | }; | ||
| 84 | |||
| 85 | /// Type alias for better readability | ||
| 86 | using DebugDataRecord = DebugData<true>::Record; | ||
| 87 | |||
| 88 | /// Helper function to set a DebugData<true>::Record field based on the template enum parameter. | ||
| 89 | template <DebugDataRecord::Type type, typename ValueType> | ||
| 90 | inline void SetField(DebugDataRecord& record, ValueType value); | ||
| 91 | |||
| 92 | template <> | ||
| 93 | inline void SetField<DebugDataRecord::SRC1>(DebugDataRecord& record, float24* value) { | ||
| 94 | record.src1.x = value[0]; | ||
| 95 | record.src1.y = value[1]; | ||
| 96 | record.src1.z = value[2]; | ||
| 97 | record.src1.w = value[3]; | ||
| 98 | } | ||
| 99 | |||
| 100 | template <> | ||
| 101 | inline void SetField<DebugDataRecord::SRC2>(DebugDataRecord& record, float24* value) { | ||
| 102 | record.src2.x = value[0]; | ||
| 103 | record.src2.y = value[1]; | ||
| 104 | record.src2.z = value[2]; | ||
| 105 | record.src2.w = value[3]; | ||
| 106 | } | ||
| 107 | |||
| 108 | template <> | ||
| 109 | inline void SetField<DebugDataRecord::SRC3>(DebugDataRecord& record, float24* value) { | ||
| 110 | record.src3.x = value[0]; | ||
| 111 | record.src3.y = value[1]; | ||
| 112 | record.src3.z = value[2]; | ||
| 113 | record.src3.w = value[3]; | ||
| 114 | } | ||
| 115 | |||
| 116 | template <> | ||
| 117 | inline void SetField<DebugDataRecord::DEST_IN>(DebugDataRecord& record, float24* value) { | ||
| 118 | record.dest_in.x = value[0]; | ||
| 119 | record.dest_in.y = value[1]; | ||
| 120 | record.dest_in.z = value[2]; | ||
| 121 | record.dest_in.w = value[3]; | ||
| 122 | } | ||
| 123 | |||
| 124 | template <> | ||
| 125 | inline void SetField<DebugDataRecord::DEST_OUT>(DebugDataRecord& record, float24* value) { | ||
| 126 | record.dest_out.x = value[0]; | ||
| 127 | record.dest_out.y = value[1]; | ||
| 128 | record.dest_out.z = value[2]; | ||
| 129 | record.dest_out.w = value[3]; | ||
| 130 | } | ||
| 131 | |||
| 132 | template <> | ||
| 133 | inline void SetField<DebugDataRecord::ADDR_REG_OUT>(DebugDataRecord& record, s32* value) { | ||
| 134 | record.address_registers[0] = value[0]; | ||
| 135 | record.address_registers[1] = value[1]; | ||
| 136 | } | ||
| 137 | |||
| 138 | template <> | ||
| 139 | inline void SetField<DebugDataRecord::CMP_RESULT>(DebugDataRecord& record, bool* value) { | ||
| 140 | record.conditional_code[0] = value[0]; | ||
| 141 | record.conditional_code[1] = value[1]; | ||
| 142 | } | ||
| 143 | |||
| 144 | template <> | ||
| 145 | inline void SetField<DebugDataRecord::COND_BOOL_IN>(DebugDataRecord& record, bool value) { | ||
| 146 | record.cond_bool = value; | ||
| 147 | } | ||
| 148 | |||
| 149 | template <> | ||
| 150 | inline void SetField<DebugDataRecord::COND_CMP_IN>(DebugDataRecord& record, bool* value) { | ||
| 151 | record.cond_cmp[0] = value[0]; | ||
| 152 | record.cond_cmp[1] = value[1]; | ||
| 153 | } | ||
| 154 | |||
| 155 | template <> | ||
| 156 | inline void SetField<DebugDataRecord::LOOP_INT_IN>(DebugDataRecord& record, Math::Vec4<u8> value) { | ||
| 157 | record.loop_int = value; | ||
| 158 | } | ||
| 159 | |||
| 160 | template <> | ||
| 161 | inline void SetField<DebugDataRecord::CUR_INSTR>(DebugDataRecord& record, u32 value) { | ||
| 162 | record.instruction_offset = value; | ||
| 163 | } | ||
| 164 | |||
| 165 | template <> | ||
| 166 | inline void SetField<DebugDataRecord::NEXT_INSTR>(DebugDataRecord& record, u32 value) { | ||
| 167 | record.next_instruction = value; | ||
| 168 | } | ||
| 169 | |||
| 170 | /// Helper function to set debug information on the current shader iteration. | ||
| 171 | template <DebugDataRecord::Type type, typename ValueType> | ||
| 172 | inline void Record(DebugData<false>& debug_data, u32 offset, ValueType value) { | ||
| 173 | // Debugging disabled => nothing to do | ||
| 174 | } | ||
| 175 | |||
| 176 | template <DebugDataRecord::Type type, typename ValueType> | ||
| 177 | inline void Record(DebugData<true>& debug_data, u32 offset, ValueType value) { | ||
| 178 | if (offset >= debug_data.records.size()) | ||
| 179 | debug_data.records.resize(offset + 1); | ||
| 180 | |||
| 181 | SetField<type, ValueType>(debug_data.records[offset], value); | ||
| 182 | debug_data.records[offset].mask |= type; | ||
| 183 | } | ||
| 184 | |||
| 185 | } // namespace Shader | ||
| 186 | } // namespace Pica | ||
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h index 0111d8c0f..87c4e0b6f 100644 --- a/src/video_core/shader/shader.h +++ b/src/video_core/shader/shader.h | |||
| @@ -8,8 +8,6 @@ | |||
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | #include <type_traits> | 10 | #include <type_traits> |
| 11 | #include <vector> | ||
| 12 | #include <boost/container/static_vector.hpp> | ||
| 13 | #include <nihstro/shader_bytecode.h> | 11 | #include <nihstro/shader_bytecode.h> |
| 14 | #include "common/assert.h" | 12 | #include "common/assert.h" |
| 15 | #include "common/common_funcs.h" | 13 | #include "common/common_funcs.h" |
| @@ -17,6 +15,7 @@ | |||
| 17 | #include "common/vector_math.h" | 15 | #include "common/vector_math.h" |
| 18 | #include "video_core/pica.h" | 16 | #include "video_core/pica.h" |
| 19 | #include "video_core/pica_types.h" | 17 | #include "video_core/pica_types.h" |
| 18 | #include "video_core/shader/debug_data.h" | ||
| 20 | 19 | ||
| 21 | using nihstro::RegisterType; | 20 | using nihstro::RegisterType; |
| 22 | using nihstro::SourceRegister; | 21 | using nihstro::SourceRegister; |
| @@ -89,176 +88,6 @@ struct OutputRegisters { | |||
| 89 | }; | 88 | }; |
| 90 | static_assert(std::is_pod<OutputRegisters>::value, "Structure is not POD"); | 89 | static_assert(std::is_pod<OutputRegisters>::value, "Structure is not POD"); |
| 91 | 90 | ||
| 92 | // Helper structure used to keep track of data useful for inspection of shader emulation | ||
| 93 | template <bool full_debugging> | ||
| 94 | struct DebugData; | ||
| 95 | |||
| 96 | template <> | ||
| 97 | struct DebugData<false> { | ||
| 98 | // TODO: Hide these behind and interface and move them to DebugData<true> | ||
| 99 | u32 max_offset; // maximum program counter ever reached | ||
| 100 | u32 max_opdesc_id; // maximum swizzle pattern index ever used | ||
| 101 | }; | ||
| 102 | |||
| 103 | template <> | ||
| 104 | struct DebugData<true> { | ||
| 105 | // Records store the input and output operands of a particular instruction. | ||
| 106 | struct Record { | ||
| 107 | enum Type { | ||
| 108 | // Floating point arithmetic operands | ||
| 109 | SRC1 = 0x1, | ||
| 110 | SRC2 = 0x2, | ||
| 111 | SRC3 = 0x4, | ||
| 112 | |||
| 113 | // Initial and final output operand value | ||
| 114 | DEST_IN = 0x8, | ||
| 115 | DEST_OUT = 0x10, | ||
| 116 | |||
| 117 | // Current and next instruction offset (in words) | ||
| 118 | CUR_INSTR = 0x20, | ||
| 119 | NEXT_INSTR = 0x40, | ||
| 120 | |||
| 121 | // Output address register value | ||
| 122 | ADDR_REG_OUT = 0x80, | ||
| 123 | |||
| 124 | // Result of a comparison instruction | ||
| 125 | CMP_RESULT = 0x100, | ||
| 126 | |||
| 127 | // Input values for conditional flow control instructions | ||
| 128 | COND_BOOL_IN = 0x200, | ||
| 129 | COND_CMP_IN = 0x400, | ||
| 130 | |||
| 131 | // Input values for a loop | ||
| 132 | LOOP_INT_IN = 0x800, | ||
| 133 | }; | ||
| 134 | |||
| 135 | Math::Vec4<float24> src1; | ||
| 136 | Math::Vec4<float24> src2; | ||
| 137 | Math::Vec4<float24> src3; | ||
| 138 | |||
| 139 | Math::Vec4<float24> dest_in; | ||
| 140 | Math::Vec4<float24> dest_out; | ||
| 141 | |||
| 142 | s32 address_registers[2]; | ||
| 143 | bool conditional_code[2]; | ||
| 144 | bool cond_bool; | ||
| 145 | bool cond_cmp[2]; | ||
| 146 | Math::Vec4<u8> loop_int; | ||
| 147 | |||
| 148 | u32 instruction_offset; | ||
| 149 | u32 next_instruction; | ||
| 150 | |||
| 151 | // set of enabled fields (as a combination of Type flags) | ||
| 152 | unsigned mask = 0; | ||
| 153 | }; | ||
| 154 | |||
| 155 | u32 max_offset; // maximum program counter ever reached | ||
| 156 | u32 max_opdesc_id; // maximum swizzle pattern index ever used | ||
| 157 | |||
| 158 | // List of records for each executed shader instruction | ||
| 159 | std::vector<DebugData<true>::Record> records; | ||
| 160 | }; | ||
| 161 | |||
| 162 | // Type alias for better readability | ||
| 163 | using DebugDataRecord = DebugData<true>::Record; | ||
| 164 | |||
| 165 | // Helper function to set a DebugData<true>::Record field based on the template enum parameter. | ||
| 166 | template <DebugDataRecord::Type type, typename ValueType> | ||
| 167 | inline void SetField(DebugDataRecord& record, ValueType value); | ||
| 168 | |||
| 169 | template <> | ||
| 170 | inline void SetField<DebugDataRecord::SRC1>(DebugDataRecord& record, float24* value) { | ||
| 171 | record.src1.x = value[0]; | ||
| 172 | record.src1.y = value[1]; | ||
| 173 | record.src1.z = value[2]; | ||
| 174 | record.src1.w = value[3]; | ||
| 175 | } | ||
| 176 | |||
| 177 | template <> | ||
| 178 | inline void SetField<DebugDataRecord::SRC2>(DebugDataRecord& record, float24* value) { | ||
| 179 | record.src2.x = value[0]; | ||
| 180 | record.src2.y = value[1]; | ||
| 181 | record.src2.z = value[2]; | ||
| 182 | record.src2.w = value[3]; | ||
| 183 | } | ||
| 184 | |||
| 185 | template <> | ||
| 186 | inline void SetField<DebugDataRecord::SRC3>(DebugDataRecord& record, float24* value) { | ||
| 187 | record.src3.x = value[0]; | ||
| 188 | record.src3.y = value[1]; | ||
| 189 | record.src3.z = value[2]; | ||
| 190 | record.src3.w = value[3]; | ||
| 191 | } | ||
| 192 | |||
| 193 | template <> | ||
| 194 | inline void SetField<DebugDataRecord::DEST_IN>(DebugDataRecord& record, float24* value) { | ||
| 195 | record.dest_in.x = value[0]; | ||
| 196 | record.dest_in.y = value[1]; | ||
| 197 | record.dest_in.z = value[2]; | ||
| 198 | record.dest_in.w = value[3]; | ||
| 199 | } | ||
| 200 | |||
| 201 | template <> | ||
| 202 | inline void SetField<DebugDataRecord::DEST_OUT>(DebugDataRecord& record, float24* value) { | ||
| 203 | record.dest_out.x = value[0]; | ||
| 204 | record.dest_out.y = value[1]; | ||
| 205 | record.dest_out.z = value[2]; | ||
| 206 | record.dest_out.w = value[3]; | ||
| 207 | } | ||
| 208 | |||
| 209 | template <> | ||
| 210 | inline void SetField<DebugDataRecord::ADDR_REG_OUT>(DebugDataRecord& record, s32* value) { | ||
| 211 | record.address_registers[0] = value[0]; | ||
| 212 | record.address_registers[1] = value[1]; | ||
| 213 | } | ||
| 214 | |||
| 215 | template <> | ||
| 216 | inline void SetField<DebugDataRecord::CMP_RESULT>(DebugDataRecord& record, bool* value) { | ||
| 217 | record.conditional_code[0] = value[0]; | ||
| 218 | record.conditional_code[1] = value[1]; | ||
| 219 | } | ||
| 220 | |||
| 221 | template <> | ||
| 222 | inline void SetField<DebugDataRecord::COND_BOOL_IN>(DebugDataRecord& record, bool value) { | ||
| 223 | record.cond_bool = value; | ||
| 224 | } | ||
| 225 | |||
| 226 | template <> | ||
| 227 | inline void SetField<DebugDataRecord::COND_CMP_IN>(DebugDataRecord& record, bool* value) { | ||
| 228 | record.cond_cmp[0] = value[0]; | ||
| 229 | record.cond_cmp[1] = value[1]; | ||
| 230 | } | ||
| 231 | |||
| 232 | template <> | ||
| 233 | inline void SetField<DebugDataRecord::LOOP_INT_IN>(DebugDataRecord& record, Math::Vec4<u8> value) { | ||
| 234 | record.loop_int = value; | ||
| 235 | } | ||
| 236 | |||
| 237 | template <> | ||
| 238 | inline void SetField<DebugDataRecord::CUR_INSTR>(DebugDataRecord& record, u32 value) { | ||
| 239 | record.instruction_offset = value; | ||
| 240 | } | ||
| 241 | |||
| 242 | template <> | ||
| 243 | inline void SetField<DebugDataRecord::NEXT_INSTR>(DebugDataRecord& record, u32 value) { | ||
| 244 | record.next_instruction = value; | ||
| 245 | } | ||
| 246 | |||
| 247 | // Helper function to set debug information on the current shader iteration. | ||
| 248 | template <DebugDataRecord::Type type, typename ValueType> | ||
| 249 | inline void Record(DebugData<false>& debug_data, u32 offset, ValueType value) { | ||
| 250 | // Debugging disabled => nothing to do | ||
| 251 | } | ||
| 252 | |||
| 253 | template <DebugDataRecord::Type type, typename ValueType> | ||
| 254 | inline void Record(DebugData<true>& debug_data, u32 offset, ValueType value) { | ||
| 255 | if (offset >= debug_data.records.size()) | ||
| 256 | debug_data.records.resize(offset + 1); | ||
| 257 | |||
| 258 | SetField<type, ValueType>(debug_data.records[offset], value); | ||
| 259 | debug_data.records[offset].mask |= type; | ||
| 260 | } | ||
| 261 | |||
| 262 | /** | 91 | /** |
| 263 | * This structure contains the state information that needs to be unique for a shader unit. The 3DS | 92 | * This structure contains the state information that needs to be unique for a shader unit. The 3DS |
| 264 | * has four shader units that process shaders in parallel. At the present, Citra only implements a | 93 | * has four shader units that process shaders in parallel. At the present, Citra only implements a |
diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp index 6abb6761f..167f9edc3 100644 --- a/src/video_core/shader/shader_interpreter.cpp +++ b/src/video_core/shader/shader_interpreter.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <cmath> | 7 | #include <cmath> |
| 8 | #include <numeric> | 8 | #include <numeric> |
| 9 | #include <boost/container/static_vector.hpp> | ||
| 9 | #include <nihstro/shader_bytecode.h> | 10 | #include <nihstro/shader_bytecode.h> |
| 10 | #include "common/assert.h" | 11 | #include "common/assert.h" |
| 11 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |