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

gl_shader_manager: Fix interaction between graphics and compute
This commit is contained in:
bunnei 2020-03-11 13:51:54 -04:00 committed by GitHub
commit fce33adcf1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 29 deletions

View file

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

View file

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

View file

@ -28,11 +28,16 @@ static_assert(sizeof(MaxwellUniformData) < 16384,
class ProgramManager { class ProgramManager {
public: public:
explicit ProgramManager();
~ProgramManager(); ~ProgramManager();
void Create(); 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) { void UseVertexShader(GLuint program) {
current_state.vertex_shader = program; current_state.vertex_shader = program;
@ -46,33 +51,27 @@ public:
current_state.fragment_shader = program; current_state.fragment_shader = program;
} }
GLuint GetHandle() const {
return pipeline.handle;
}
void UseTrivialFragmentShader() {
current_state.fragment_shader = 0;
}
private: private:
struct PipelineState { 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 && return vertex_shader == rhs.vertex_shader && fragment_shader == rhs.fragment_shader &&
geometry_shader == rhs.geometry_shader; geometry_shader == rhs.geometry_shader;
} }
bool operator!=(const PipelineState& rhs) const { bool operator!=(const PipelineState& rhs) const noexcept {
return !operator==(rhs); return !operator==(rhs);
} }
GLuint vertex_shader{}; GLuint vertex_shader = 0;
GLuint fragment_shader{}; GLuint fragment_shader = 0;
GLuint geometry_shader{}; GLuint geometry_shader = 0;
}; };
OGLPipeline pipeline; OGLPipeline graphics_pipeline;
OGLPipeline compute_pipeline;
PipelineState current_state; PipelineState current_state;
PipelineState old_state; PipelineState old_state;
bool is_graphics_bound = true;
}; };
} // namespace OpenGL::GLShader } // namespace OpenGL::GLShader

View file

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