From 14ac40436ead929506d5fdf16eb3721940e60956 Mon Sep 17 00:00:00 2001 From: Subv Date: Sun, 15 Apr 2018 14:14:57 -0500 Subject: [PATCH 1/2] GPU: Don't use explicit binding points when uploading the constbuffers to opengl. The bindpoints will now be dynamically calculated based on the number of buffers used by the previous shader stage. --- .../renderer_opengl/gl_rasterizer.cpp | 30 +++++++++++++++---- .../renderer_opengl/gl_rasterizer.h | 13 ++++++-- .../renderer_opengl/gl_shader_manager.h | 11 +++++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a778dfc640..a80923285b 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); @@ -223,6 +226,10 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size Memory::ReadBlock(cpu_address, program_code.data(), program_code.size() * sizeof(u64)); GLShader::ShaderSetup setup{std::move(program_code)}; + static constexpr std::array base_names = { + "buffer_vs_c", "buffer_tessc_c", "buffer_tesse_c", "buffer_gs_c", "buffer_fs_c", + }; + GLShader::ShaderEntries shader_resources; switch (program) { @@ -244,9 +251,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, base_names[stage], + current_constbuffer_bindpoint, shader_resources.const_buffer_entries); } shader_program_manager->UseTrivialGeometryShader(); @@ -543,8 +554,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, + const std::string& base_name, u32 current_bindpoint, + const std::vector& entries) { auto& gpu = Core::System::GetInstance().GPU(); auto& maxwell3d = gpu.Get3DEngine(); @@ -568,7 +580,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 +589,17 @@ 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 = base_name + std::to_string(used_buffer.GetIndex()); + GLuint index = + glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, buffer_name.c_str()); + 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 1ea0dfa71d..32d9598aa2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -87,8 +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, + /* + * 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 base_name The name prefix of the buffer objects in the GLSL shaders. + * @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, + const std::string& base_name, u32 current_bindpoint, const std::vector& entries); /// Syncs the viewport to match the guest state diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index ecc92d9863..be63320e0d 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; } From 477aab59603825e3cfc5144b784d0fe3df286ae4 Mon Sep 17 00:00:00 2001 From: Subv Date: Sun, 15 Apr 2018 14:42:23 -0500 Subject: [PATCH 2/2] GPU: Use the same buffer names in the generated GLSL and the buffer uploading code. --- .../renderer_opengl/gl_rasterizer.cpp | 17 +++++++---------- src/video_core/renderer_opengl/gl_rasterizer.h | 5 ++--- .../renderer_opengl/gl_shader_decompiler.cpp | 5 ++--- src/video_core/renderer_opengl/gl_shader_gen.h | 14 +++++++++++++- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a80923285b..28abc563a1 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -226,10 +226,6 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size Memory::ReadBlock(cpu_address, program_code.data(), program_code.size() * sizeof(u64)); GLShader::ShaderSetup setup{std::move(program_code)}; - static constexpr std::array base_names = { - "buffer_vs_c", "buffer_tessc_c", "buffer_tesse_c", "buffer_gs_c", "buffer_fs_c", - }; - GLShader::ShaderEntries shader_resources; switch (program) { @@ -255,9 +251,9 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size static_cast(stage)); // Configure the const buffers for this shader stage. - current_constbuffer_bindpoint = SetupConstBuffers( - static_cast(stage), gl_stage_program, base_names[stage], - current_constbuffer_bindpoint, 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(); @@ -555,7 +551,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr } u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint program, - const std::string& base_name, u32 current_bindpoint, + u32 current_bindpoint, const std::vector& entries) { auto& gpu = Core::System::GetInstance().GPU(); auto& maxwell3d = gpu.Get3DEngine(); @@ -591,10 +587,11 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); // Now configure the bindpoint of the buffer inside the shader - std::string buffer_name = base_name + std::to_string(used_buffer.GetIndex()); + std::string buffer_name = used_buffer.GetName(); GLuint index = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, buffer_name.c_str()); - glShaderStorageBlockBinding(program, index, buffer_draw_state.bindpoint); + if (index != -1) + glShaderStorageBlockBinding(program, index, buffer_draw_state.bindpoint); } state.Apply(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 32d9598aa2..548ce0453f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -91,14 +91,13 @@ private: * 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 base_name The name prefix of the buffer objects in the GLSL shaders. * @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, - const std::string& base_name, u32 current_bindpoint, - const std::vector& entries); + 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 9cf2c6a0cd..e11711533e 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 3d9aead74f..458032b5c4 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 {