diff options
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 40 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.h | 4 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 54 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 38 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_manager.h | 41 |
5 files changed, 146 insertions, 31 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 1290fa4cd..9cf2c6a0c 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -140,6 +140,11 @@ public: return declarations.GetResult() + shader.GetResult(); } + /// Returns entries in the shader that are useful for external functions + ShaderEntries GetEntries() const { + return {GetConstBuffersDeclarations()}; + } + private: /// Gets the Subroutine object corresponding to the specified address. const Subroutine& GetSubroutine(u32 begin, u32 end) const { @@ -186,10 +191,9 @@ private: } /// Generates code representing a uniform (C buffer) register. - std::string GetUniform(const Uniform& reg) const { - std::string index = std::to_string(reg.index); - return "uniform_" + index + "[" + std::to_string(reg.offset >> 2) + "][" + - std::to_string(reg.offset & 3) + "]"; + std::string GetUniform(const Uniform& reg) { + declr_const_buffers[reg.index].MarkAsUsed(reg.index, reg.offset); + return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']'; } /** @@ -439,6 +443,14 @@ private: GenerateDeclarations(); } + /// Returns a list of constant buffer declarations + std::vector<ConstBufferEntry> GetConstBuffersDeclarations() const { + std::vector<ConstBufferEntry> result; + std::copy_if(declr_const_buffers.begin(), declr_const_buffers.end(), + std::back_inserter(result), [](const auto& entry) { return entry.IsUsed(); }); + return result; + } + /// Add declarations for registers void GenerateDeclarations() { for (const auto& reg : declr_register) { @@ -463,6 +475,17 @@ private: ") out vec4 " + GetOutputAttribute(index) + ";"); } declarations.AddLine(""); + + 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("{"); + declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];"); + declarations.AddLine("};"); + declarations.AddLine(""); + ++const_buffer_layout; + } } private: @@ -478,18 +501,19 @@ private: std::set<std::string> declr_register; std::set<Attribute::Index> declr_input_attribute; std::set<Attribute::Index> declr_output_attribute; -}; // namespace Decompiler + std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers; +}; std::string GetCommonDeclarations() { return "bool exec_shader();"; } -boost::optional<std::string> DecompileProgram(const ProgramCode& program_code, u32 main_offset, - Maxwell3D::Regs::ShaderStage stage) { +boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, + Maxwell3D::Regs::ShaderStage stage) { try { auto subroutines = ControlFlowAnalyzer(program_code, main_offset).GetSubroutines(); GLSLGenerator generator(subroutines, program_code, main_offset, stage); - return generator.GetShaderCode(); + return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; } catch (const DecompileFail& exception) { LOG_ERROR(HW_GPU, "Shader decompilation failed: %s", exception.what()); } diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h index 2f4047d87..9f6e0ef58 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.h +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h @@ -17,8 +17,8 @@ using Tegra::Engines::Maxwell3D; std::string GetCommonDeclarations(); -boost::optional<std::string> DecompileProgram(const ProgramCode& program_code, u32 main_offset, - Maxwell3D::Regs::ShaderStage stage); +boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, + Maxwell3D::Regs::ShaderStage stage); } // namespace Decompiler } // namespace GLShader diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 524c2cfb5..aeea1c805 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -3,18 +3,60 @@ // Refer to the license.txt file included. #include "common/assert.h" +#include "video_core/engines/maxwell_3d.h" +#include "video_core/renderer_opengl/gl_shader_decompiler.h" #include "video_core/renderer_opengl/gl_shader_gen.h" namespace GLShader { -std::string GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config) { - UNREACHABLE(); - return {}; +using Tegra::Engines::Maxwell3D; + +static constexpr u32 PROGRAM_OFFSET{10}; + +ProgramResult GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config) { + std::string out = "#version 430 core\n"; + out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; + out += Decompiler::GetCommonDeclarations(); + + ProgramResult program = Decompiler::DecompileProgram(setup.program_code, PROGRAM_OFFSET, + Maxwell3D::Regs::ShaderStage::Vertex) + .get_value_or({}); + out += R"( + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + exec_shader(); +} + +)"; + out += program.first; + return {out, program.second}; +} + +ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config) { + std::string out = "#version 430 core\n"; + out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; + out += Decompiler::GetCommonDeclarations(); + + ProgramResult program = Decompiler::DecompileProgram(setup.program_code, PROGRAM_OFFSET, + Maxwell3D::Regs::ShaderStage::Fragment) + .get_value_or({}); + out += R"( + +out vec4 color; + +uniform sampler2D tex[32]; + +void main() { + exec_shader(); } -std::string GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config) { - UNREACHABLE(); - return {}; +)"; + out += program.first; + return {out, program.second}; } } // namespace GLShader diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index 925e66ee4..3d9aead74 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -7,6 +7,8 @@ #include <array> #include <string> #include <type_traits> +#include <utility> +#include <vector> #include "common/common_types.h" #include "common/hash.h" @@ -16,6 +18,38 @@ constexpr size_t MAX_PROGRAM_CODE_LENGTH{0x1000}; using ProgramCode = std::array<u64, MAX_PROGRAM_CODE_LENGTH>; +class ConstBufferEntry { +public: + void MarkAsUsed(unsigned index, unsigned offset) { + is_used = true; + this->index = index; + max_offset = std::max(max_offset, offset); + } + + bool IsUsed() const { + return is_used; + } + + unsigned GetIndex() const { + return index; + } + + unsigned GetSize() const { + return max_offset + 1; + } + +private: + bool is_used{}; + unsigned index{}; + unsigned max_offset{}; +}; + +struct ShaderEntries { + std::vector<ConstBufferEntry> const_buffer_entries; +}; + +using ProgramResult = std::pair<std::string, ShaderEntries>; + struct ShaderSetup { ShaderSetup(ProgramCode&& program_code) : program_code(std::move(program_code)) {} @@ -58,13 +92,13 @@ struct MaxwellFSConfig : Common::HashableStruct<MaxwellShaderConfigCommon> { * Generates the GLSL vertex shader program source code for the given VS program * @returns String of the shader source code */ -std::string GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config); +ProgramResult GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config); /** * Generates the GLSL fragment shader program source code for the given FS program * @returns String of the shader source code */ -std::string GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config); +ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config); } // namespace GLShader diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index f003ce532..ecc92d986 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -41,19 +41,25 @@ class OGLShaderStage { public: OGLShaderStage() = default; - void Create(const char* source, GLenum type) { + void Create(const ProgramResult& program_result, GLenum type) { OGLShader shader; - shader.Create(source, type); + shader.Create(program_result.first.c_str(), type); program.Create(true, shader.handle); Impl::SetShaderUniformBlockBindings(program.handle); Impl::SetShaderSamplerBindings(program.handle); + entries = program_result.second; } GLuint GetHandle() const { return program.handle; } + ShaderEntries GetEntries() const { + return entries; + } + private: OGLProgram program; + ShaderEntries entries; }; // TODO(wwylele): beautify this doc @@ -61,25 +67,28 @@ private: // The double cache is needed because diffent KeyConfigType, which includes a hash of the code // region (including its leftover unused code) can generate the same GLSL code. template <typename KeyConfigType, - std::string (*CodeGenerator)(const ShaderSetup&, const KeyConfigType&), GLenum ShaderType> + ProgramResult (*CodeGenerator)(const ShaderSetup&, const KeyConfigType&), + GLenum ShaderType> class ShaderCache { public: ShaderCache() = default; - GLuint Get(const KeyConfigType& key, const ShaderSetup& setup) { + using Result = std::pair<GLuint, ShaderEntries>; + + Result Get(const KeyConfigType& key, const ShaderSetup& setup) { auto map_it = shader_map.find(key); if (map_it == shader_map.end()) { - std::string program = CodeGenerator(setup, key); + ProgramResult program = CodeGenerator(setup, key); - auto [iter, new_shader] = shader_cache.emplace(program, OGLShaderStage{}); + auto [iter, new_shader] = shader_cache.emplace(program.first, OGLShaderStage{}); OGLShaderStage& cached_shader = iter->second; if (new_shader) { - cached_shader.Create(program.c_str(), ShaderType); + cached_shader.Create(program, ShaderType); } shader_map[key] = &cached_shader; - return cached_shader.GetHandle(); + return {cached_shader.GetHandle(), program.second}; } else { - return map_it->second->GetHandle(); + return {map_it->second->GetHandle(), map_it->second->GetEntries()}; } } @@ -98,12 +107,18 @@ public: pipeline.Create(); } - void UseProgrammableVertexShader(const MaxwellVSConfig& config, const ShaderSetup setup) { - current.vs = vertex_shaders.Get(config, setup); + ShaderEntries UseProgrammableVertexShader(const MaxwellVSConfig& config, + const ShaderSetup setup) { + ShaderEntries result; + std::tie(current.vs, result) = vertex_shaders.Get(config, setup); + return result; } - void UseProgrammableFragmentShader(const MaxwellFSConfig& config, const ShaderSetup setup) { - current.fs = fragment_shaders.Get(config, setup); + ShaderEntries UseProgrammableFragmentShader(const MaxwellFSConfig& config, + const ShaderSetup setup) { + ShaderEntries result; + std::tie(current.fs, result) = fragment_shaders.Get(config, setup); + return result; } void UseTrivialGeometryShader() { |