From dd3ba7bd2179217f7a866c64887e32310c20000f Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sun, 18 Aug 2019 20:07:50 -0400 Subject: [PATCH] opengl: remove hw geometry shader related stuff --- .../renderer_opengl/gl_rasterizer.cpp | 71 +++------ .../renderer_opengl/gl_rasterizer.h | 5 +- .../renderer_opengl/gl_shader_decompiler.cpp | 35 +---- .../renderer_opengl/gl_shader_decompiler.h | 3 +- .../renderer_opengl/gl_shader_gen.cpp | 135 +----------------- .../renderer_opengl/gl_shader_gen.h | 36 ----- .../renderer_opengl/gl_shader_manager.cpp | 18 +-- .../renderer_opengl/gl_shader_manager.h | 12 -- 8 files changed, 32 insertions(+), 283 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 70551a3f1..6bfe35efa 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -104,8 +104,6 @@ RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& window) glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); uniform_size_aligned_vs = Common::AlignUp(sizeof(VSUniformData), uniform_buffer_alignment); - uniform_size_aligned_gs = - Common::AlignUp(sizeof(GSUniformData), uniform_buffer_alignment); uniform_size_aligned_fs = Common::AlignUp(sizeof(UniformData), uniform_buffer_alignment); @@ -392,8 +390,7 @@ bool RasterizerOpenGL::SetupGeometryShader() { shader_program_manager->UseFixedGeometryShader(gs_config); return true; } else { - PicaGSConfig gs_config(regs, Pica::g_state.gs); - return shader_program_manager->UseProgrammableGeometryShader(gs_config, Pica::g_state.gs); + LOG_ERROR(Render_OpenGL, "Accelerate draw doesn't support geometry shader"); } } @@ -417,42 +414,24 @@ bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { return Draw(true, is_indexed); } -static GLenum GetCurrentPrimitiveMode(bool use_gs) { +static GLenum GetCurrentPrimitiveMode() { 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) { - case Pica::PipelineRegs::TriangleTopology::Shader: - case Pica::PipelineRegs::TriangleTopology::List: - return GL_TRIANGLES; - case Pica::PipelineRegs::TriangleTopology::Fan: - return GL_TRIANGLE_FAN; - case Pica::PipelineRegs::TriangleTopology::Strip: - return GL_TRIANGLE_STRIP; - default: - UNREACHABLE(); - } + switch (regs.pipeline.triangle_topology) { + case Pica::PipelineRegs::TriangleTopology::Shader: + case Pica::PipelineRegs::TriangleTopology::List: + return GL_TRIANGLES; + case Pica::PipelineRegs::TriangleTopology::Fan: + return GL_TRIANGLE_FAN; + case Pica::PipelineRegs::TriangleTopology::Strip: + return GL_TRIANGLE_STRIP; + default: + UNREACHABLE(); } } -bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed, bool use_gs) { +bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed) { 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); @@ -787,8 +766,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) { SyncAndUploadLUTs(); // Sync the uniform data - const bool use_gs = regs.pipeline.use_gs == Pica::PipelineRegs::UseGS::Yes; - UploadUniforms(accelerate, use_gs); + UploadUniforms(accelerate); // Viewport can have negative offsets or larger // dimensions than our framebuffer sub-rect. @@ -804,7 +782,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) { // Draw the vertex batch bool succeeded = true; if (accelerate) { - succeeded = AccelerateDrawBatchInternal(is_indexed, use_gs); + succeeded = AccelerateDrawBatchInternal(is_indexed); } else { state.draw.vertex_array = sw_vao.handle; state.draw.vertex_buffer = vertex_buffer.GetHandle(); @@ -2119,21 +2097,19 @@ void RasterizerOpenGL::SyncAndUploadLUTs() { 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 // first state.draw.uniform_buffer = uniform_buffer.GetHandle(); state.Apply(); bool sync_vs = accelerate_draw; - bool sync_gs = accelerate_draw && use_gs; bool sync_fs = uniform_block_data.dirty; - if (!sync_vs && !sync_gs && !sync_fs) + if (!sync_vs && !sync_fs) return; - std::size_t uniform_size = - uniform_size_aligned_vs + uniform_size_aligned_gs + uniform_size_aligned_fs; + std::size_t uniform_size = uniform_size_aligned_vs + uniform_size_aligned_fs; std::size_t used_bytes = 0; u8* uniforms; GLintptr offset; @@ -2150,15 +2126,6 @@ void RasterizerOpenGL::UploadUniforms(bool accelerate_draw, bool use_gs) { 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(UniformBindings::GS), - uniform_buffer.GetHandle(), offset + used_bytes, sizeof(GSUniformData)); - used_bytes += uniform_size_aligned_gs; - } - if (sync_fs || invalidate) { std::memcpy(uniforms + used_bytes, &uniform_block_data.data, sizeof(UniformData)); glBindBufferRange(GL_UNIFORM_BUFFER, static_cast(UniformBindings::Common), diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 8c1e57f55..6ba23762d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -231,13 +231,13 @@ private: void SyncAndUploadLUTs(); /// 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 bool Draw(bool accelerate, bool is_indexed); /// Internal implementation for AccelerateDrawBatch - bool AccelerateDrawBatchInternal(bool is_indexed, bool use_gs); + bool AccelerateDrawBatchInternal(bool is_indexed); struct VertexArrayInfo { u32 vs_input_index_min; @@ -304,7 +304,6 @@ private: OGLFramebuffer framebuffer; GLint uniform_buffer_alignment; std::size_t uniform_size_aligned_vs; - std::size_t uniform_size_aligned_gs; std::size_t uniform_size_aligned_fs; SamplerInfo texture_cube_sampler; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index c464f3a7a..19ac13ce2 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -249,10 +249,10 @@ public: GLSLGenerator(const std::set& subroutines, const ProgramCode& program_code, const SwizzleData& swizzle_data, u32 main_offset, 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), 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(); } @@ -342,13 +342,6 @@ private: /// Generates code representing a bool uniform 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) + "]"; } @@ -751,22 +744,10 @@ private: break; } - case OpCode::Id::EMIT: { - if (is_gs) { - shader.AddLine("emit();"); - } + case OpCode::Id::EMIT: + case OpCode::Id::SETEMIT: + LOG_ERROR(HW_GPU, "Geometry shader operation detected in vertex shader"); 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: { LOG_ERROR(HW_GPU, "Unhandled instruction: 0x{:02x} ({}): 0x{:08x}", @@ -890,7 +871,6 @@ private: const RegGetter& inputreg_getter; const RegGetter& outputreg_getter; const bool sanitize_mul; - const bool is_gs; ShaderWriter shader; }; @@ -911,13 +891,12 @@ bool exec_shader(); std::optional DecompileProgram(const ProgramCode& program_code, const SwizzleData& swizzle_data, u32 main_offset, const RegGetter& inputreg_getter, - const RegGetter& outputreg_getter, bool sanitize_mul, - bool is_gs) { + const RegGetter& outputreg_getter, bool sanitize_mul) { try { auto subroutines = ControlFlowAnalyzer(program_code, main_offset).MoveSubroutines(); 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(); } catch (const DecompileFail& exception) { LOG_INFO(HW_GPU, "Shader decompilation failed: {}", exception.what()); diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h index 2ec8fddd1..51befb91d 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.h +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h @@ -20,7 +20,6 @@ std::string GetCommonDeclarations(); std::optional DecompileProgram(const ProgramCode& program_code, const SwizzleData& swizzle_data, u32 main_offset, const RegGetter& inputreg_getter, - const RegGetter& outputreg_getter, bool sanitize_mul, - bool is_gs); + const RegGetter& outputreg_getter, bool sanitize_mul); } // namespace OpenGL::ShaderDecompiler diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 1e9e856ce..75ddc289b 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -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) static bool IsPassThroughTevStage(const TevStageConfig& stage) { return (stage.color_op == TevStageConfig::Operation::Replace && @@ -1675,7 +1659,7 @@ std::optional GenerateVertexShader(const Pica::Shader::ShaderSetup& 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, false); + get_output_reg, config.state.sanitize_mul); if (!program_source_opt) return {}; @@ -1727,11 +1711,6 @@ static std::string GetGSCommonSource(const PicaGSConfigCommonRaw& config, bool s } out += R"( -#define uniforms gs_uniforms -layout (std140) uniform gs_config { - pica_uniforms uniforms; -}; - struct Vertex { )"; out += " vec4 attributes[" + std::to_string(config.gs_output_attributes) + "];\n"; @@ -1838,116 +1817,4 @@ void main() { return out; } - -std::optional 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 diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index cd1264bdb..8875c62b4 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -195,26 +195,6 @@ struct PicaFixedGSConfig : Common::HashableStruct { } }; -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 input_map; -}; - -/** - * This struct contains information to identify a GL geometry shader generated from PICA geometry - * shader. - */ -struct PicaGSConfig : Common::HashableStruct { - 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 * and directly passes them to the fragment shader. @@ -236,15 +216,6 @@ std::optional GenerateVertexShader(const Pica::Shader::ShaderSetup& */ 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 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 * @param config ShaderCacheKey object generated for the current Pica state, used for the shader @@ -277,11 +248,4 @@ struct hash { return k.Hash(); } }; - -template <> -struct hash { - std::size_t operator()(const OpenGL::PicaGSConfig& k) const { - return k.Hash(); - } -}; } // namespace std diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index a5c62a0e1..c0172c900 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -27,7 +27,6 @@ static void SetShaderUniformBlockBindings(GLuint shader) { SetShaderUniformBlockBinding(shader, "shader_data", UniformBindings::Common, sizeof(UniformData)); SetShaderUniformBlockBinding(shader, "vs_config", UniformBindings::VS, sizeof(VSUniformData)); - SetShaderUniformBlockBinding(shader, "gs_config", UniformBindings::GS, sizeof(GSUniformData)); } static void SetShaderSamplerBinding(GLuint shader, const char* name, @@ -205,9 +204,6 @@ private: using ProgrammableVertexShaders = ShaderDoubleCache; -using ProgrammableGeometryShaders = - ShaderDoubleCache; - using FixedGeometryShaders = ShaderCache; @@ -217,8 +213,8 @@ class ShaderProgramManager::Impl { public: explicit Impl(bool separable, bool is_amd) : is_amd(is_amd), separable(separable), programmable_vertex_shaders(separable), - trivial_vertex_shader(separable), programmable_geometry_shaders(separable), - fixed_geometry_shaders(separable), fragment_shaders(separable) { + trivial_vertex_shader(separable), fixed_geometry_shaders(separable), + fragment_shaders(separable) { if (separable) pipeline.Create(); } @@ -254,7 +250,6 @@ public: ProgrammableVertexShaders programmable_vertex_shaders; TrivialVertexShader trivial_vertex_shader; - ProgrammableGeometryShaders programmable_geometry_shaders; FixedGeometryShaders fixed_geometry_shaders; FragmentShaders fragment_shaders; @@ -282,15 +277,6 @@ void ShaderProgramManager::UseTrivialVertexShader() { 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) { impl->current.gs = impl->fixed_geometry_shaders.Get(config); } diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index e160bd0e7..a31fbc4e6 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -91,15 +91,6 @@ static_assert( static_assert(sizeof(VSUniformData) < 16384, "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. class ShaderProgramManager { public: @@ -111,9 +102,6 @@ public: void UseTrivialVertexShader(); - bool UseProgrammableGeometryShader(const PicaGSConfig& config, - const Pica::Shader::ShaderSetup setup); - void UseFixedGeometryShader(const PicaFixedGSConfig& config); void UseTrivialGeometryShader();