mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Add immediate mode vertex submission
This commit is contained in:
		
							parent
							
								
									ea0ca17215
								
							
						
					
					
						commit
						6b775034dd
					
				
					 21 changed files with 177 additions and 61 deletions
				
			
		|  | @ -33,6 +33,7 @@ set(HEADERS | |||
|             command_processor.h | ||||
|             gpu_debugger.h | ||||
|             pica.h | ||||
|             pica_state.h | ||||
|             pica_types.h | ||||
|             primitive_assembly.h | ||||
|             rasterizer.h | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| 
 | ||||
| #include "video_core/clipper.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/rasterizer.h" | ||||
| #include "video_core/shader/shader_interpreter.h" | ||||
| 
 | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ | |||
| #include "video_core/clipper.h" | ||||
| #include "video_core/command_processor.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/primitive_assembly.h" | ||||
| #include "video_core/renderer_base.h" | ||||
| #include "video_core/video_core.h" | ||||
|  | @ -73,6 +74,14 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
|             GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); | ||||
|             break; | ||||
| 
 | ||||
|         case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.index, 0x232): | ||||
|             if (regs.vs_default_attributes_setup.index == 15) { | ||||
|                 // Reset immediate primitive state
 | ||||
|                 g_state.immediate.primitive_assembler.Reconfigure(regs.triangle_topology); | ||||
|                 g_state.immediate.attribute_id = 0; | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|         // Load default vertex input attributes
 | ||||
|         case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233): | ||||
|         case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234): | ||||
|  | @ -108,11 +117,48 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
|                           attribute.w.ToFloat32()); | ||||
| 
 | ||||
|                 // TODO: Verify that this actually modifies the register!
 | ||||
|                 setup.index = setup.index + 1; | ||||
|                 if (setup.index < 15) { | ||||
|                     setup.index++; | ||||
|                 } else { | ||||
|                     // Put each attribute into an immediate input buffer.
 | ||||
|                     // When all specified immediate attributes are present, the Vertex Shader is invoked and everything is
 | ||||
|                     // sent to the primitive assembler.
 | ||||
| 
 | ||||
|                     auto& immediate_input = g_state.immediate.input; | ||||
|                     auto& immediate_attribute_id = g_state.immediate.attribute_id; | ||||
|                     const auto& attribute_config = regs.vertex_attributes; | ||||
| 
 | ||||
|                     immediate_input.attr[immediate_attribute_id++] = attribute; | ||||
| 
 | ||||
|                     if (immediate_attribute_id >= attribute_config.GetNumTotalAttributes()) { | ||||
|                         immediate_attribute_id = 0; | ||||
| 
 | ||||
|                         Shader::UnitState<false> shader_unit; | ||||
|                         Shader::Setup(shader_unit); | ||||
| 
 | ||||
|                         // Send to vertex shader
 | ||||
|                         Shader::OutputVertex output = Shader::Run(shader_unit, immediate_input, attribute_config.GetNumTotalAttributes()); | ||||
| 
 | ||||
|                         // Send to renderer
 | ||||
|                         using Pica::Shader::OutputVertex; | ||||
|                         auto AddTriangle = [](const OutputVertex& v0, const OutputVertex& v1, const OutputVertex& v2) { | ||||
|                             VideoCore::g_renderer->rasterizer->AddTriangle(v0, v1, v2); | ||||
|                         }; | ||||
| 
 | ||||
|                         g_state.immediate.primitive_assembler.SubmitVertex(output, AddTriangle); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case PICA_REG_INDEX(gpu_mode): | ||||
|             if (regs.gpu_mode == Regs::GPUMode::Configuring && regs.vs_default_attributes_setup.index == 15) { | ||||
|                 // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring
 | ||||
|                 VideoCore::g_renderer->rasterizer->DrawTriangles(); | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|         case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): | ||||
|         case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): | ||||
|         { | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ | |||
| #include "core/settings.h" | ||||
| 
 | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/renderer_base.h" | ||||
| #include "video_core/utils.h" | ||||
| #include "video_core/video_core.h" | ||||
|  | @ -113,7 +114,7 @@ void GeometryDumper::Dump() { | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, const State::ShaderSetup& setup, const Regs::VSOutputAttributes* output_attributes) | ||||
| void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, const Shader::ShaderSetup& setup, const Regs::VSOutputAttributes* output_attributes) | ||||
| { | ||||
|     struct StuffToWrite { | ||||
|         u8* pointer; | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ | |||
| #include "core/tracer/recorder.h" | ||||
| 
 | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
|  | @ -182,7 +183,7 @@ private: | |||
| }; | ||||
| 
 | ||||
| void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, | ||||
|                 const State::ShaderSetup& setup, const Regs::VSOutputAttributes* output_attributes); | ||||
|                 const Shader::ShaderSetup& setup, const Regs::VSOutputAttributes* output_attributes); | ||||
| 
 | ||||
| 
 | ||||
| // Utility class to log Pica commands.
 | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| #include <unordered_map> | ||||
| 
 | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
|  |  | |||
|  | @ -1089,7 +1089,16 @@ struct Regs { | |||
|         } | ||||
|     } command_buffer; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x20); | ||||
|     INSERT_PADDING_WORDS(0x07); | ||||
| 
 | ||||
|     enum class GPUMode : u32 { | ||||
|         Drawing = 0, | ||||
|         Configuring = 1 | ||||
|     }; | ||||
| 
 | ||||
|     GPUMode gpu_mode; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x18); | ||||
| 
 | ||||
|     enum class TriangleTopology : u32 { | ||||
|         List   = 0, | ||||
|  | @ -1278,6 +1287,7 @@ ASSERT_REG_POSITION(trigger_draw, 0x22e); | |||
| ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f); | ||||
| ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); | ||||
| ASSERT_REG_POSITION(command_buffer, 0x238); | ||||
| ASSERT_REG_POSITION(gpu_mode, 0x245); | ||||
| ASSERT_REG_POSITION(triangle_topology, 0x25e); | ||||
| ASSERT_REG_POSITION(restart_primitive, 0x25f); | ||||
| ASSERT_REG_POSITION(gs, 0x280); | ||||
|  | @ -1292,64 +1302,10 @@ static_assert(sizeof(Regs::ShaderConfig) == 0x30 * sizeof(u32), "ShaderConfig st | |||
| static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), "Register set structure larger than it should be"); | ||||
| static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), "Register set structure smaller than it should be"); | ||||
| 
 | ||||
| /// Struct used to describe current Pica state
 | ||||
