mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	opengl: remove hw geometry shader related stuff
This commit is contained in:
		
							parent
							
								
									1cf75e55c2
								
							
						
					
					
						commit
						dd3ba7bd21
					
				
					 8 changed files with 32 additions and 283 deletions
				
			
		|  | @ -104,8 +104,6 @@ RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& window) | ||||||
|     glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); |     glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); | ||||||
|     uniform_size_aligned_vs = |     uniform_size_aligned_vs = | ||||||
|         Common::AlignUp<std::size_t>(sizeof(VSUniformData), uniform_buffer_alignment); |         Common::AlignUp<std::size_t>(sizeof(VSUniformData), uniform_buffer_alignment); | ||||||
|     uniform_size_aligned_gs = |  | ||||||
|         Common::AlignUp<std::size_t>(sizeof(GSUniformData), uniform_buffer_alignment); |  | ||||||
|     uniform_size_aligned_fs = |     uniform_size_aligned_fs = | ||||||
|         Common::AlignUp<std::size_t>(sizeof(UniformData), uniform_buffer_alignment); |         Common::AlignUp<std::size_t>(sizeof(UniformData), uniform_buffer_alignment); | ||||||
| 
 | 
 | ||||||
|  | @ -392,8 +390,7 @@ bool RasterizerOpenGL::SetupGeometryShader() { | ||||||
|         shader_program_manager->UseFixedGeometryShader(gs_config); |         shader_program_manager->UseFixedGeometryShader(gs_config); | ||||||
|         return true; |         return true; | ||||||
|     } else { |     } else { | ||||||
|         PicaGSConfig gs_config(regs, Pica::g_state.gs); |         LOG_ERROR(Render_OpenGL, "Accelerate draw doesn't support geometry shader"); | ||||||
|         return shader_program_manager->UseProgrammableGeometryShader(gs_config, Pica::g_state.gs); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -417,25 +414,8 @@ bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { | ||||||
|     return Draw(true, is_indexed); |     return Draw(true, is_indexed); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static GLenum GetCurrentPrimitiveMode(bool use_gs) { | static GLenum GetCurrentPrimitiveMode() { | ||||||
|     const auto& regs = Pica::g_state.regs; |     const auto& regs = Pica::g_state.regs; | ||||||
|     if (use_gs) { |  | ||||||
|         switch ((regs.gs.max_input_attribute_index + 1) / |  | ||||||
|                 (regs.pipeline.vs_outmap_total_minus_1_a + 1)) { |  | ||||||
|         case 1: |  | ||||||
|             return GL_POINTS; |  | ||||||
|         case 2: |  | ||||||
|             return GL_LINES; |  | ||||||
|         case 4: |  | ||||||
|             return GL_LINES_ADJACENCY; |  | ||||||
|         case 3: |  | ||||||
|             return GL_TRIANGLES; |  | ||||||
|         case 6: |  | ||||||
|             return GL_TRIANGLES_ADJACENCY; |  | ||||||
|         default: |  | ||||||
|             UNREACHABLE(); |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|     switch (regs.pipeline.triangle_topology) { |     switch (regs.pipeline.triangle_topology) { | ||||||
|     case Pica::PipelineRegs::TriangleTopology::Shader: |     case Pica::PipelineRegs::TriangleTopology::Shader: | ||||||
|     case Pica::PipelineRegs::TriangleTopology::List: |     case Pica::PipelineRegs::TriangleTopology::List: | ||||||
|  | @ -448,11 +428,10 @@ static GLenum GetCurrentPrimitiveMode(bool use_gs) { | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed, bool use_gs) { | bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed) { | ||||||
|     const auto& regs = Pica::g_state.regs; |     const auto& regs = Pica::g_state.regs; | ||||||
|     GLenum primitive_mode = GetCurrentPrimitiveMode(use_gs); |     GLenum primitive_mode = GetCurrentPrimitiveMode(); | ||||||
| 
 | 
 | ||||||
|     auto [vs_input_index_min, vs_input_index_max, vs_input_size] = AnalyzeVertexArray(is_indexed); |     auto [vs_input_index_min, vs_input_index_max, vs_input_size] = AnalyzeVertexArray(is_indexed); | ||||||
| 
 | 
 | ||||||
|  | @ -787,8 +766,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) { | ||||||
|     SyncAndUploadLUTs(); |     SyncAndUploadLUTs(); | ||||||
| 
 | 
 | ||||||
|     // Sync the uniform data
 |     // Sync the uniform data
 | ||||||
|     const bool use_gs = regs.pipeline.use_gs == Pica::PipelineRegs::UseGS::Yes; |     UploadUniforms(accelerate); | ||||||
|     UploadUniforms(accelerate, use_gs); |  | ||||||
| 
 | 
 | ||||||
|     // Viewport can have negative offsets or larger
 |     // Viewport can have negative offsets or larger
 | ||||||
|     // dimensions than our framebuffer sub-rect.
 |     // dimensions than our framebuffer sub-rect.
 | ||||||
|  | @ -804,7 +782,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) { | ||||||
|     // Draw the vertex batch
 |     // Draw the vertex batch
 | ||||||
|     bool succeeded = true; |     bool succeeded = true; | ||||||
|     if (accelerate) { |     if (accelerate) { | ||||||
|         succeeded = AccelerateDrawBatchInternal(is_indexed, use_gs); |         succeeded = AccelerateDrawBatchInternal(is_indexed); | ||||||
|     } else { |     } else { | ||||||
|         state.draw.vertex_array = sw_vao.handle; |         state.draw.vertex_array = sw_vao.handle; | ||||||
|         state.draw.vertex_buffer = vertex_buffer.GetHandle(); |         state.draw.vertex_buffer = vertex_buffer.GetHandle(); | ||||||
|  | @ -2119,21 +2097,19 @@ void RasterizerOpenGL::SyncAndUploadLUTs() { | ||||||
|     texture_buffer.Unmap(bytes_used); |     texture_buffer.Unmap(bytes_used); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RasterizerOpenGL::UploadUniforms(bool accelerate_draw, bool use_gs) { | void RasterizerOpenGL::UploadUniforms(bool accelerate_draw) { | ||||||
|     // glBindBufferRange below also changes the generic buffer binding point, so we sync the state
 |     // glBindBufferRange below also changes the generic buffer binding point, so we sync the state
 | ||||||
|     // first
 |     // first
 | ||||||
|     state.draw.uniform_buffer = uniform_buffer.GetHandle(); |     state.draw.uniform_buffer = uniform_buffer.GetHandle(); | ||||||
|     state.Apply(); |     state.Apply(); | ||||||
| 
 | 
 | ||||||
|     bool sync_vs = accelerate_draw; |     bool sync_vs = accelerate_draw; | ||||||
|     bool sync_gs = accelerate_draw && use_gs; |  | ||||||
|     bool sync_fs = uniform_block_data.dirty; |     bool sync_fs = uniform_block_data.dirty; | ||||||
| 
 | 
 | ||||||
|     if (!sync_vs && !sync_gs && !sync_fs) |     if (!sync_vs && !sync_fs) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     std::size_t uniform_size = |     std::size_t uniform_size = uniform_size_aligned_vs + uniform_size_aligned_fs; | ||||||
|         uniform_size_aligned_vs + uniform_size_aligned_gs + uniform_size_aligned_fs; |  | ||||||
|     std::size_t used_bytes = 0; |     std::size_t used_bytes = 0; | ||||||
|     u8* uniforms; |     u8* uniforms; | ||||||
|     GLintptr offset; |     GLintptr offset; | ||||||
|  | @ -2150,15 +2126,6 @@ void RasterizerOpenGL::UploadUniforms(bool accelerate_draw, bool use_gs) { | ||||||
|         used_bytes += uniform_size_aligned_vs; |         used_bytes += uniform_size_aligned_vs; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (sync_gs) { |  | ||||||
|         GSUniformData gs_uniforms; |  | ||||||
|         gs_uniforms.uniforms.SetFromRegs(Pica::g_state.regs.gs, Pica::g_state.gs); |  | ||||||
|         std::memcpy(uniforms + used_bytes, &gs_uniforms, sizeof(gs_uniforms)); |  | ||||||
|         glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(UniformBindings::GS), |  | ||||||
|                           uniform_buffer.GetHandle(), offset + used_bytes, sizeof(GSUniformData)); |  | ||||||
|         used_bytes += uniform_size_aligned_gs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (sync_fs || invalidate) { |     if (sync_fs || invalidate) { | ||||||
|         std::memcpy(uniforms + used_bytes, &uniform_block_data.data, sizeof(UniformData)); |         std::memcpy(uniforms + used_bytes, &uniform_block_data.data, sizeof(UniformData)); | ||||||
|         glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(UniformBindings::Common), |         glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(UniformBindings::Common), | ||||||
|  |  | ||||||
|  | @ -231,13 +231,13 @@ private: | ||||||
|     void SyncAndUploadLUTs(); |     void SyncAndUploadLUTs(); | ||||||
| 
 | 
 | ||||||
|     /// Upload the uniform blocks to the uniform buffer object
 |     /// Upload the uniform blocks to the uniform buffer object
 | ||||||
|     void UploadUniforms(bool accelerate_draw, bool use_gs); |     void UploadUniforms(bool accelerate_draw); | ||||||
| 
 | 
 | ||||||
|     /// Generic draw function for DrawTriangles and AccelerateDrawBatch
 |     /// Generic draw function for DrawTriangles and AccelerateDrawBatch
 | ||||||
|     bool Draw(bool accelerate, bool is_indexed); |     bool Draw(bool accelerate, bool is_indexed); | ||||||
| 
 | 
 | ||||||
|     /// Internal implementation for AccelerateDrawBatch
 |     /// Internal implementation for AccelerateDrawBatch
 | ||||||
|     bool AccelerateDrawBatchInternal(bool is_indexed, bool use_gs); |     bool AccelerateDrawBatchInternal(bool is_indexed); | ||||||
| 
 | 
 | ||||||
|     struct VertexArrayInfo { |     struct VertexArrayInfo { | ||||||
|         u32 vs_input_index_min; |         u32 vs_input_index_min; | ||||||
|  | @ -304,7 +304,6 @@ private: | ||||||
|     OGLFramebuffer framebuffer; |     OGLFramebuffer framebuffer; | ||||||
|     GLint uniform_buffer_alignment; |     GLint uniform_buffer_alignment; | ||||||
|     std::size_t uniform_size_aligned_vs; |     std::size_t uniform_size_aligned_vs; | ||||||
|     std::size_t uniform_size_aligned_gs; |  | ||||||
|     std::size_t uniform_size_aligned_fs; |     std::size_t uniform_size_aligned_fs; | ||||||
| 
 | 
 | ||||||
|     SamplerInfo texture_cube_sampler; |     SamplerInfo texture_cube_sampler; | ||||||
|  |  | ||||||
|  | @ -249,10 +249,10 @@ public: | ||||||
|     GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, |     GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, | ||||||
|                   const SwizzleData& swizzle_data, u32 main_offset, |                   const SwizzleData& swizzle_data, u32 main_offset, | ||||||
|                   const RegGetter& inputreg_getter, const RegGetter& outputreg_getter, |                   const RegGetter& inputreg_getter, const RegGetter& outputreg_getter, | ||||||
|                   bool sanitize_mul, bool is_gs) |                   bool sanitize_mul) | ||||||
|         : subroutines(subroutines), program_code(program_code), swizzle_data(swizzle_data), |         : subroutines(subroutines), program_code(program_code), swizzle_data(swizzle_data), | ||||||
|           main_offset(main_offset), inputreg_getter(inputreg_getter), |           main_offset(main_offset), inputreg_getter(inputreg_getter), | ||||||
|           outputreg_getter(outputreg_getter), sanitize_mul(sanitize_mul), is_gs(is_gs) { |           outputreg_getter(outputreg_getter), sanitize_mul(sanitize_mul) { | ||||||
| 
 | 
 | ||||||
|         Generate(); |         Generate(); | ||||||
|     } |     } | ||||||
|  | @ -342,13 +342,6 @@ private: | ||||||
| 
 | 
 | ||||||
|     /// Generates code representing a bool uniform
 |     /// Generates code representing a bool uniform
 | ||||||
|     std::string GetUniformBool(u32 index) const { |     std::string GetUniformBool(u32 index) const { | ||||||
|         if (is_gs && index == 15) { |  | ||||||
|             // In PICA geometry shader, b15 is set to true after every geometry shader invocation.
 |  | ||||||
|             // Accessing b15 usually indicates that the program relies on register value
 |  | ||||||
|             // preservation across invocation (and therefore it uses b15 to determine whether to
 |  | ||||||
|             // initialize the registers), which cannot be implemented in GL shaders.
 |  | ||||||
|             throw DecompileFail("b15 access in geometry shader"); |  | ||||||
|         } |  | ||||||
|         return "uniforms.b[" + std::to_string(index) + "]"; |         return "uniforms.b[" + std::to_string(index) + "]"; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -751,22 +744,10 @@ private: | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             case OpCode::Id::EMIT: { |             case OpCode::Id::EMIT: | ||||||
|                 if (is_gs) { |             case OpCode::Id::SETEMIT: | ||||||
|                     shader.AddLine("emit();"); |                 LOG_ERROR(HW_GPU, "Geometry shader operation detected in vertex shader"); | ||||||
|                 } |  | ||||||
|                 break; |                 break; | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             case OpCode::Id::SETEMIT: { |  | ||||||
|                 if (is_gs) { |  | ||||||
|                     ASSERT(instr.setemit.vertex_id < 3); |  | ||||||
|                     shader.AddLine("setemit(" + std::to_string(instr.setemit.vertex_id) + "u, " + |  | ||||||
|                                    ((instr.setemit.prim_emit != 0) ? "true" : "false") + ", " + |  | ||||||
|                                    ((instr.setemit.winding != 0) ? "true" : "false") + ");"); |  | ||||||
|                 } |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             default: { |             default: { | ||||||
|                 LOG_ERROR(HW_GPU, "Unhandled instruction: 0x{:02x} ({}): 0x{:08x}", |                 LOG_ERROR(HW_GPU, "Unhandled instruction: 0x{:02x} ({}): 0x{:08x}", | ||||||
|  | @ -890,7 +871,6 @@ private: | ||||||
|     const RegGetter& inputreg_getter; |     const RegGetter& inputreg_getter; | ||||||
|     const RegGetter& outputreg_getter; |     const RegGetter& outputreg_getter; | ||||||
|     const bool sanitize_mul; |     const bool sanitize_mul; | ||||||
|     const bool is_gs; |  | ||||||
| 
 | 
 | ||||||
|     ShaderWriter shader; |     ShaderWriter shader; | ||||||
| }; | }; | ||||||
|  | @ -911,13 +891,12 @@ bool exec_shader(); | ||||||
| std::optional<std::string> DecompileProgram(const ProgramCode& program_code, | std::optional<std::string> DecompileProgram(const ProgramCode& program_code, | ||||||
|                                             const SwizzleData& swizzle_data, u32 main_offset, |                                             const SwizzleData& swizzle_data, u32 main_offset, | ||||||
|                                             const RegGetter& inputreg_getter, |                                             const RegGetter& inputreg_getter, | ||||||
|                                             const RegGetter& outputreg_getter, bool sanitize_mul, |                                             const RegGetter& outputreg_getter, bool sanitize_mul) { | ||||||
|                                             bool is_gs) { |  | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|         auto subroutines = ControlFlowAnalyzer(program_code, main_offset).MoveSubroutines(); |         auto subroutines = ControlFlowAnalyzer(program_code, main_offset).MoveSubroutines(); | ||||||
|         GLSLGenerator generator(subroutines, program_code, swizzle_data, main_offset, |         GLSLGenerator generator(subroutines, program_code, swizzle_data, main_offset, | ||||||
|                                 inputreg_getter, outputreg_getter, sanitize_mul, is_gs); |                                 inputreg_getter, outputreg_getter, sanitize_mul); | ||||||
|         return generator.MoveShaderCode(); |         return generator.MoveShaderCode(); | ||||||
|     } catch (const DecompileFail& exception) { |     } catch (const DecompileFail& exception) { | ||||||
|         LOG_INFO(HW_GPU, "Shader decompilation failed: {}", exception.what()); |         LOG_INFO(HW_GPU, "Shader decompilation failed: {}", exception.what()); | ||||||
|  |  | ||||||
|  | @ -20,7 +20,6 @@ std::string GetCommonDeclarations(); | ||||||
| std::optional<std::string> DecompileProgram(const ProgramCode& program_code, | std::optional<std::string> DecompileProgram(const ProgramCode& program_code, | ||||||
|                                             const SwizzleData& swizzle_data, u32 main_offset, |                                             const SwizzleData& swizzle_data, u32 main_offset, | ||||||
|                                             const RegGetter& inputreg_getter, |                                             const RegGetter& inputreg_getter, | ||||||
|                                             const RegGetter& outputreg_getter, bool sanitize_mul, |                                             const RegGetter& outputreg_getter, bool sanitize_mul); | ||||||
|                                             bool is_gs); |  | ||||||
| 
 | 
 | ||||||
| } // namespace OpenGL::ShaderDecompiler
 | } // namespace OpenGL::ShaderDecompiler
 | ||||||
|  |  | ||||||
|  | @ -283,22 +283,6 @@ void PicaGSConfigCommonRaw::Init(const Pica::Regs& regs) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PicaGSConfigRaw::Init(const Pica::Regs& regs, Pica::Shader::ShaderSetup& setup) { |  | ||||||
|     PicaShaderConfigCommon::Init(regs.gs, setup); |  | ||||||
|     PicaGSConfigCommonRaw::Init(regs); |  | ||||||
| 
 |  | ||||||
|     num_inputs = regs.gs.max_input_attribute_index + 1; |  | ||||||
|     input_map.fill(16); |  | ||||||
| 
 |  | ||||||
|     for (u32 attr = 0; attr < num_inputs; ++attr) { |  | ||||||
|         input_map[regs.gs.GetRegisterForAttribute(attr)] = attr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     attributes_per_vertex = regs.pipeline.vs_outmap_total_minus_1_a + 1; |  | ||||||
| 
 |  | ||||||
|     gs_output_attributes = num_outputs; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code)
 | /// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code)
 | ||||||
| static bool IsPassThroughTevStage(const TevStageConfig& stage) { | static bool IsPassThroughTevStage(const TevStageConfig& stage) { | ||||||
|     return (stage.color_op == TevStageConfig::Operation::Replace && |     return (stage.color_op == TevStageConfig::Operation::Replace && | ||||||
|  | @ -1675,7 +1659,7 @@ std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& | ||||||
| 
 | 
 | ||||||
|     auto program_source_opt = ShaderDecompiler::DecompileProgram( |     auto program_source_opt = ShaderDecompiler::DecompileProgram( | ||||||
|         setup.program_code, setup.swizzle_data, config.state.main_offset, get_input_reg, |         setup.program_code, setup.swizzle_data, config.state.main_offset, get_input_reg, | ||||||
|         get_output_reg, config.state.sanitize_mul, false); |         get_output_reg, config.state.sanitize_mul); | ||||||
| 
 | 
 | ||||||
|     if (!program_source_opt) |     if (!program_source_opt) | ||||||
|         return {}; |         return {}; | ||||||
|  | @ -1727,11 +1711,6 @@ static std::string GetGSCommonSource(const PicaGSConfigCommonRaw& config, bool s | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     out += R"( |     out += R"( | ||||||
| #define uniforms gs_uniforms |  | ||||||
| layout (std140) uniform gs_config { |  | ||||||
|     pica_uniforms uniforms; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct Vertex { | struct Vertex { | ||||||
| )"; | )"; | ||||||
|     out += "    vec4 attributes[" + std::to_string(config.gs_output_attributes) + "];\n"; |     out += "    vec4 attributes[" + std::to_string(config.gs_output_attributes) + "];\n"; | ||||||
|  | @ -1838,116 +1817,4 @@ void main() { | ||||||
| 
 | 
 | ||||||
|     return out; |     return out; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| std::optional<std::string> GenerateGeometryShader(const Pica::Shader::ShaderSetup& setup, |  | ||||||
|                                                   const PicaGSConfig& config, |  | ||||||
|                                                   bool separable_shader) { |  | ||||||
|     std::string out = ""; |  | ||||||
|     if (separable_shader) { |  | ||||||
|         out += "#extension GL_ARB_separate_shader_objects : enable\n"; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (config.state.num_inputs % config.state.attributes_per_vertex != 0) |  | ||||||
|         return {}; |  | ||||||
| 
 |  | ||||||
|     switch (config.state.num_inputs / config.state.attributes_per_vertex) { |  | ||||||
|     case 1: |  | ||||||
|         out += "layout(points) in;\n"; |  | ||||||
|         break; |  | ||||||
|     case 2: |  | ||||||
|         out += "layout(lines) in;\n"; |  | ||||||
|         break; |  | ||||||
|     case 4: |  | ||||||
|         out += "layout(lines_adjacency) in;\n"; |  | ||||||
|         break; |  | ||||||
|     case 3: |  | ||||||
|         out += "layout(triangles) in;\n"; |  | ||||||
|         break; |  | ||||||
|     case 6: |  | ||||||
|         out += "layout(triangles_adjacency) in;\n"; |  | ||||||
|         break; |  | ||||||
|     default: |  | ||||||
|         return {}; |  | ||||||
|     } |  | ||||||
|     out += "layout(triangle_strip, max_vertices = 30) out;\n\n"; |  | ||||||
| 
 |  | ||||||
|     out += GetGSCommonSource(config.state, separable_shader); |  | ||||||
| 
 |  | ||||||
|     auto get_input_reg = [&](u32 reg) -> std::string { |  | ||||||
|         ASSERT(reg < 16); |  | ||||||
|         u32 attr = config.state.input_map[reg]; |  | ||||||
|         if (attr < config.state.num_inputs) { |  | ||||||
|             return "vs_out_attr" + std::to_string(attr % config.state.attributes_per_vertex) + "[" + |  | ||||||
|                    std::to_string(attr / config.state.attributes_per_vertex) + "]"; |  | ||||||
|         } |  | ||||||
|         return "vec4(0.0, 0.0, 0.0, 1.0)"; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     auto get_output_reg = [&](u32 reg) -> std::string { |  | ||||||
|         ASSERT(reg < 16); |  | ||||||
|         if (config.state.output_map[reg] < config.state.num_outputs) { |  | ||||||
|             return "output_buffer.attributes[" + std::to_string(config.state.output_map[reg]) + "]"; |  | ||||||
|         } |  | ||||||
|         return ""; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     auto program_source_opt = ShaderDecompiler::DecompileProgram( |  | ||||||
|         setup.program_code, setup.swizzle_data, config.state.main_offset, get_input_reg, |  | ||||||
|         get_output_reg, config.state.sanitize_mul, true); |  | ||||||
| 
 |  | ||||||
|     if (!program_source_opt) |  | ||||||
|         return {}; |  | ||||||
| 
 |  | ||||||
|     std::string& program_source = *program_source_opt; |  | ||||||
| 
 |  | ||||||
|     out += R"( |  | ||||||
| Vertex output_buffer; |  | ||||||
| Vertex prim_buffer[3]; |  | ||||||
| uint vertex_id = 0u; |  | ||||||
| bool prim_emit = false; |  | ||||||
| bool winding = false; |  | ||||||
| 
 |  | ||||||
| void setemit(uint vertex_id_, bool prim_emit_, bool winding_); |  | ||||||
| void emit(); |  | ||||||
| 
 |  | ||||||
| void main() { |  | ||||||
| )"; |  | ||||||
|     for (u32 i = 0; i < config.state.num_outputs; ++i) { |  | ||||||
|         out += |  | ||||||
|             "    output_buffer.attributes[" + std::to_string(i) + "] = vec4(0.0, 0.0, 0.0, 1.0);\n"; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // execute shader
 |  | ||||||
|     out += "\n    exec_shader();\n\n"; |  | ||||||
| 
 |  | ||||||
|     out += "}\n\n"; |  | ||||||
| 
 |  | ||||||
|     // Put the definition of setemit and emit after main to avoid spurious warning about
 |  | ||||||
|     // uninitialized output_buffer in some drivers
 |  | ||||||
|     out += R"( |  | ||||||
| void setemit(uint vertex_id_, bool prim_emit_, bool winding_) { |  | ||||||
|     vertex_id = vertex_id_; |  | ||||||
|     prim_emit = prim_emit_; |  | ||||||
|     winding = winding_; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void emit() { |  | ||||||
|     prim_buffer[vertex_id] = output_buffer; |  | ||||||
| 
 |  | ||||||
|     if (prim_emit) { |  | ||||||
|         if (winding) { |  | ||||||
|             EmitPrim(prim_buffer[1], prim_buffer[0], prim_buffer[2]); |  | ||||||
|             winding = false; |  | ||||||
|         } else { |  | ||||||
|             EmitPrim(prim_buffer[0], prim_buffer[1], prim_buffer[2]); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| )"; |  | ||||||
| 
 |  | ||||||
|     out += program_source; |  | ||||||
| 
 |  | ||||||
|     return out; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| } // namespace OpenGL
 | } // namespace OpenGL
 | ||||||
|  |  | ||||||
|  | @ -195,26 +195,6 @@ struct PicaFixedGSConfig : Common::HashableStruct<PicaGSConfigCommonRaw> { | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct PicaGSConfigRaw : PicaShaderConfigCommon, PicaGSConfigCommonRaw { |  | ||||||
|     void Init(const Pica::Regs& regs, Pica::Shader::ShaderSetup& setup); |  | ||||||
| 
 |  | ||||||
|     u32 num_inputs; |  | ||||||
|     u32 attributes_per_vertex; |  | ||||||
| 
 |  | ||||||
|     // input_map[input register index] -> input attribute index
 |  | ||||||
|     std::array<u32, 16> input_map; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * This struct contains information to identify a GL geometry shader generated from PICA geometry |  | ||||||
|  * shader. |  | ||||||
|  */ |  | ||||||
| struct PicaGSConfig : Common::HashableStruct<PicaGSConfigRaw> { |  | ||||||
|     explicit PicaGSConfig(const Pica::Regs& regs, Pica::Shader::ShaderSetup& setups) { |  | ||||||
|         state.Init(regs, setups); |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * Generates the GLSL vertex shader program source code that accepts vertices from software shader |  * Generates the GLSL vertex shader program source code that accepts vertices from software shader | ||||||
|  * and directly passes them to the fragment shader. |  * and directly passes them to the fragment shader. | ||||||
|  | @ -236,15 +216,6 @@ std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& | ||||||
|  */ |  */ | ||||||
| std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, bool separable_shader); | std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, bool separable_shader); | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * Generates the GLSL geometry shader program source code for the given GS program and its |  | ||||||
|  * configuration |  | ||||||
|  * @returns String of the shader source code; boost::none on failure |  | ||||||
|  */ |  | ||||||
| std::optional<std::string> GenerateGeometryShader(const Pica::Shader::ShaderSetup& setup, |  | ||||||
|                                                   const PicaGSConfig& config, |  | ||||||
|                                                   bool separable_shader); |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * Generates the GLSL fragment shader program source code for the current Pica state |  * Generates the GLSL fragment shader program source code for the current Pica state | ||||||
|  * @param config ShaderCacheKey object generated for the current Pica state, used for the shader |  * @param config ShaderCacheKey object generated for the current Pica state, used for the shader | ||||||
|  | @ -277,11 +248,4 @@ struct hash<OpenGL::PicaFixedGSConfig> { | ||||||
|         return k.Hash(); |         return k.Hash(); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| template <> |  | ||||||
| struct hash<OpenGL::PicaGSConfig> { |  | ||||||
|     std::size_t operator()(const OpenGL::PicaGSConfig& k) const { |  | ||||||
|         return k.Hash(); |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| } // namespace std
 | } // namespace std
 | ||||||
|  |  | ||||||
|  | @ -27,7 +27,6 @@ static void SetShaderUniformBlockBindings(GLuint shader) { | ||||||
|     SetShaderUniformBlockBinding(shader, "shader_data", UniformBindings::Common, |     SetShaderUniformBlockBinding(shader, "shader_data", UniformBindings::Common, | ||||||
|                                  sizeof(UniformData)); |                                  sizeof(UniformData)); | ||||||
|     SetShaderUniformBlockBinding(shader, "vs_config", UniformBindings::VS, sizeof(VSUniformData)); |     SetShaderUniformBlockBinding(shader, "vs_config", UniformBindings::VS, sizeof(VSUniformData)); | ||||||
|     SetShaderUniformBlockBinding(shader, "gs_config", UniformBindings::GS, sizeof(GSUniformData)); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void SetShaderSamplerBinding(GLuint shader, const char* name, | static void SetShaderSamplerBinding(GLuint shader, const char* name, | ||||||
|  | @ -205,9 +204,6 @@ private: | ||||||
| using ProgrammableVertexShaders = | using ProgrammableVertexShaders = | ||||||
|     ShaderDoubleCache<PicaVSConfig, &GenerateVertexShader, GL_VERTEX_SHADER>; |     ShaderDoubleCache<PicaVSConfig, &GenerateVertexShader, GL_VERTEX_SHADER>; | ||||||
| 
 | 
 | ||||||
| using ProgrammableGeometryShaders = |  | ||||||
|     ShaderDoubleCache<PicaGSConfig, &GenerateGeometryShader, GL_GEOMETRY_SHADER>; |  | ||||||
| 
 |  | ||||||
| using FixedGeometryShaders = | using FixedGeometryShaders = | ||||||
|     ShaderCache<PicaFixedGSConfig, &GenerateFixedGeometryShader, GL_GEOMETRY_SHADER>; |     ShaderCache<PicaFixedGSConfig, &GenerateFixedGeometryShader, GL_GEOMETRY_SHADER>; | ||||||
| 
 | 
 | ||||||
|  | @ -217,8 +213,8 @@ class ShaderProgramManager::Impl { | ||||||
| public: | public: | ||||||
|     explicit Impl(bool separable, bool is_amd) |     explicit Impl(bool separable, bool is_amd) | ||||||
|         : is_amd(is_amd), separable(separable), programmable_vertex_shaders(separable), |         : is_amd(is_amd), separable(separable), programmable_vertex_shaders(separable), | ||||||
|           trivial_vertex_shader(separable), programmable_geometry_shaders(separable), |           trivial_vertex_shader(separable), fixed_geometry_shaders(separable), | ||||||
|           fixed_geometry_shaders(separable), fragment_shaders(separable) { |           fragment_shaders(separable) { | ||||||
|         if (separable) |         if (separable) | ||||||
|             pipeline.Create(); |             pipeline.Create(); | ||||||
|     } |     } | ||||||
|  | @ -254,7 +250,6 @@ public: | ||||||
|     ProgrammableVertexShaders programmable_vertex_shaders; |     ProgrammableVertexShaders programmable_vertex_shaders; | ||||||
|     TrivialVertexShader trivial_vertex_shader; |     TrivialVertexShader trivial_vertex_shader; | ||||||
| 
 | 
 | ||||||
|     ProgrammableGeometryShaders programmable_geometry_shaders; |  | ||||||
|     FixedGeometryShaders fixed_geometry_shaders; |     FixedGeometryShaders fixed_geometry_shaders; | ||||||
| 
 | 
 | ||||||
|     FragmentShaders fragment_shaders; |     FragmentShaders fragment_shaders; | ||||||
|  | @ -282,15 +277,6 @@ void ShaderProgramManager::UseTrivialVertexShader() { | ||||||
|     impl->current.vs = impl->trivial_vertex_shader.Get(); |     impl->current.vs = impl->trivial_vertex_shader.Get(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool ShaderProgramManager::UseProgrammableGeometryShader(const PicaGSConfig& config, |  | ||||||
|                                                          const Pica::Shader::ShaderSetup setup) { |  | ||||||
|     GLuint handle = impl->programmable_geometry_shaders.Get(config, setup); |  | ||||||
|     if (handle == 0) |  | ||||||
|         return false; |  | ||||||
|     impl->current.gs = handle; |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ShaderProgramManager::UseFixedGeometryShader(const PicaFixedGSConfig& config) { | void ShaderProgramManager::UseFixedGeometryShader(const PicaFixedGSConfig& config) { | ||||||
|     impl->current.gs = impl->fixed_geometry_shaders.Get(config); |     impl->current.gs = impl->fixed_geometry_shaders.Get(config); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -91,15 +91,6 @@ static_assert( | ||||||
| static_assert(sizeof(VSUniformData) < 16384, | static_assert(sizeof(VSUniformData) < 16384, | ||||||
|               "VSUniformData structure must be less than 16kb as per the OpenGL spec"); |               "VSUniformData structure must be less than 16kb as per the OpenGL spec"); | ||||||
| 
 | 
 | ||||||
| struct GSUniformData { |  | ||||||
|     PicaUniformsData uniforms; |  | ||||||
| }; |  | ||||||
| static_assert( |  | ||||||
|     sizeof(GSUniformData) == 1856, |  | ||||||
|     "The size of the GSUniformData structure has changed, update the structure in the shader"); |  | ||||||
| static_assert(sizeof(GSUniformData) < 16384, |  | ||||||
|               "GSUniformData structure must be less than 16kb as per the OpenGL spec"); |  | ||||||
| 
 |  | ||||||
| /// A class that manage different shader stages and configures them with given config data.
 | /// A class that manage different shader stages and configures them with given config data.
 | ||||||
| class ShaderProgramManager { | class ShaderProgramManager { | ||||||
| public: | public: | ||||||
|  | @ -111,9 +102,6 @@ public: | ||||||
| 
 | 
 | ||||||
|     void UseTrivialVertexShader(); |     void UseTrivialVertexShader(); | ||||||
| 
 | 
 | ||||||
|     bool UseProgrammableGeometryShader(const PicaGSConfig& config, |  | ||||||
|                                        const Pica::Shader::ShaderSetup setup); |  | ||||||
| 
 |  | ||||||
|     void UseFixedGeometryShader(const PicaFixedGSConfig& config); |     void UseFixedGeometryShader(const PicaFixedGSConfig& config); | ||||||
| 
 | 
 | ||||||
|     void UseTrivialGeometryShader(); |     void UseTrivialGeometryShader(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue