mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Pica/VertexShader: Remove (now) duplicated shader bytecode definitions in favor of nihstro's ones.
This commit is contained in:
		
							parent
							
								
									056a8f9dfa
								
							
						
					
					
						commit
						8ce1d32460
					
				
					 2 changed files with 30 additions and 222 deletions
				
			
		|  | @ -8,11 +8,18 @@ | ||||||
| 
 | 
 | ||||||
| #include <core/mem_map.h> | #include <core/mem_map.h> | ||||||
| 
 | 
 | ||||||
|  | #include <nihstro/shader_bytecode.h> | ||||||
|  | 
 | ||||||
| #include "debug_utils/debug_utils.h" | #include "debug_utils/debug_utils.h" | ||||||
| 
 | 
 | ||||||
| #include "pica.h" | #include "pica.h" | ||||||
| #include "vertex_shader.h" | #include "vertex_shader.h" | ||||||
| 
 | 
 | ||||||
|  | using nihstro::Instruction; | ||||||
|  | using nihstro::RegisterType; | ||||||
|  | using nihstro::SourceRegister; | ||||||
|  | using nihstro::SwizzlePattern; | ||||||
|  | 
 | ||||||
| namespace Pica { | namespace Pica { | ||||||
| 
 | 
 | ||||||
| namespace VertexShader { | namespace VertexShader { | ||||||
|  | @ -70,19 +77,28 @@ static void ProcessShaderCode(VertexShaderState& state) { | ||||||
|         const Instruction& instr = *(const Instruction*)state.program_counter; |         const Instruction& instr = *(const Instruction*)state.program_counter; | ||||||
|         state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + (state.program_counter - shader_memory)); |         state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + (state.program_counter - shader_memory)); | ||||||
| 
 | 
 | ||||||
|         const float24* src1_ = (instr.common.src1 < 0x10) ? state.input_register_table[instr.common.src1.GetIndex()] |         auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* { | ||||||
|                              : (instr.common.src1 < 0x20) ? &state.temporary_registers[instr.common.src1.GetIndex()].x |             switch (source_reg.GetRegisterType()) { | ||||||
|                              : (instr.common.src1 < 0x80) ? &shader_uniforms.f[instr.common.src1.GetIndex()].x |             case RegisterType::Input: | ||||||
|                              : nullptr; |                 return state.input_register_table[source_reg.GetIndex()]; | ||||||
|         const float24* src2_ = (instr.common.src2 < 0x10) ? state.input_register_table[instr.common.src2.GetIndex()] | 
 | ||||||
|                              : &state.temporary_registers[instr.common.src2.GetIndex()].x; |             case RegisterType::Temporary: | ||||||
|  |                 return &state.temporary_registers[source_reg.GetIndex()].x; | ||||||
|  | 
 | ||||||
|  |             case RegisterType::FloatUniform: | ||||||
|  |                 return &shader_uniforms.f[source_reg.GetIndex()].x; | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         bool is_inverted = 0 != (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::SrcInversed); | ||||||
|  |         const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted)); | ||||||
|  |         const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted)); | ||||||
|         float24* dest = (instr.common.dest < 0x08) ? state.output_register_table[4*instr.common.dest.GetIndex()] |         float24* dest = (instr.common.dest < 0x08) ? state.output_register_table[4*instr.common.dest.GetIndex()] | ||||||
|                       : (instr.common.dest < 0x10) ? nullptr |                       : (instr.common.dest < 0x10) ? nullptr | ||||||
|                       : (instr.common.dest < 0x20) ? &state.temporary_registers[instr.common.dest.GetIndex()][0] |                       : (instr.common.dest < 0x20) ? &state.temporary_registers[instr.common.dest.GetIndex()][0] | ||||||
|                       : nullptr; |                       : nullptr; | ||||||
| 
 | 
 | ||||||
|         const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; |         const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; | ||||||
|         const bool negate_src1 = (swizzle.negate != 0); |         const bool negate_src1 = (swizzle.negate_src1 != 0); | ||||||
| 
 | 
 | ||||||
|         float24 src1[4] = { |         float24 src1[4] = { | ||||||
|             src1_[(int)swizzle.GetSelectorSrc1(0)], |             src1_[(int)swizzle.GetSelectorSrc1(0)], | ||||||
|  | @ -192,7 +208,9 @@ static void ProcessShaderCode(VertexShaderState& state) { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             case Instruction::OpCode::RET: |             // NOP is currently used as a heuristic for leaving from a function.
 | ||||||
|  |             // TODO: This is completely incorrect.
 | ||||||
|  |             case Instruction::OpCode::NOP: | ||||||
|                 if (*state.call_stack_pointer == VertexShaderState::INVALID_ADDRESS) { |                 if (*state.call_stack_pointer == VertexShaderState::INVALID_ADDRESS) { | ||||||
|                     exit_loop = true; |                     exit_loop = true; | ||||||
|                 } else { |                 } else { | ||||||
|  | @ -209,17 +227,16 @@ static void ProcessShaderCode(VertexShaderState& state) { | ||||||
|                 _dbg_assert_(HW_GPU, state.call_stack_pointer - state.call_stack < sizeof(state.call_stack)); |                 _dbg_assert_(HW_GPU, state.call_stack_pointer - state.call_stack < sizeof(state.call_stack)); | ||||||
| 
 | 
 | ||||||
|                 *++state.call_stack_pointer = state.program_counter - shader_memory; |                 *++state.call_stack_pointer = state.program_counter - shader_memory; | ||||||
|                 // TODO: Does this offset refer to the beginning of shader memory?
 |                 state.program_counter = &shader_memory[instr.flow_control.dest_offset]; | ||||||
|                 state.program_counter = &shader_memory[instr.flow_control.offset_words]; |  | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case Instruction::OpCode::FLS: |             case Instruction::OpCode::END: | ||||||
|                 // TODO: Do whatever needs to be done here?
 |                 // TODO
 | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             default: |             default: | ||||||
|                 LOG_ERROR(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x", |                 LOG_ERROR(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x", | ||||||
|                           (int)instr.opcode.Value(), instr.GetOpCodeName().c_str(), instr.hex); |                           (int)instr.opcode.Value(), instr.opcode.GetInfo().name, instr.hex); | ||||||
|                 break; |                 break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -66,215 +66,6 @@ struct OutputVertex { | ||||||
| static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); | static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); | ||||||
| static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size"); | static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size"); | ||||||
| 
 | 
 | ||||||
| union Instruction { |  | ||||||
|     enum class OpCode : u32 { |  | ||||||
|         ADD = 0x0, |  | ||||||
|         DP3 = 0x1, |  | ||||||
|         DP4 = 0x2, |  | ||||||
| 
 |  | ||||||
|         MUL = 0x8, |  | ||||||
| 
 |  | ||||||
|         MAX = 0xC, |  | ||||||
|         MIN = 0xD, |  | ||||||
|         RCP = 0xE, |  | ||||||
|         RSQ = 0xF, |  | ||||||
| 
 |  | ||||||
|         MOV = 0x13, |  | ||||||
| 
 |  | ||||||
|         RET = 0x21, |  | ||||||
|         FLS = 0x22, // Flush
 |  | ||||||
|         CALL = 0x24, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     std::string GetOpCodeName() const { |  | ||||||
|         std::map<OpCode, std::string> map = { |  | ||||||
|             { OpCode::ADD, "ADD" }, |  | ||||||
|             { OpCode::DP3, "DP3" }, |  | ||||||
|             { OpCode::DP4, "DP4" }, |  | ||||||
|             { OpCode::MUL, "MUL" }, |  | ||||||
|             { OpCode::MAX, "MAX" }, |  | ||||||
|             { OpCode::MIN, "MIN" }, |  | ||||||
|             { OpCode::RCP, "RCP" }, |  | ||||||
|             { OpCode::RSQ, "RSQ" }, |  | ||||||
|             { OpCode::MOV, "MOV" }, |  | ||||||
|             { OpCode::RET, "RET" }, |  | ||||||
|             { OpCode::FLS, "FLS" }, |  | ||||||
|         }; |  | ||||||
|         auto it = map.find(opcode); |  | ||||||
|         if (it == map.end()) |  | ||||||
|             return "UNK"; |  | ||||||
|         else |  | ||||||
|             return it->second; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     u32 hex; |  | ||||||
| 
 |  | ||||||
|     BitField<0x1a, 0x6, OpCode> opcode; |  | ||||||
| 
 |  | ||||||
|     // General notes:
 |  | ||||||
|     //
 |  | ||||||
|     // When two input registers are used, one of them uses a 5-bit index while the other
 |  | ||||||
|     // one uses a 7-bit index. This is because at most one floating point uniform may be used
 |  | ||||||
|     // as an input.
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     // Format used e.g. by arithmetic instructions and comparisons
 |  | ||||||
|     // "src1" and "src2" specify register indices (i.e. indices referring to groups of 4 floats),
 |  | ||||||
|     // while "dest" addresses individual floats.
 |  | ||||||
|     union { |  | ||||||
|         BitField<0x00, 0x5, u32> operand_desc_id; |  | ||||||
| 
 |  | ||||||
|         template<class BitFieldType> |  | ||||||
|         struct SourceRegister : BitFieldType { |  | ||||||
|             enum RegisterType { |  | ||||||
|                 Input, |  | ||||||
|                 Temporary, |  | ||||||
|                 FloatUniform |  | ||||||
|             }; |  | ||||||
| 
 |  | ||||||
|             RegisterType GetRegisterType() const { |  | ||||||
|                 if (BitFieldType::Value() < 0x10) |  | ||||||
|                     return Input; |  | ||||||
|                 else if (BitFieldType::Value() < 0x20) |  | ||||||
|                     return Temporary; |  | ||||||
|                 else |  | ||||||
|                     return FloatUniform; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             int GetIndex() const { |  | ||||||
|                 if (GetRegisterType() == Input) |  | ||||||
|                     return BitFieldType::Value(); |  | ||||||
|                 else if (GetRegisterType() == Temporary) |  | ||||||
|                     return BitFieldType::Value() - 0x10; |  | ||||||
|                 else // if (GetRegisterType() == FloatUniform)
 |  | ||||||
|                     return BitFieldType::Value() - 0x20; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             std::string GetRegisterName() const { |  | ||||||
|                 std::map<RegisterType, std::string> type = { |  | ||||||
|                     { Input, "i" }, |  | ||||||
|                     { Temporary, "t" }, |  | ||||||
|                     { FloatUniform, "f" }, |  | ||||||
|                 }; |  | ||||||
|                 return type[GetRegisterType()] + std::to_string(GetIndex()); |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         SourceRegister<BitField<0x07, 0x5, u32>> src2; |  | ||||||
|         SourceRegister<BitField<0x0c, 0x7, u32>> src1; |  | ||||||
| 
 |  | ||||||
|         struct : BitField<0x15, 0x5, u32> |  | ||||||
|         { |  | ||||||
|             enum RegisterType { |  | ||||||
|                 Output, |  | ||||||
|                 Temporary, |  | ||||||
|                 Unknown |  | ||||||
|             }; |  | ||||||
|             RegisterType GetRegisterType() const { |  | ||||||
|                 if (Value() < 0x8) |  | ||||||
|                     return Output; |  | ||||||
|                 else if (Value() < 0x10) |  | ||||||
|                     return Unknown; |  | ||||||
|                 else |  | ||||||
|                     return Temporary; |  | ||||||
|             } |  | ||||||
|             int GetIndex() const { |  | ||||||
|                 if (GetRegisterType() == Output) |  | ||||||
|                     return Value(); |  | ||||||
|                 else if (GetRegisterType() == Temporary) |  | ||||||
|                     return Value() - 0x10; |  | ||||||
|                 else |  | ||||||
|                     return Value(); |  | ||||||
|             } |  | ||||||
|             std::string GetRegisterName() const { |  | ||||||
|                 std::map<RegisterType, std::string> type = { |  | ||||||
|                     { Output, "o" }, |  | ||||||
|                     { Temporary, "t" }, |  | ||||||
|                     { Unknown, "u" } |  | ||||||
|                 }; |  | ||||||
|                 return type[GetRegisterType()] + std::to_string(GetIndex()); |  | ||||||
|             } |  | ||||||
|         } dest; |  | ||||||
|     } common; |  | ||||||
| 
 |  | ||||||
|     // Format used for flow control instructions ("if")
 |  | ||||||
|     union { |  | ||||||
|         BitField<0x00, 0x8, u32> num_instructions; |  | ||||||
|         BitField<0x0a, 0xc, u32> offset_words; |  | ||||||
|     } flow_control; |  | ||||||
| }; |  | ||||||
| static_assert(std::is_standard_layout<Instruction>::value, "Structure is not using standard layout!"); |  | ||||||
| 
 |  | ||||||
| union SwizzlePattern { |  | ||||||
|     u32 hex; |  | ||||||
| 
 |  | ||||||
|     enum class Selector : u32 { |  | ||||||
|         x = 0, |  | ||||||
|         y = 1, |  | ||||||
|         z = 2, |  | ||||||
|         w = 3 |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     Selector GetSelectorSrc1(int comp) const { |  | ||||||
|         Selector selectors[] = { |  | ||||||
|             src1_selector_0, src1_selector_1, src1_selector_2, src1_selector_3 |  | ||||||
|         }; |  | ||||||
|         return selectors[comp]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     Selector GetSelectorSrc2(int comp) const { |  | ||||||
|         Selector selectors[] = { |  | ||||||
|             src2_selector_0, src2_selector_1, src2_selector_2, src2_selector_3 |  | ||||||
|         }; |  | ||||||
|         return selectors[comp]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool DestComponentEnabled(int i) const { |  | ||||||
|         return (dest_mask & (0x8 >> i)) != 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     std::string SelectorToString(bool src2) const { |  | ||||||
|         std::map<Selector, std::string> map = { |  | ||||||
|             { Selector::x, "x" }, |  | ||||||
|             { Selector::y, "y" }, |  | ||||||
|             { Selector::z, "z" }, |  | ||||||
|             { Selector::w, "w" } |  | ||||||
|         }; |  | ||||||
|         std::string ret; |  | ||||||
|         for (int i = 0; i < 4; ++i) { |  | ||||||
|             ret += map.at(src2 ? GetSelectorSrc2(i) : GetSelectorSrc1(i)); |  | ||||||
|         } |  | ||||||
|         return ret; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     std::string DestMaskToString() const { |  | ||||||
|         std::string ret; |  | ||||||
|         for (int i = 0; i < 4; ++i) { |  | ||||||
|             if (!DestComponentEnabled(i)) |  | ||||||
|                 ret += "_"; |  | ||||||
|             else |  | ||||||
|                 ret += "xyzw"[i]; |  | ||||||
|         } |  | ||||||
|         return ret; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Components of "dest" that should be written to: LSB=dest.w, MSB=dest.x
 |  | ||||||
|     BitField< 0, 4, u32> dest_mask; |  | ||||||
| 
 |  | ||||||
|     BitField< 4, 1, u32> negate; // negates src1
 |  | ||||||
| 
 |  | ||||||
|     BitField< 5, 2, Selector> src1_selector_3; |  | ||||||
|     BitField< 7, 2, Selector> src1_selector_2; |  | ||||||
|     BitField< 9, 2, Selector> src1_selector_1; |  | ||||||
|     BitField<11, 2, Selector> src1_selector_0; |  | ||||||
| 
 |  | ||||||
|     BitField<14, 2, Selector> src2_selector_3; |  | ||||||
|     BitField<16, 2, Selector> src2_selector_2; |  | ||||||
|     BitField<18, 2, Selector> src2_selector_1; |  | ||||||
|     BitField<20, 2, Selector> src2_selector_0; |  | ||||||
| 
 |  | ||||||
|     BitField<31, 1, u32> flag; // not sure what this means, maybe it's the sign?
 |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| void SubmitShaderMemoryChange(u32 addr, u32 value); | void SubmitShaderMemoryChange(u32 addr, u32 value); | ||||||
| void SubmitSwizzleDataChange(u32 addr, u32 value); | void SubmitSwizzleDataChange(u32 addr, u32 value); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue