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