diff options
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 21 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 11 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 55 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 71 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 44 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 33 | 
7 files changed, 149 insertions, 89 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 3bca16364..dfbf80abd 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -398,27 +398,6 @@ u32 Maxwell3D::GetRegisterValue(u32 method) const {      return regs.reg_array[method];  } -bool Maxwell3D::IsShaderStageEnabled(Regs::ShaderStage stage) const { -    // The Vertex stage is always enabled. -    if (stage == Regs::ShaderStage::Vertex) -        return true; - -    switch (stage) { -    case Regs::ShaderStage::TesselationControl: -        return regs.shader_config[static_cast<size_t>(Regs::ShaderProgram::TesselationControl)] -                   .enable != 0; -    case Regs::ShaderStage::TesselationEval: -        return regs.shader_config[static_cast<size_t>(Regs::ShaderProgram::TesselationEval)] -                   .enable != 0; -    case Regs::ShaderStage::Geometry: -        return regs.shader_config[static_cast<size_t>(Regs::ShaderProgram::Geometry)].enable != 0; -    case Regs::ShaderStage::Fragment: -        return regs.shader_config[static_cast<size_t>(Regs::ShaderProgram::Fragment)].enable != 0; -    } - -    UNREACHABLE(); -} -  void Maxwell3D::ProcessClearBuffers() {      ASSERT(regs.clear_buffers.R == regs.clear_buffers.G &&             regs.clear_buffers.R == regs.clear_buffers.B && diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 5a7cf0107..6f0170ff7 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -379,6 +379,14 @@ public:              }          }; +        bool IsShaderConfigEnabled(size_t index) const { +            // The VertexB is always enabled. +            if (index == static_cast<size_t>(Regs::ShaderProgram::VertexB)) { +                return true; +            } +            return shader_config[index].enable != 0; +        } +          union {              struct {                  INSERT_PADDING_WORDS(0x45); @@ -780,9 +788,6 @@ public:      /// Returns the texture information for a specific texture in a specific shader stage.      Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, size_t offset) const; -    /// Returns whether the specified shader stage is enabled or not. -    bool IsShaderStageEnabled(Regs::ShaderStage stage) const; -  private:      std::unordered_map<u32, std::vector<u32>> uploaded_macros; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index ea138d402..4072a12b4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -181,6 +181,19 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,      return {array_ptr, buffer_offset};  } +static GLShader::ProgramCode GetShaderProgramCode(Maxwell::ShaderProgram program) { +    auto& gpu = Core::System().GetInstance().GPU().Maxwell3D(); + +    // Fetch program code from memory +    GLShader::ProgramCode program_code; +    auto& shader_config = gpu.regs.shader_config[static_cast<size_t>(program)]; +    const u64 gpu_address{gpu.regs.code_address.CodeAddress() + shader_config.offset}; +    const boost::optional<VAddr> cpu_address{gpu.memory_manager.GpuToCpuAddress(gpu_address)}; +    Memory::ReadBlock(*cpu_address, program_code.data(), program_code.size() * sizeof(u64)); + +    return program_code; +} +  void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {      // Helper function for uploading uniform data      const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) { @@ -193,26 +206,23 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {      };      auto& gpu = Core::System().GetInstance().GPU().Maxwell3D(); -    ASSERT_MSG(!gpu.regs.shader_config[0].enable, "VertexA is unsupported!");      // Next available bindpoints to use when uploading the const buffers and textures to the GLSL      // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.      u32 current_constbuffer_bindpoint = uniform_buffers.size();      u32 current_texture_bindpoint = 0; -    for (unsigned index = 1; index < Maxwell::MaxShaderProgram; ++index) { +    for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {          auto& shader_config = gpu.regs.shader_config[index];          const Maxwell::ShaderProgram program{static_cast<Maxwell::ShaderProgram>(index)}; -        const auto& stage = index - 1; // Stage indices are 0 - 5 - -        const bool is_enabled = gpu.IsShaderStageEnabled(static_cast<Maxwell::ShaderStage>(stage)); -          // Skip stages that are not enabled -        if (!is_enabled) { +        if (!gpu.regs.IsShaderConfigEnabled(index)) {              continue;          } +        const size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5 +          GLShader::MaxwellUniformData ubo{};          ubo.SetFromRegs(gpu.state.shader_stages[stage]);          std::memcpy(buffer_ptr, &ubo, sizeof(ubo)); @@ -228,16 +238,21 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {          buffer_ptr += sizeof(GLShader::MaxwellUniformData);          buffer_offset += sizeof(GLShader::MaxwellUniformData); -        // Fetch program code from memory -        GLShader::ProgramCode program_code; -        const u64 gpu_address{gpu.regs.code_address.CodeAddress() + shader_config.offset}; -        const boost::optional<VAddr> cpu_address{gpu.memory_manager.GpuToCpuAddress(gpu_address)}; -        Memory::ReadBlock(*cpu_address, program_code.data(), program_code.size() * sizeof(u64)); -        GLShader::ShaderSetup setup{std::move(program_code)}; - +        GLShader::ShaderSetup setup{GetShaderProgramCode(program)};          GLShader::ShaderEntries shader_resources;          switch (program) { +        case Maxwell::ShaderProgram::VertexA: { +            // VertexB is always enabled, so when VertexA is enabled, we have two vertex shaders. +            // Conventional HW does not support this, so we combine VertexA and VertexB into one +            // stage here. +            setup.SetProgramB(GetShaderProgramCode(Maxwell::ShaderProgram::VertexB)); +            GLShader::MaxwellVSConfig vs_config{setup}; +            shader_resources = +                shader_program_manager->UseProgrammableVertexShader(vs_config, setup); +            break; +        } +          case Maxwell::ShaderProgram::VertexB: {              GLShader::MaxwellVSConfig vs_config{setup};              shader_resources = @@ -268,6 +283,12 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {          current_texture_bindpoint =              SetupTextures(static_cast<Maxwell::ShaderStage>(stage), gl_stage_program,                            current_texture_bindpoint, shader_resources.texture_samplers); + +        // When VertexA is enabled, we have dual vertex shaders +        if (program == Maxwell::ShaderProgram::VertexA) { +            // VertexB was combined with VertexA, so we skip the VertexB iteration +            index++; +        }      }      shader_program_manager->UseTrivialGeometryShader(); @@ -605,9 +626,6 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr      auto& gpu = Core::System::GetInstance().GPU();      auto& maxwell3d = gpu.Get3DEngine(); -    ASSERT_MSG(maxwell3d.IsShaderStageEnabled(stage), -               "Attempted to upload constbuffer of disabled shader stage"); -      // Reset all buffer draw state for this stage.      for (auto& buffer : state.draw.const_buffers[static_cast<size_t>(stage)]) {          buffer.bindpoint = 0; @@ -674,9 +692,6 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program,      auto& gpu = Core::System::GetInstance().GPU();      auto& maxwell3d = gpu.Get3DEngine(); -    ASSERT_MSG(maxwell3d.IsShaderStageEnabled(stage), -               "Attempted to upload textures of disabled shader stage"); -      ASSERT_MSG(current_unit + entries.size() <= std::size(state.texture_units),                 "Exceeded the number of active textures."); diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 96a4ca6fe..5fae95788 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -42,13 +42,14 @@ enum class ExitMethod {  struct Subroutine {      /// Generates a name suitable for GLSL source code.      std::string GetName() const { -        return "sub_" + std::to_string(begin) + '_' + std::to_string(end); +        return "sub_" + std::to_string(begin) + '_' + std::to_string(end) + '_' + suffix;      } -    u32 begin;              ///< Entry point of the subroutine. -    u32 end;                ///< Return point of the subroutine. -    ExitMethod exit_method; ///< Exit method of the subroutine. -    std::set<u32> labels;   ///< Addresses refereced by JMP instructions. +    u32 begin;                 ///< Entry point of the subroutine. +    u32 end;                   ///< Return point of the subroutine. +    const std::string& suffix; ///< Suffix of the shader, used to make a unique subroutine name +    ExitMethod exit_method;    ///< Exit method of the subroutine. +    std::set<u32> labels;      ///< Addresses refereced by JMP instructions.      bool operator<(const Subroutine& rhs) const {          return std::tie(begin, end) < std::tie(rhs.begin, rhs.end); @@ -58,11 +59,11 @@ struct Subroutine {  /// Analyzes shader code and produces a set of subroutines.  class ControlFlowAnalyzer {  public: -    ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset) +    ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset, const std::string& suffix)          : program_code(program_code) {          // Recursively finds all subroutines. -        const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END); +        const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END, suffix);          if (program_main.exit_method != ExitMethod::AlwaysEnd)              throw DecompileFail("Program does not always end");      } @@ -77,12 +78,12 @@ private:      std::map<std::pair<u32, u32>, ExitMethod> exit_method_map;      /// Adds and analyzes a new subroutine if it is not added yet. -    const Subroutine& AddSubroutine(u32 begin, u32 end) { -        auto iter = subroutines.find(Subroutine{begin, end}); +    const Subroutine& AddSubroutine(u32 begin, u32 end, const std::string& suffix) { +        auto iter = subroutines.find(Subroutine{begin, end, suffix});          if (iter != subroutines.end())              return *iter; -        Subroutine subroutine{begin, end}; +        Subroutine subroutine{begin, end, suffix};          subroutine.exit_method = Scan(begin, end, subroutine.labels);          if (subroutine.exit_method == ExitMethod::Undetermined)              throw DecompileFail("Recursive function detected"); @@ -191,7 +192,8 @@ public:          UnsignedInteger,      }; -    GLSLRegister(size_t index, ShaderWriter& shader) : index{index}, shader{shader} {} +    GLSLRegister(size_t index, ShaderWriter& shader, const std::string& suffix) +        : index{index}, shader{shader}, suffix{suffix} {}      /// Gets the GLSL type string for a register      static std::string GetTypeString(Type type) { @@ -216,7 +218,7 @@ public:      /// Returns a GLSL string representing the current state of the register      const std::string GetActiveString() {          declr_type.insert(active_type); -        return GetPrefixString(active_type) + std::to_string(index); +        return GetPrefixString(active_type) + std::to_string(index) + '_' + suffix;      }      /// Returns true if the active type is a float @@ -251,6 +253,7 @@ private:      ShaderWriter& shader;      Type active_type{Type::Float};      std::set<Type> declr_type; +    const std::string& suffix;  };  /** @@ -262,8 +265,8 @@ private:  class GLSLRegisterManager {  public:      GLSLRegisterManager(ShaderWriter& shader, ShaderWriter& declarations, -                        const Maxwell3D::Regs::ShaderStage& stage) -        : shader{shader}, declarations{declarations}, stage{stage} { +                        const Maxwell3D::Regs::ShaderStage& stage, const std::string& suffix) +        : shader{shader}, declarations{declarations}, stage{stage}, suffix{suffix} {          BuildRegisterList();      } @@ -430,12 +433,12 @@ public:      }      /// Add declarations for registers -    void GenerateDeclarations() { +    void GenerateDeclarations(const std::string& suffix) {          for (const auto& reg : regs) {              for (const auto& type : reg.DeclaredTypes()) {                  declarations.AddLine(GLSLRegister::GetTypeString(type) + ' ' + -                                     GLSLRegister::GetPrefixString(type) + -                                     std::to_string(reg.GetIndex()) + " = 0;"); +                                     reg.GetPrefixString(type) + std::to_string(reg.GetIndex()) + +                                     '_' + suffix + " = 0;");              }          }          declarations.AddNewLine(); @@ -558,7 +561,7 @@ private:      /// Build the GLSL register list.      void BuildRegisterList() {          for (size_t index = 0; index < Register::NumRegisters; ++index) { -            regs.emplace_back(index, shader); +            regs.emplace_back(index, shader, suffix);          }      } @@ -620,16 +623,17 @@ private:      std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers;      std::vector<SamplerEntry> used_samplers;      const Maxwell3D::Regs::ShaderStage& stage; +    const std::string& suffix;  };  class GLSLGenerator {  public:      GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, -                  u32 main_offset, Maxwell3D::Regs::ShaderStage stage) +                  u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix)          : subroutines(subroutines), program_code(program_code), main_offset(main_offset), -          stage(stage) { +          stage(stage), suffix(suffix) { -        Generate(); +        Generate(suffix);      }      std::string GetShaderCode() { @@ -644,7 +648,7 @@ public:  private:      /// Gets the Subroutine object corresponding to the specified address.      const Subroutine& GetSubroutine(u32 begin, u32 end) const { -        auto iter = subroutines.find(Subroutine{begin, end}); +        auto iter = subroutines.find(Subroutine{begin, end, suffix});          ASSERT(iter != subroutines.end());          return *iter;      } @@ -689,7 +693,7 @@ private:          // Can't assign to the constant predicate.          ASSERT(pred != static_cast<u64>(Pred::UnusedIndex)); -        std::string variable = 'p' + std::to_string(pred); +        std::string variable = 'p' + std::to_string(pred) + '_' + suffix;          shader.AddLine(variable + " = " + value + ';');          declr_predicates.insert(std::move(variable));      } @@ -707,7 +711,7 @@ private:          if (index == static_cast<u64>(Pred::UnusedIndex))              variable = "true";          else -            variable = 'p' + std::to_string(index); +            variable = 'p' + std::to_string(index) + '_' + suffix;          if (negate) {              return "!(" + variable + ')'; @@ -1728,7 +1732,7 @@ private:          return program_counter;      } -    void Generate() { +    void Generate(const std::string& suffix) {          // Add declarations for all subroutines          for (const auto& subroutine : subroutines) {              shader.AddLine("bool " + subroutine.GetName() + "();"); @@ -1736,7 +1740,7 @@ private:          shader.AddNewLine();          // Add the main entry point -        shader.AddLine("bool exec_shader() {"); +        shader.AddLine("bool exec_" + suffix + "() {");          ++shader.scope;          CallSubroutine(GetSubroutine(main_offset, PROGRAM_END));          --shader.scope; @@ -1799,7 +1803,7 @@ private:      /// Add declarations for registers      void GenerateDeclarations() { -        regs.GenerateDeclarations(); +        regs.GenerateDeclarations(suffix);          for (const auto& pred : declr_predicates) {              declarations.AddLine("bool " + pred + " = false;"); @@ -1812,27 +1816,30 @@ private:      const ProgramCode& program_code;      const u32 main_offset;      Maxwell3D::Regs::ShaderStage stage; +    const std::string& suffix;      ShaderWriter shader;      ShaderWriter declarations; -    GLSLRegisterManager regs{shader, declarations, stage}; +    GLSLRegisterManager regs{shader, declarations, stage, suffix};      // Declarations      std::set<std::string> declr_predicates;  }; // namespace Decompiler  std::string GetCommonDeclarations() { -    std::string declarations = "bool exec_shader();\n"; +    std::string declarations;      declarations += "#define MAX_CONSTBUFFER_ELEMENTS " +                      std::to_string(RasterizerOpenGL::MaxConstbufferSize / (sizeof(GLvec4))); +    declarations += '\n';      return declarations;  }  boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, -                                                Maxwell3D::Regs::ShaderStage stage) { +                                                Maxwell3D::Regs::ShaderStage stage, +                                                const std::string& suffix) {      try { -        auto subroutines = ControlFlowAnalyzer(program_code, main_offset).GetSubroutines(); -        GLSLGenerator generator(subroutines, program_code, main_offset, stage); +        auto subroutines = ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines(); +        GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix);          return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};      } catch (const DecompileFail& exception) {          LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", 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 382c76b7a..7610dad3a 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.h +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h @@ -20,7 +20,8 @@ using Tegra::Engines::Maxwell3D;  std::string GetCommonDeclarations();  boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, -                                                Maxwell3D::Regs::ShaderStage stage); +                                                Maxwell3D::Regs::ShaderStage stage, +                                                const std::string& suffix);  } // 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 c1e6fac9f..129c777d1 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -17,10 +17,17 @@ ProgramResult GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConf      std::string out = "#version 430 core\n";      out += "#extension GL_ARB_separate_shader_objects : enable\n\n";      out += Decompiler::GetCommonDeclarations(); +    out += "bool exec_vertex();\n"; + +    if (setup.IsDualProgram()) { +        out += "bool exec_vertex_b();\n"; +    } + +    ProgramResult program = +        Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET, +                                     Maxwell3D::Regs::ShaderStage::Vertex, "vertex") +            .get_value_or({}); -    ProgramResult program = Decompiler::DecompileProgram(setup.program_code, PROGRAM_OFFSET, -                                                         Maxwell3D::Regs::ShaderStage::Vertex) -                                .get_value_or({});      out += R"(  out gl_PerVertex { @@ -34,7 +41,14 @@ layout (std140) uniform vs_config {  };  void main() { -    exec_shader(); +    exec_vertex(); +)"; + +    if (setup.IsDualProgram()) { +        out += "    exec_vertex_b();"; +    } + +    out += R"(      // Viewport can be flipped, which is unsupported by glViewport      position.xy *= viewport_flip.xy; @@ -44,8 +58,19 @@ void main() {      // For now, this is here to bring order in lieu of proper emulation      position.w = 1.0;  } +  )"; +      out += program.first; + +    if (setup.IsDualProgram()) { +        ProgramResult program_b = +            Decompiler::DecompileProgram(setup.program.code_b, PROGRAM_OFFSET, +                                         Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b") +                .get_value_or({}); +        out += program_b.first; +    } +      return {out, program.second};  } @@ -53,12 +78,13 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSCo      std::string out = "#version 430 core\n";      out += "#extension GL_ARB_separate_shader_objects : enable\n\n";      out += Decompiler::GetCommonDeclarations(); +    out += "bool exec_fragment();\n"; -    ProgramResult program = Decompiler::DecompileProgram(setup.program_code, PROGRAM_OFFSET, -                                                         Maxwell3D::Regs::ShaderStage::Fragment) -                                .get_value_or({}); +    ProgramResult program = +        Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET, +                                     Maxwell3D::Regs::ShaderStage::Fragment, "fragment") +            .get_value_or({});      out += R"( -  in vec4 position;  out vec4 color; @@ -67,7 +93,7 @@ layout (std140) uniform fs_config {  };  void main() { -    exec_shader(); +    exec_fragment();  }  )"; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index ed890e0f9..4729ce0fc 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -115,21 +115,48 @@ struct ShaderEntries {  using ProgramResult = std::pair<std::string, ShaderEntries>;  struct ShaderSetup { -    ShaderSetup(ProgramCode&& program_code) : program_code(std::move(program_code)) {} +    ShaderSetup(const ProgramCode& program_code) { +        program.code = program_code; +    } + +    struct { +        ProgramCode code; +        ProgramCode code_b; // Used for dual vertex shaders +    } program; -    ProgramCode program_code;      bool program_code_hash_dirty = true;      u64 GetProgramCodeHash() {          if (program_code_hash_dirty) { -            program_code_hash = Common::ComputeHash64(&program_code, sizeof(program_code)); +            program_code_hash = GetNewHash();              program_code_hash_dirty = false;          }          return program_code_hash;      } +    /// Used in scenarios where we have a dual vertex shaders +    void SetProgramB(const ProgramCode& program_b) { +        program.code_b = program_b; +        has_program_b = true; +    } + +    bool IsDualProgram() const { +        return has_program_b; +    } +  private: +    u64 GetNewHash() const { +        if (has_program_b) { +            // Compute hash over dual shader programs +            return Common::ComputeHash64(&program, sizeof(program)); +        } else { +            // Compute hash over a single shader program +            return Common::ComputeHash64(&program.code, program.code.size()); +        } +    } +      u64 program_code_hash{}; +    bool has_program_b{};  };  struct MaxwellShaderConfigCommon {  | 
