diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a778dfc64..28abc563a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -193,6 +193,9 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size auto& gpu = Core::System().GetInstance().GPU().Maxwell3D(); ASSERT_MSG(!gpu.regs.shader_config[0].enable, "VertexA is unsupported!"); + // Next available bindpoint to use when uploading the const buffers to the GLSL shaders. + u32 current_constbuffer_bindpoint = 0; + for (unsigned index = 1; index < Maxwell::MaxShaderProgram; ++index) { ptr_pos += sizeof(GLShader::MaxwellUniformData); @@ -244,9 +247,13 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size UNREACHABLE(); } + GLuint gl_stage_program = shader_program_manager->GetCurrentProgramStage( + static_cast(stage)); + // Configure the const buffers for this shader stage. - SetupConstBuffers(static_cast(stage), - shader_resources.const_buffer_entries); + current_constbuffer_bindpoint = + SetupConstBuffers(static_cast(stage), gl_stage_program, + current_constbuffer_bindpoint, shader_resources.const_buffer_entries); } shader_program_manager->UseTrivialGeometryShader(); @@ -543,8 +550,9 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr } } -void RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, - const std::vector& entries) { +u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint program, + u32 current_bindpoint, + const std::vector& entries) { auto& gpu = Core::System::GetInstance().GPU(); auto& maxwell3d = gpu.Get3DEngine(); @@ -568,7 +576,7 @@ void RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, ASSERT_MSG(buffer.enabled, "Attempted to upload disabled constbuffer"); buffer_draw_state.enabled = true; - buffer_draw_state.bindpoint = bindpoint; + buffer_draw_state.bindpoint = current_bindpoint + bindpoint; VAddr addr = gpu.memory_manager->PhysicalToVirtualAddress(buffer.address); std::vector data(used_buffer.GetSize() * sizeof(float)); @@ -577,9 +585,18 @@ void RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer_draw_state.ssbo); glBufferData(GL_SHADER_STORAGE_BUFFER, data.size(), data.data(), GL_DYNAMIC_DRAW); glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + + // Now configure the bindpoint of the buffer inside the shader + std::string buffer_name = used_buffer.GetName(); + GLuint index = + glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, buffer_name.c_str()); + if (index != -1) + glShaderStorageBlockBinding(program, index, buffer_draw_state.bindpoint); } state.Apply(); + + return current_bindpoint + entries.size(); } void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 1ea0dfa71..548ce0453 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -87,9 +87,17 @@ private: /// Binds the required textures to OpenGL before drawing a batch. void BindTextures(); - /// Configures the current constbuffers to use for the draw command. - void SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, - const std::vector& entries); + /* + * Configures the current constbuffers to use for the draw command. + * @param stage The shader stage to configure buffers for. + * @param program The OpenGL program object that contains the specified stage. + * @param current_bindpoint The offset at which to start counting new buffer bindpoints. + * @param entries Vector describing the buffers that are actually used in the guest shader. + * @returns The next available bindpoint for use in the next shader stage. + */ + u32 SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, GLuint program, + u32 current_bindpoint, + const std::vector& entries); /// Syncs the viewport to match the guest state void SyncViewport(const MathUtil::Rectangle& surfaces_rect, u16 res_scale); diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 9cf2c6a0c..e11711533 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -192,7 +192,7 @@ private: /// Generates code representing a uniform (C buffer) register. std::string GetUniform(const Uniform& reg) { - declr_const_buffers[reg.index].MarkAsUsed(reg.index, reg.offset); + declr_const_buffers[reg.index].MarkAsUsed(reg.index, reg.offset, stage); return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']'; } @@ -478,8 +478,7 @@ private: unsigned const_buffer_layout = 0; for (const auto& entry : GetConstBuffersDeclarations()) { - declarations.AddLine("layout(std430, binding = " + std::to_string(const_buffer_layout) + - ") buffer c" + std::to_string(entry.GetIndex()) + "_buffer"); + declarations.AddLine("layout(std430) buffer " + entry.GetName()); declarations.AddLine("{"); declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];"); declarations.AddLine("};"); diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index 3d9aead74..458032b5c 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -19,10 +19,13 @@ constexpr size_t MAX_PROGRAM_CODE_LENGTH{0x1000}; using ProgramCode = std::array; class ConstBufferEntry { + using Maxwell = Tegra::Engines::Maxwell3D::Regs; + public: - void MarkAsUsed(unsigned index, unsigned offset) { + void MarkAsUsed(unsigned index, unsigned offset, Maxwell::ShaderStage stage) { is_used = true; this->index = index; + this->stage = stage; max_offset = std::max(max_offset, offset); } @@ -38,10 +41,19 @@ public: return max_offset + 1; } + std::string GetName() const { + return BufferBaseNames[static_cast(stage)] + std::to_string(index); + } + private: + static constexpr std::array BufferBaseNames = { + "buffer_vs_c", "buffer_tessc_c", "buffer_tesse_c", "buffer_gs_c", "buffer_fs_c", + }; + bool is_used{}; unsigned index{}; unsigned max_offset{}; + Maxwell::ShaderStage stage; }; struct ShaderEntries { diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index ecc92d986..be63320e0 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -121,6 +121,17 @@ public: return result; } + GLuint GetCurrentProgramStage(Maxwell3D::Regs::ShaderStage stage) { + switch (stage) { + case Maxwell3D::Regs::ShaderStage::Vertex: + return current.vs; + case Maxwell3D::Regs::ShaderStage::Fragment: + return current.fs; + } + + UNREACHABLE(); + } + void UseTrivialGeometryShader() { current.gs = 0; }