forked from eden-emu/eden
		
	Pica: Implement command buffer execution registers.
This commit is contained in:
		
							parent
							
								
									4ac6c1a3b5
								
							
						
					
					
						commit
						02c9fe202c
					
				
					 2 changed files with 75 additions and 43 deletions
				
			
		|  | @ -56,7 +56,17 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | ||||||
|         // Trigger IRQ
 |         // Trigger IRQ
 | ||||||
|         case PICA_REG_INDEX(trigger_irq): |         case PICA_REG_INDEX(trigger_irq): | ||||||
|             GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); |             GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); | ||||||
|             return; |             break; | ||||||
|  | 
 | ||||||
|  |         case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): | ||||||
|  |         case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): | ||||||
|  |         { | ||||||
|  |             unsigned index = id - PICA_REG_INDEX(command_buffer.trigger[0]); | ||||||
|  |             u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index)); | ||||||
|  |             g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr; | ||||||
|  |             g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         // It seems like these trigger vertex rendering
 |         // It seems like these trigger vertex rendering
 | ||||||
|         case PICA_REG_INDEX(trigger_draw): |         case PICA_REG_INDEX(trigger_draw): | ||||||
|  | @ -363,38 +373,34 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | ||||||
|         g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id)); |         g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) { |  | ||||||
|     const CommandHeader& header = *(const CommandHeader*)(&first_command_word[1]); |  | ||||||
| 
 |  | ||||||
|     u32* read_pointer = (u32*)first_command_word; |  | ||||||
| 
 |  | ||||||
|     const u32 write_mask = ((header.parameter_mask & 0x1) ? (0xFFu <<  0) : 0u) | |  | ||||||
|                            ((header.parameter_mask & 0x2) ? (0xFFu <<  8) : 0u) | |  | ||||||
|                            ((header.parameter_mask & 0x4) ? (0xFFu << 16) : 0u) | |  | ||||||
|                            ((header.parameter_mask & 0x8) ? (0xFFu << 24) : 0u); |  | ||||||
| 
 |  | ||||||
|     WritePicaReg(header.cmd_id, *read_pointer, write_mask); |  | ||||||
|     read_pointer += 2; |  | ||||||
| 
 |  | ||||||
|     for (unsigned int i = 1; i < 1+header.extra_data_length; ++i) { |  | ||||||
|         u32 cmd = header.cmd_id + ((header.group_commands) ? i : 0); |  | ||||||
|         WritePicaReg(cmd, *read_pointer, write_mask); |  | ||||||
|         ++read_pointer; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // align read pointer to 8 bytes
 |  | ||||||
|     if ((first_command_word - read_pointer) % 2) |  | ||||||
|         ++read_pointer; |  | ||||||
| 
 |  | ||||||
|     return read_pointer - first_command_word; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ProcessCommandList(const u32* list, u32 size) { | void ProcessCommandList(const u32* list, u32 size) { | ||||||
|     u32* read_pointer = (u32*)list; |     g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = list; | ||||||
|     u32 list_length = size / sizeof(u32); |     g_state.cmd_list.length = size / sizeof(u32); | ||||||
| 
 | 
 | ||||||
|     while (read_pointer < list + list_length) { |     while (g_state.cmd_list.current_ptr < g_state.cmd_list.head_ptr + g_state.cmd_list.length) { | ||||||
|         read_pointer += ExecuteCommandBlock(read_pointer); |         // Expand a 4-bit mask to 4-byte mask, e.g. 0b0101 -> 0x00FF00FF
 | ||||||
|  |         static const u32 expand_bits_to_bytes[] = { | ||||||
|  |             0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, | ||||||
|  |             0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, | ||||||
|  |             0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, | ||||||
|  |             0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         // Align read pointer to 8 bytes
 | ||||||
|  |         if ((g_state.cmd_list.head_ptr - g_state.cmd_list.current_ptr) % 2 != 0) | ||||||
|  |             ++g_state.cmd_list.current_ptr; | ||||||
|  | 
 | ||||||
|  |         u32 value = *g_state.cmd_list.current_ptr++; | ||||||
|  |         const CommandHeader header = { *g_state.cmd_list.current_ptr++ }; | ||||||
|  |         const u32 write_mask = expand_bits_to_bytes[header.parameter_mask]; | ||||||
|  |         u32 cmd = header.cmd_id; | ||||||
|  | 
 | ||||||
|  |         WritePicaReg(cmd, value, write_mask); | ||||||
|  | 
 | ||||||
|  |         for (unsigned i = 0; i < header.extra_data_length; ++i) { | ||||||
|  |             u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0); | ||||||
|  |             WritePicaReg(cmd, *g_state.cmd_list.current_ptr++, write_mask); | ||||||
|  |          } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -708,7 +708,33 @@ struct Regs { | ||||||
|         u32 set_value[3]; |         u32 set_value[3]; | ||||||
|     } vs_default_attributes_setup; |     } vs_default_attributes_setup; | ||||||
| 
 | 
 | ||||||
|     INSERT_PADDING_WORDS(0x28); |     INSERT_PADDING_WORDS(0x2); | ||||||
|  | 
 | ||||||
|  |     struct { | ||||||
|  |         // There are two channels that can be used to configure the next command buffer, which
 | ||||||
|  |         // can be then executed by writing to the "trigger" registers. There are two reasons why a
 | ||||||
|  |         // game might use this feature:
 | ||||||
|  |         //  1) With this, an arbitrary number of additional command buffers may be executed in
 | ||||||
|  |         //     sequence without requiring any intervention of the CPU after the initial one is
 | ||||||
|  |         //     kicked off.
 | ||||||
|  |         //  2) Games can configure these registers to provide a command list subroutine mechanism.
 | ||||||
|  | 
 | ||||||
|  |         BitField< 0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
 | ||||||
|  |         BitField< 0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
 | ||||||
|  |         u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
 | ||||||
|  | 
 | ||||||
|  |         unsigned GetSize(unsigned index) const { | ||||||
|  |             ASSERT(index < 2); | ||||||
|  |             return 8 * size[index]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         PAddr GetPhysicalAddress(unsigned index) const { | ||||||
|  |             ASSERT(index < 2); | ||||||
|  |             return (PAddr)(8 * addr[index]); | ||||||
|  |         } | ||||||
|  |     } command_buffer; | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_WORDS(0x20); | ||||||
| 
 | 
 | ||||||
|     enum class TriangleTopology : u32 { |     enum class TriangleTopology : u32 { | ||||||
|         List        = 0, |         List        = 0, | ||||||
|  | @ -861,6 +887,7 @@ struct Regs { | ||||||
|         ADD_FIELD(trigger_draw); |         ADD_FIELD(trigger_draw); | ||||||
|         ADD_FIELD(trigger_draw_indexed); |         ADD_FIELD(trigger_draw_indexed); | ||||||
|         ADD_FIELD(vs_default_attributes_setup); |         ADD_FIELD(vs_default_attributes_setup); | ||||||
|  |         ADD_FIELD(command_buffer); | ||||||
|         ADD_FIELD(triangle_topology); |         ADD_FIELD(triangle_topology); | ||||||
|         ADD_FIELD(vs_bool_uniforms); |         ADD_FIELD(vs_bool_uniforms); | ||||||
|         ADD_FIELD(vs_int_uniforms); |         ADD_FIELD(vs_int_uniforms); | ||||||
|  | @ -938,6 +965,7 @@ ASSERT_REG_POSITION(num_vertices, 0x228); | ||||||
| ASSERT_REG_POSITION(trigger_draw, 0x22e); | ASSERT_REG_POSITION(trigger_draw, 0x22e); | ||||||
| ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f); | ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f); | ||||||
| ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); | ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); | ||||||
|  | ASSERT_REG_POSITION(command_buffer, 0x238); | ||||||
| ASSERT_REG_POSITION(triangle_topology, 0x25e); | ASSERT_REG_POSITION(triangle_topology, 0x25e); | ||||||
| ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0); | ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0); | ||||||
| ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1); | ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1); | ||||||
|  | @ -1053,21 +1081,12 @@ private: | ||||||
|     float value; |     float value; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| union CommandHeader { |  | ||||||
|     CommandHeader(u32 h) : hex(h) {} |  | ||||||
| 
 |  | ||||||
|     u32 hex; |  | ||||||
| 
 |  | ||||||
|     BitField< 0, 16, u32> cmd_id; |  | ||||||
|     BitField<16,  4, u32> parameter_mask; |  | ||||||
|     BitField<20, 11, u32> extra_data_length; |  | ||||||
|     BitField<31,  1, u32> group_commands; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /// Struct used to describe current Pica state
 | /// Struct used to describe current Pica state
 | ||||||
| struct State { | struct State { | ||||||
|  |     /// Pica registers
 | ||||||
|     Regs regs; |     Regs regs; | ||||||
| 
 | 
 | ||||||
|  |     /// Vertex shader memory
 | ||||||
|     struct { |     struct { | ||||||
|         struct { |         struct { | ||||||
|             Math::Vec4<float24> f[96]; |             Math::Vec4<float24> f[96]; | ||||||
|  | @ -1080,6 +1099,13 @@ struct State { | ||||||
|         std::array<u32, 1024> program_code; |         std::array<u32, 1024> program_code; | ||||||
|         std::array<u32, 1024> swizzle_data; |         std::array<u32, 1024> swizzle_data; | ||||||
|     } vs; |     } vs; | ||||||
|  | 
 | ||||||
|  |     /// Current Pica command list
 | ||||||
|  |     struct { | ||||||
|  |         const u32* head_ptr; | ||||||
|  |         const u32* current_ptr; | ||||||
|  |         u32 length; | ||||||
|  |     } cmd_list; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Initialize Pica state
 | /// Initialize Pica state
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bunnei
						bunnei