diff options
Diffstat (limited to 'src/video_core/shader/shader.h')
| -rw-r--r-- | src/video_core/shader/shader.h | 92 |
1 files changed, 48 insertions, 44 deletions
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h index fee16df62..830d933a8 100644 --- a/src/video_core/shader/shader.h +++ b/src/video_core/shader/shader.h | |||
| @@ -94,46 +94,46 @@ struct OutputRegisters { | |||
| 94 | static_assert(std::is_pod<OutputRegisters>::value, "Structure is not POD"); | 94 | static_assert(std::is_pod<OutputRegisters>::value, "Structure is not POD"); |
| 95 | 95 | ||
| 96 | // Helper structure used to keep track of data useful for inspection of shader emulation | 96 | // Helper structure used to keep track of data useful for inspection of shader emulation |
| 97 | template<bool full_debugging> | 97 | template <bool full_debugging> |
| 98 | struct DebugData; | 98 | struct DebugData; |
| 99 | 99 | ||
| 100 | template<> | 100 | template <> |
| 101 | struct DebugData<false> { | 101 | struct DebugData<false> { |
| 102 | // TODO: Hide these behind and interface and move them to DebugData<true> | 102 | // TODO: Hide these behind and interface and move them to DebugData<true> |
| 103 | u32 max_offset; // maximum program counter ever reached | 103 | u32 max_offset; // maximum program counter ever reached |
| 104 | u32 max_opdesc_id; // maximum swizzle pattern index ever used | 104 | u32 max_opdesc_id; // maximum swizzle pattern index ever used |
| 105 | }; | 105 | }; |
| 106 | 106 | ||
| 107 | template<> | 107 | template <> |
| 108 | struct DebugData<true> { | 108 | struct DebugData<true> { |
| 109 | // Records store the input and output operands of a particular instruction. | 109 | // Records store the input and output operands of a particular instruction. |
| 110 | struct Record { | 110 | struct Record { |
| 111 | enum Type { | 111 | enum Type { |
| 112 | // Floating point arithmetic operands | 112 | // Floating point arithmetic operands |
| 113 | SRC1 = 0x1, | 113 | SRC1 = 0x1, |
| 114 | SRC2 = 0x2, | 114 | SRC2 = 0x2, |
| 115 | SRC3 = 0x4, | 115 | SRC3 = 0x4, |
| 116 | 116 | ||
| 117 | // Initial and final output operand value | 117 | // Initial and final output operand value |
| 118 | DEST_IN = 0x8, | 118 | DEST_IN = 0x8, |
| 119 | DEST_OUT = 0x10, | 119 | DEST_OUT = 0x10, |
| 120 | 120 | ||
| 121 | // Current and next instruction offset (in words) | 121 | // Current and next instruction offset (in words) |
| 122 | CUR_INSTR = 0x20, | 122 | CUR_INSTR = 0x20, |
| 123 | NEXT_INSTR = 0x40, | 123 | NEXT_INSTR = 0x40, |
| 124 | 124 | ||
| 125 | // Output address register value | 125 | // Output address register value |
| 126 | ADDR_REG_OUT = 0x80, | 126 | ADDR_REG_OUT = 0x80, |
| 127 | 127 | ||
| 128 | // Result of a comparison instruction | 128 | // Result of a comparison instruction |
| 129 | CMP_RESULT = 0x100, | 129 | CMP_RESULT = 0x100, |
| 130 | 130 | ||
| 131 | // Input values for conditional flow control instructions | 131 | // Input values for conditional flow control instructions |
| 132 | COND_BOOL_IN = 0x200, | 132 | COND_BOOL_IN = 0x200, |
| 133 | COND_CMP_IN = 0x400, | 133 | COND_CMP_IN = 0x400, |
| 134 | 134 | ||
| 135 | // Input values for a loop | 135 | // Input values for a loop |
| 136 | LOOP_INT_IN = 0x800, | 136 | LOOP_INT_IN = 0x800, |
| 137 | }; | 137 | }; |
| 138 | 138 | ||
| 139 | Math::Vec4<float24> src1; | 139 | Math::Vec4<float24> src1; |
| @@ -156,7 +156,7 @@ struct DebugData<true> { | |||
| 156 | unsigned mask = 0; | 156 | unsigned mask = 0; |
| 157 | }; | 157 | }; |
| 158 | 158 | ||
| 159 | u32 max_offset; // maximum program counter ever reached | 159 | u32 max_offset; // maximum program counter ever reached |
| 160 | u32 max_opdesc_id; // maximum swizzle pattern index ever used | 160 | u32 max_opdesc_id; // maximum swizzle pattern index ever used |
| 161 | 161 | ||
| 162 | // List of records for each executed shader instruction | 162 | // List of records for each executed shader instruction |
| @@ -167,10 +167,10 @@ struct DebugData<true> { | |||
| 167 | using DebugDataRecord = DebugData<true>::Record; | 167 | using DebugDataRecord = DebugData<true>::Record; |
| 168 | 168 | ||
| 169 | // Helper function to set a DebugData<true>::Record field based on the template enum parameter. | 169 | // Helper function to set a DebugData<true>::Record field based on the template enum parameter. |
| 170 | template<DebugDataRecord::Type type, typename ValueType> | 170 | template <DebugDataRecord::Type type, typename ValueType> |
| 171 | inline void SetField(DebugDataRecord& record, ValueType value); | 171 | inline void SetField(DebugDataRecord& record, ValueType value); |
| 172 | 172 | ||
| 173 | template<> | 173 | template <> |
| 174 | inline void SetField<DebugDataRecord::SRC1>(DebugDataRecord& record, float24* value) { | 174 | inline void SetField<DebugDataRecord::SRC1>(DebugDataRecord& record, float24* value) { |
| 175 | record.src1.x = value[0]; | 175 | record.src1.x = value[0]; |
| 176 | record.src1.y = value[1]; | 176 | record.src1.y = value[1]; |
| @@ -178,7 +178,7 @@ inline void SetField<DebugDataRecord::SRC1>(DebugDataRecord& record, float24* va | |||
| 178 | record.src1.w = value[3]; | 178 | record.src1.w = value[3]; |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | template<> | 181 | template <> |
| 182 | inline void SetField<DebugDataRecord::SRC2>(DebugDataRecord& record, float24* value) { | 182 | inline void SetField<DebugDataRecord::SRC2>(DebugDataRecord& record, float24* value) { |
| 183 | record.src2.x = value[0]; | 183 | record.src2.x = value[0]; |
| 184 | record.src2.y = value[1]; | 184 | record.src2.y = value[1]; |
| @@ -186,7 +186,7 @@ inline void SetField<DebugDataRecord::SRC2>(DebugDataRecord& record, float24* va | |||
| 186 | record.src2.w = value[3]; | 186 | record.src2.w = value[3]; |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | template<> | 189 | template <> |
| 190 | inline void SetField<DebugDataRecord::SRC3>(DebugDataRecord& record, float24* value) { | 190 | inline void SetField<DebugDataRecord::SRC3>(DebugDataRecord& record, float24* value) { |
| 191 | record.src3.x = value[0]; | 191 | record.src3.x = value[0]; |
| 192 | record.src3.y = value[1]; | 192 | record.src3.y = value[1]; |
| @@ -194,7 +194,7 @@ inline void SetField<DebugDataRecord::SRC3>(DebugDataRecord& record, float24* va | |||
| 194 | record.src3.w = value[3]; | 194 | record.src3.w = value[3]; |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | template<> | 197 | template <> |
| 198 | inline void SetField<DebugDataRecord::DEST_IN>(DebugDataRecord& record, float24* value) { | 198 | inline void SetField<DebugDataRecord::DEST_IN>(DebugDataRecord& record, float24* value) { |
| 199 | record.dest_in.x = value[0]; | 199 | record.dest_in.x = value[0]; |
| 200 | record.dest_in.y = value[1]; | 200 | record.dest_in.y = value[1]; |
| @@ -202,7 +202,7 @@ inline void SetField<DebugDataRecord::DEST_IN>(DebugDataRecord& record, float24* | |||
| 202 | record.dest_in.w = value[3]; | 202 | record.dest_in.w = value[3]; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | template<> | 205 | template <> |
| 206 | inline void SetField<DebugDataRecord::DEST_OUT>(DebugDataRecord& record, float24* value) { | 206 | inline void SetField<DebugDataRecord::DEST_OUT>(DebugDataRecord& record, float24* value) { |
| 207 | record.dest_out.x = value[0]; | 207 | record.dest_out.x = value[0]; |
| 208 | record.dest_out.y = value[1]; | 208 | record.dest_out.y = value[1]; |
| @@ -210,67 +210,66 @@ inline void SetField<DebugDataRecord::DEST_OUT>(DebugDataRecord& record, float24 | |||
| 210 | record.dest_out.w = value[3]; | 210 | record.dest_out.w = value[3]; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | template<> | 213 | template <> |
| 214 | inline void SetField<DebugDataRecord::ADDR_REG_OUT>(DebugDataRecord& record, s32* value) { | 214 | inline void SetField<DebugDataRecord::ADDR_REG_OUT>(DebugDataRecord& record, s32* value) { |
| 215 | record.address_registers[0] = value[0]; | 215 | record.address_registers[0] = value[0]; |
| 216 | record.address_registers[1] = value[1]; | 216 | record.address_registers[1] = value[1]; |
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | template<> | 219 | template <> |
| 220 | inline void SetField<DebugDataRecord::CMP_RESULT>(DebugDataRecord& record, bool* value) { | 220 | inline void SetField<DebugDataRecord::CMP_RESULT>(DebugDataRecord& record, bool* value) { |
| 221 | record.conditional_code[0] = value[0]; | 221 | record.conditional_code[0] = value[0]; |
| 222 | record.conditional_code[1] = value[1]; | 222 | record.conditional_code[1] = value[1]; |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | template<> | 225 | template <> |
| 226 | inline void SetField<DebugDataRecord::COND_BOOL_IN>(DebugDataRecord& record, bool value) { | 226 | inline void SetField<DebugDataRecord::COND_BOOL_IN>(DebugDataRecord& record, bool value) { |
| 227 | record.cond_bool = value; | 227 | record.cond_bool = value; |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | template<> | 230 | template <> |
| 231 | inline void SetField<DebugDataRecord::COND_CMP_IN>(DebugDataRecord& record, bool* value) { | 231 | inline void SetField<DebugDataRecord::COND_CMP_IN>(DebugDataRecord& record, bool* value) { |
| 232 | record.cond_cmp[0] = value[0]; | 232 | record.cond_cmp[0] = value[0]; |
| 233 | record.cond_cmp[1] = value[1]; | 233 | record.cond_cmp[1] = value[1]; |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | template<> | 236 | template <> |
| 237 | inline void SetField<DebugDataRecord::LOOP_INT_IN>(DebugDataRecord& record, Math::Vec4<u8> value) { | 237 | inline void SetField<DebugDataRecord::LOOP_INT_IN>(DebugDataRecord& record, Math::Vec4<u8> value) { |
| 238 | record.loop_int = value; | 238 | record.loop_int = value; |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | template<> | 241 | template <> |
| 242 | inline void SetField<DebugDataRecord::CUR_INSTR>(DebugDataRecord& record, u32 value) { | 242 | inline void SetField<DebugDataRecord::CUR_INSTR>(DebugDataRecord& record, u32 value) { |
| 243 | record.instruction_offset = value; | 243 | record.instruction_offset = value; |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | template<> | 246 | template <> |
| 247 | inline void SetField<DebugDataRecord::NEXT_INSTR>(DebugDataRecord& record, u32 value) { | 247 | inline void SetField<DebugDataRecord::NEXT_INSTR>(DebugDataRecord& record, u32 value) { |
| 248 | record.next_instruction = value; | 248 | record.next_instruction = value; |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | // Helper function to set debug information on the current shader iteration. | 251 | // Helper function to set debug information on the current shader iteration. |
| 252 | template<DebugDataRecord::Type type, typename ValueType> | 252 | template <DebugDataRecord::Type type, typename ValueType> |
| 253 | inline void Record(DebugData<false>& debug_data, u32 offset, ValueType value) { | 253 | inline void Record(DebugData<false>& debug_data, u32 offset, ValueType value) { |
| 254 | // Debugging disabled => nothing to do | 254 | // Debugging disabled => nothing to do |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | template<DebugDataRecord::Type type, typename ValueType> | 257 | template <DebugDataRecord::Type type, typename ValueType> |
| 258 | inline void Record(DebugData<true>& debug_data, u32 offset, ValueType value) { | 258 | inline void Record(DebugData<true>& debug_data, u32 offset, ValueType value) { |
| 259 | if (offset >= debug_data.records.size()) | 259 | if (offset >= debug_data.records.size()) |
| 260 | debug_data.records.resize(offset + 1); | 260 | debug_data.records.resize(offset + 1); |
| 261 | 261 | ||
| 262 | SetField<type, ValueType>(debug_data.records[offset], value); | 262 | SetField<type, ValueType>(debug_data.records[offset], value); |
| 263 | debug_data.records[offset].mask |= type; | 263 | debug_data.records[offset].mask |= type; |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | |||
| 267 | /** | 266 | /** |
| 268 | * This structure contains the state information that needs to be unique for a shader unit. The 3DS | 267 | * This structure contains the state information that needs to be unique for a shader unit. The 3DS |
| 269 | * has four shader units that process shaders in parallel. At the present, Citra only implements a | 268 | * has four shader units that process shaders in parallel. At the present, Citra only implements a |
| 270 | * single shader unit that processes all shaders serially. Putting the state information in a struct | 269 | * single shader unit that processes all shaders serially. Putting the state information in a struct |
| 271 | * here will make it easier for us to parallelize the shader processing later. | 270 | * here will make it easier for us to parallelize the shader processing later. |
| 272 | */ | 271 | */ |
| 273 | template<bool Debug> | 272 | template <bool Debug> |
| 274 | struct UnitState { | 273 | struct UnitState { |
| 275 | struct Registers { | 274 | struct Registers { |
| 276 | // The registers are accessed by the shader JIT using SSE instructions, and are therefore | 275 | // The registers are accessed by the shader JIT using SSE instructions, and are therefore |
| @@ -293,10 +292,12 @@ struct UnitState { | |||
| 293 | static size_t InputOffset(const SourceRegister& reg) { | 292 | static size_t InputOffset(const SourceRegister& reg) { |
| 294 | switch (reg.GetRegisterType()) { | 293 | switch (reg.GetRegisterType()) { |
| 295 | case RegisterType::Input: | 294 | case RegisterType::Input: |
| 296 | return offsetof(UnitState, registers.input) + reg.GetIndex()*sizeof(Math::Vec4<float24>); | 295 | return offsetof(UnitState, registers.input) + |
| 296 | reg.GetIndex() * sizeof(Math::Vec4<float24>); | ||
| 297 | 297 | ||
| 298 | case RegisterType::Temporary: | 298 | case RegisterType::Temporary: |
| 299 | return offsetof(UnitState, registers.temporary) + reg.GetIndex()*sizeof(Math::Vec4<float24>); | 299 | return offsetof(UnitState, registers.temporary) + |
| 300 | reg.GetIndex() * sizeof(Math::Vec4<float24>); | ||
| 300 | 301 | ||
| 301 | default: | 302 | default: |
| 302 | UNREACHABLE(); | 303 | UNREACHABLE(); |
| @@ -307,10 +308,12 @@ struct UnitState { | |||
| 307 | static size_t OutputOffset(const DestRegister& reg) { | 308 | static size_t OutputOffset(const DestRegister& reg) { |
| 308 | switch (reg.GetRegisterType()) { | 309 | switch (reg.GetRegisterType()) { |
| 309 | case RegisterType::Output: | 310 | case RegisterType::Output: |
| 310 | return offsetof(UnitState, output_registers.value) + reg.GetIndex()*sizeof(Math::Vec4<float24>); | 311 | return offsetof(UnitState, output_registers.value) + |
| 312 | reg.GetIndex() * sizeof(Math::Vec4<float24>); | ||
| 311 | 313 | ||
| 312 | case RegisterType::Temporary: | 314 | case RegisterType::Temporary: |
| 313 | return offsetof(UnitState, registers.temporary) + reg.GetIndex()*sizeof(Math::Vec4<float24>); | 315 | return offsetof(UnitState, registers.temporary) + |
| 316 | reg.GetIndex() * sizeof(Math::Vec4<float24>); | ||
| 314 | 317 | ||
| 315 | default: | 318 | default: |
| 316 | UNREACHABLE(); | 319 | UNREACHABLE(); |
| @@ -336,13 +339,13 @@ struct ShaderSetup { | |||
| 336 | static size_t UniformOffset(RegisterType type, unsigned index) { | 339 | static size_t UniformOffset(RegisterType type, unsigned index) { |
| 337 | switch (type) { | 340 | switch (type) { |
| 338 | case RegisterType::FloatUniform: | 341 | case RegisterType::FloatUniform: |
| 339 | return offsetof(ShaderSetup, uniforms.f) + index*sizeof(Math::Vec4<float24>); | 342 | return offsetof(ShaderSetup, uniforms.f) + index * sizeof(Math::Vec4<float24>); |
| 340 | 343 | ||
| 341 | case RegisterType::BoolUniform: | 344 | case RegisterType::BoolUniform: |
| 342 | return offsetof(ShaderSetup, uniforms.b) + index*sizeof(bool); | 345 | return offsetof(ShaderSetup, uniforms.b) + index * sizeof(bool); |
| 343 | 346 | ||
| 344 | case RegisterType::IntUniform: | 347 | case RegisterType::IntUniform: |
| 345 | return offsetof(ShaderSetup, uniforms.i) + index*sizeof(Math::Vec4<u8>); | 348 | return offsetof(ShaderSetup, uniforms.i) + index * sizeof(Math::Vec4<u8>); |
| 346 | 349 | ||
| 347 | default: | 350 | default: |
| 348 | UNREACHABLE(); | 351 | UNREACHABLE(); |
| @@ -354,7 +357,8 @@ struct ShaderSetup { | |||
| 354 | std::array<u32, 1024> swizzle_data; | 357 | std::array<u32, 1024> swizzle_data; |
| 355 | 358 | ||
| 356 | /** | 359 | /** |
| 357 | * Performs any shader unit setup that only needs to happen once per shader (as opposed to once per | 360 | * Performs any shader unit setup that only needs to happen once per shader (as opposed to once |
| 361 | * per | ||
| 358 | * vertex, which would happen within the `Run` function). | 362 | * vertex, which would happen within the `Run` function). |
| 359 | */ | 363 | */ |
| 360 | void Setup(); | 364 | void Setup(); |
| @@ -375,8 +379,8 @@ struct ShaderSetup { | |||
| 375 | * @param setup Setup object for the shader pipeline | 379 | * @param setup Setup object for the shader pipeline |
| 376 | * @return Debug information for this shader with regards to the given vertex | 380 | * @return Debug information for this shader with regards to the given vertex |
| 377 | */ | 381 | */ |
| 378 | DebugData<true> ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const ShaderSetup& setup); | 382 | DebugData<true> ProduceDebugInfo(const InputVertex& input, int num_attributes, |
| 379 | 383 | const Regs::ShaderConfig& config, const ShaderSetup& setup); | |
| 380 | }; | 384 | }; |
| 381 | 385 | ||
| 382 | } // namespace Shader | 386 | } // namespace Shader |