mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-12-22 16:30:57 +01:00
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:
parent
22e825a3bc
commit
8357908099
4 changed files with 39 additions and 29 deletions
|
@ -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 *
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue