gl_shader_manager: Fix interaction between graphics and compute

After a compute shader was set to the pipeline, no graphics shader was
invoked again. To address this use glUseProgram to bind compute shaders
(without state tracking) and call glUseProgram(0) when transitioning out
of it back to the graphics pipeline.
This commit is contained in:
ReinUsesLisp 2020-03-11 01:03:01 -03:00
parent 22e825a3bc
commit 8357908099
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_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 *

View File

@ -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::BindGraphicsPipeline() {
if (!is_graphics_bound) {
is_graphics_bound = true;
glUseProgram(0);
}
void ProgramManager::Update() {
// 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.

View File

@ -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

View File

@ -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) {