| struct State { | ||||
|     /// Pica registers
 | ||||
|     Regs regs; | ||||
| 
 | ||||
|     /// Vertex shader memory
 | ||||
|     struct ShaderSetup { | ||||
|         struct { | ||||
|             // The float uniforms are accessed by the shader JIT using SSE instructions, and are
 | ||||
|             // therefore required to be 16-byte aligned.
 | ||||
|             Math::Vec4<float24> MEMORY_ALIGNED16(f[96]); | ||||
| 
 | ||||
|             std::array<bool, 16> b; | ||||
|             std::array<Math::Vec4<u8>, 4> i; | ||||
|         } uniforms; | ||||
| 
 | ||||
|         Math::Vec4<float24> default_attributes[16]; | ||||
| 
 | ||||
|         std::array<u32, 1024> program_code; | ||||
|         std::array<u32, 1024> swizzle_data; | ||||
|     }; | ||||
| 
 | ||||
|     ShaderSetup vs; | ||||
|     ShaderSetup gs; | ||||
| 
 | ||||
|     struct { | ||||
|         union LutEntry { | ||||
|             // Used for raw access
 | ||||
|             u32 raw; | ||||
| 
 | ||||
|             // LUT value, encoded as 12-bit fixed point, with 12 fraction bits
 | ||||
|             BitField< 0, 12, u32> value; | ||||
| 
 | ||||
|             // Used by HW for efficient interpolation, Citra does not use these
 | ||||
|             BitField<12, 12, u32> difference; | ||||
| 
 | ||||
|             float ToFloat() { | ||||
|                 return static_cast<float>(value) / 4095.f; | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         std::array<std::array<LutEntry, 256>, 24> luts; | ||||
|     } lighting; | ||||
| 
 | ||||
|     /// Current Pica command list
 | ||||
|     struct { | ||||
|         const u32* head_ptr; | ||||
|         const u32* current_ptr; | ||||
|         u32 length; | ||||
|     } cmd_list; | ||||
| }; | ||||
| 
 | ||||
| /// Initialize Pica state
 | ||||
| void Init(); | ||||
| 
 | ||||
| /// Shutdown Pica state
 | ||||
| void Shutdown(); | ||||
| 
 | ||||
| extern State g_state; ///< Current Pica state
 | ||||
| 
 | ||||
| } // namespace
 | ||||
|  |  | |||
							
								
								
									
										60
									
								
								src/video_core/pica_state.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/video_core/pica_state.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| // Copyright 2016 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/primitive_assembly.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| /// Struct used to describe current Pica state
 | ||||
| struct State { | ||||
|     /// Pica registers
 | ||||
|     Regs regs; | ||||
| 
 | ||||
|     Shader::ShaderSetup vs; | ||||
|     Shader::ShaderSetup gs; | ||||
| 
 | ||||
|     struct { | ||||
|         union LutEntry { | ||||
|             // Used for raw access
 | ||||
|             u32 raw; | ||||
| 
 | ||||
|             // LUT value, encoded as 12-bit fixed point, with 12 fraction bits
 | ||||
|             BitField< 0, 12, u32> value; | ||||
| 
 | ||||
|             // Used by HW for efficient interpolation, Citra does not use these
 | ||||
|             BitField<12, 12, u32> difference; | ||||
| 
 | ||||
|             float ToFloat() { | ||||
|                 return static_cast<float>(value) / 4095.f; | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         std::array<std::array<LutEntry, 256>, 24> luts; | ||||
|     } lighting; | ||||
| 
 | ||||
|     /// Current Pica command list
 | ||||
|     struct { | ||||
|         const u32* head_ptr; | ||||
|         const u32* current_ptr; | ||||
|         u32 length; | ||||
|     } cmd_list; | ||||
| 
 | ||||
|     /// Struct used to describe immediate mode rendering state
 | ||||
|     struct ImmediateModeState { | ||||
|         Shader::InputVertex input; | ||||
|         // This is constructed with a dummy triangle topology
 | ||||
|         PrimitiveAssembler<Shader::OutputVertex> primitive_assembler; | ||||
|         int attribute_id = 0; | ||||
| 
 | ||||
|         ImmediateModeState() : primitive_assembler(Regs::TriangleTopology::List) {} | ||||
|     } immediate; | ||||
| }; | ||||
| 
 | ||||
| extern State g_state; ///< Current Pica state
 | ||||
| 
 | ||||
| } // namespace
 | ||||
|  | @ -53,6 +53,18 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(VertexType& vtx, TriangleHandl | |||
|     } | ||||
| } | ||||
| 
 | ||||
| template<typename VertexType> | ||||
| void PrimitiveAssembler<VertexType>::Reset() { | ||||
|     buffer_index = 0; | ||||
|     strip_ready = false; | ||||
| } | ||||
| 
 | ||||
| template<typename VertexType> | ||||
| void PrimitiveAssembler<VertexType>::Reconfigure(Regs::TriangleTopology topology) { | ||||
|     Reset(); | ||||
|     this->topology = topology; | ||||
| } | ||||
| 
 | ||||
| // explicitly instantiate use cases
 | ||||
| template | ||||
| struct PrimitiveAssembler<Shader::OutputVertex>; | ||||
|  |  | |||
|  | @ -30,6 +30,16 @@ struct PrimitiveAssembler { | |||
|      */ | ||||
|     void SubmitVertex(VertexType& vtx, TriangleHandler triangle_handler); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Resets the internal state of the PrimitiveAssembler. | ||||
|      */ | ||||
|     void Reset(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Reconfigures the PrimitiveAssembler to use a different triangle topology. | ||||
|      */ | ||||
|     void Reconfigure(Regs::TriangleTopology topology); | ||||
| 
 | ||||
| private: | ||||
|     Regs::TriangleTopology topology; | ||||
| 
 | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ | |||
| #include "core/hw/gpu.h" | ||||
| 
 | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/rasterizer.h" | ||||
| #include "video_core/utils.h" | ||||
| #include "video_core/debug_utils/debug_utils.h" | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ | |||
| #include "core/hw/gpu.h" | ||||
| 
 | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/utils.h" | ||||
| #include "video_core/renderer_opengl/gl_rasterizer.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_gen.h" | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ | |||
| #include "common/hash.h" | ||||
| 
 | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/rasterizer_interface.h" | ||||
| #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_state.h" | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ | |||
| 
 | ||||
| #include "video_core/debug_utils/debug_utils.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
| #include "shader.h" | ||||
|  | @ -145,7 +146,7 @@ OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attr | |||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| DebugData<true> ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const State::ShaderSetup& setup) { | ||||
| DebugData<true> ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const ShaderSetup& setup) { | ||||
|     UnitState<true> state; | ||||
| 
 | ||||
|     state.program_counter = config.main_offset; | ||||
|  |  | |||
|  | @ -77,6 +77,22 @@ struct OutputVertex { | |||
| static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); | ||||
| static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size"); | ||||
| 
 | ||||
| /// Vertex shader memory
 | ||||
| struct ShaderSetup { | ||||
|     struct { | ||||
|         // The float uniforms are accessed by the shader JIT using SSE instructions, and are
 | ||||
|         // therefore required to be 16-byte aligned.
 | ||||
|         Math::Vec4<float24> MEMORY_ALIGNED16(f[96]); | ||||
| 
 | ||||
|         std::array<bool, 16> b; | ||||
|         std::array<Math::Vec4<u8>, 4> i; | ||||
|     } uniforms; | ||||
| 
 | ||||
|     Math::Vec4<float24> default_attributes[16]; | ||||
| 
 | ||||
|     std::array<u32, 1024> program_code; | ||||
|     std::array<u32, 1024> swizzle_data; | ||||
| }; | ||||
| 
 | ||||
| // Helper structure used to keep track of data useful for inspection of shader emulation
 | ||||
| template<bool full_debugging> | ||||
|  | @ -347,7 +363,7 @@ OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attr | |||
|  * @param setup Setup object for the shader pipeline | ||||
|  * @return Debug information for this shader with regards to the given vertex | ||||
|  */ | ||||
| DebugData<true> ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const State::ShaderSetup& setup); | ||||
| DebugData<true> ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const ShaderSetup& setup); | ||||
| 
 | ||||
| } // namespace Shader
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include <nihstro/shader_bytecode.h> | ||||
| 
 | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| #include "video_core/shader/shader_interpreter.h" | ||||
| 
 | ||||
|  |  | |||
|  | @ -11,6 +11,8 @@ | |||
| #include "shader.h" | ||||
| #include "shader_jit_x64.h" | ||||
| 
 | ||||
| #include "video_core/pica_state.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| namespace Shader { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue