Procházet zdrojové kódy

Merge pull request #3494 from ReinUsesLisp/fix-cs-pipeline

gl_shader_manager: Fix interaction between graphics and compute
bunnei před 6 roky
rodič
revize
fce33adcf1

+ 2 - 3
src/video_core/renderer_opengl/gl_rasterizer.cpp

@@ -565,7 +565,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
     bind_ubo_pushbuffer.Bind();
     bind_ssbo_pushbuffer.Bind();
 
-    program_manager.Update();
+    program_manager.BindGraphicsPipeline();
 
     if (texture_cache.TextureBarrier()) {
         glTextureBarrier();
@@ -627,8 +627,7 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
     const ProgramVariant variant(launch_desc.block_dim_x, launch_desc.block_dim_y,
                                  launch_desc.block_dim_z, launch_desc.shared_alloc,
                                  launch_desc.local_pos_alloc);
-    glUseProgramStages(program_manager.GetHandle(), GL_COMPUTE_SHADER_BIT,
-                       kernel->GetHandle(variant));
+    program_manager.BindComputeShader(kernel->GetHandle(variant));
 
     const std::size_t buffer_size =
         Tegra::Engines::KeplerCompute::NumConstBuffers *

+ 22 - 9
src/video_core/renderer_opengl/gl_shader_manager.cpp

@@ -2,21 +2,29 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <glad/glad.h>
+
 #include "common/common_types.h"
 #include "video_core/engines/maxwell_3d.h"
 #include "video_core/renderer_opengl/gl_shader_manager.h"
 
 namespace OpenGL::GLShader {
 
-using Tegra::Engines::Maxwell3D;
+ProgramManager::ProgramManager() = default;
 
 ProgramManager::~ProgramManager() = default;
 
 void ProgramManager::Create() {
-    pipeline.Create();
+    graphics_pipeline.Create();
+    glBindProgramPipeline(graphics_pipeline.handle);
 }
 
-void ProgramManager::Update() {
+void ProgramManager::BindGraphicsPipeline() {
+    if (!is_graphics_bound) {
+        is_graphics_bound = true;
+        glUseProgram(0);
+    }
+
     // Avoid updating the pipeline when values have no changed
     if (old_state == current_state) {
         return;
@@ -25,16 +33,21 @@ void ProgramManager::Update() {
     // Workaround for AMD bug
     static constexpr GLenum all_used_stages{GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT |
                                             GL_FRAGMENT_SHADER_BIT};
-    glUseProgramStages(pipeline.handle, all_used_stages, 0);
-
-    glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, current_state.vertex_shader);
-    glUseProgramStages(pipeline.handle, GL_GEOMETRY_SHADER_BIT, current_state.geometry_shader);
-    glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, current_state.fragment_shader);
+    const GLuint handle = graphics_pipeline.handle;
+    glUseProgramStages(handle, all_used_stages, 0);
+    glUseProgramStages(handle, GL_VERTEX_SHADER_BIT, current_state.vertex_shader);
+    glUseProgramStages(handle, GL_GEOMETRY_SHADER_BIT, current_state.geometry_shader);
+    glUseProgramStages(handle, GL_FRAGMENT_SHADER_BIT, current_state.fragment_shader);
 
     old_state = current_state;
 }
 
-void MaxwellUniformData::SetFromRegs(const Maxwell3D& maxwell) {
+void ProgramManager::BindComputeShader(GLuint program) {
+    is_graphics_bound = false;
+    glUseProgram(program);
+}
+
+void MaxwellUniformData::SetFromRegs(const Tegra::Engines::Maxwell3D& maxwell) {
     const auto& regs = maxwell.regs;
 
     // Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value.

+ 14 - 15
src/video_core/renderer_opengl/gl_shader_manager.h

@@ -28,11 +28,16 @@ static_assert(sizeof(MaxwellUniformData) < 16384,
 
 class ProgramManager {
 public:
+    explicit ProgramManager();
     ~ProgramManager();
 
     void Create();
 
-    void Update();
+    /// Updates the graphics pipeline and binds it.
+    void BindGraphicsPipeline();
+
+    /// Binds a compute shader.
+    void BindComputeShader(GLuint program);
 
     void UseVertexShader(GLuint program) {
         current_state.vertex_shader = program;
@@ -46,33 +51,27 @@ public:
         current_state.fragment_shader = program;
     }
 
-    GLuint GetHandle() const {
-        return pipeline.handle;
-    }
-
-    void UseTrivialFragmentShader() {
-        current_state.fragment_shader = 0;
-    }
-
 private:
     struct PipelineState {
-        bool operator==(const PipelineState& rhs) const {
+        bool operator==(const PipelineState& rhs) const noexcept {
             return vertex_shader == rhs.vertex_shader && fragment_shader == rhs.fragment_shader &&
                    geometry_shader == rhs.geometry_shader;
         }
 
-        bool operator!=(const PipelineState& rhs) const {
+        bool operator!=(const PipelineState& rhs) const noexcept {
             return !operator==(rhs);
         }
 
-        GLuint vertex_shader{};
-        GLuint fragment_shader{};
-        GLuint geometry_shader{};
+        GLuint vertex_shader = 0;
+        GLuint fragment_shader = 0;
+        GLuint geometry_shader = 0;
     };
 
-    OGLPipeline pipeline;
+    OGLPipeline graphics_pipeline;
+    OGLPipeline compute_pipeline;
     PipelineState current_state;
     PipelineState old_state;
+    bool is_graphics_bound = true;
 };
 
 } // namespace OpenGL::GLShader

+ 1 - 2
src/video_core/renderer_opengl/renderer_opengl.cpp

@@ -443,7 +443,6 @@ void RendererOpenGL::InitOpenGLObjects() {
 
     // Create program pipeline
     program_manager.Create();
-    glBindProgramPipeline(program_manager.GetHandle());
 
     // Generate VBO handle for drawing
     vertex_buffer.Create();
@@ -596,7 +595,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
     program_manager.UseVertexShader(vertex_program.handle);
     program_manager.UseGeometryShader(0);
     program_manager.UseFragmentShader(fragment_program.handle);
-    program_manager.Update();
+    program_manager.BindGraphicsPipeline();
 
     glEnable(GL_CULL_FACE);
     if (screen_info.display_srgb) {