mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +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 <nihstro/shader_bytecode.h> | ||||
| 
 | ||||
| #include "debug_utils/debug_utils.h" | ||||
| 
 | ||||
| #include "pica.h" | ||||
| #include "vertex_shader.h" | ||||
| 
 | ||||
| using nihstro::Instruction; | ||||
| using nihstro::RegisterType; | ||||
| using nihstro::SourceRegister; | ||||
| using nihstro::SwizzlePattern; | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| namespace VertexShader { | ||||
|  | @ -70,19 +77,28 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
|         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)); | ||||
| 
 | ||||
|         const float24* src1_ = (instr.common.src1 < 0x10) ? state.input_register_table[instr.common.src1.GetIndex()] | ||||
|                              : (instr.common.src1 < 0x20) ? &state.temporary_registers[instr.common.src1.GetIndex()].x | ||||
|                              : (instr.common.src1 < 0x80) ? &shader_uniforms.f[instr.common.src1.GetIndex()].x | ||||
|                              : nullptr; | ||||
|         const float24* src2_ = (instr.common.src2 < 0x10) ? state.input_register_table[instr.common.src2.GetIndex()] | ||||
|                              : &state.temporary_registers[instr.common.src2.GetIndex()].x; | ||||
|         auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* { | ||||
|             switch (source_reg.GetRegisterType()) { | ||||
|             case RegisterType::Input: | ||||
|                 return state.input_register_table[source_reg.GetIndex()]; | ||||
| 
 | ||||
|             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()] | ||||
|                       : (instr.common.dest < 0x10) ? nullptr | ||||
|                       : (instr.common.dest < 0x20) ? &state.temporary_registers[instr.common.dest.GetIndex()][0] | ||||
|                       : nullptr; | ||||
| 
 | ||||
|         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] = { | ||||
|             src1_[(int)swizzle.GetSelectorSrc1(0)], | ||||
|  | @ -192,7 +208,9 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
|                 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) { | ||||
|                     exit_loop = true; | ||||
|                 } 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)); | ||||
| 
 | ||||
|                 *++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.offset_words]; | ||||
|                 state.program_counter = &shader_memory[instr.flow_control.dest_offset]; | ||||
|                 break; | ||||
| 
 | ||||
|             case Instruction::OpCode::FLS: | ||||
|                 // TODO: Do whatever needs to be done here?
 | ||||
|             case Instruction::OpCode::END: | ||||
|                 // TODO
 | ||||
|                 break; | ||||
| 
 | ||||
|             default: | ||||
|                 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; | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -66,215 +66,6 @@ struct OutputVertex { | |||
| static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); | ||||
| 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 SubmitSwizzleDataChange(u32 addr, u32 value); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue