diff options
| author | bunnei <bunneidev@gmail.com> | 2015-10-05 22:33:47 -0400 | 
|---|---|---|
| committer | bunnei <bunneidev@gmail.com> | 2015-10-21 21:53:14 -0400 | 
| commit | c86b9d42423b5a83ccba40f828b7ad9dafe3e317 (patch) | |
| tree | 04bdd0a99fa7fa36946422d0119b3d537dd99526 /src/video_core | |
| parent | 3c057bd3d80b049720b11d0b44391c18870c28e8 (diff) | |
renderer_opengl: Refactor shader generation/caching to be more organized + various cleanups.
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 131 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 41 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_resource_manager.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 371 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 17 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_util.cpp | 348 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_util.h | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shaders.h | 339 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 39 | 
10 files changed, 509 insertions, 788 deletions
| diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 8c9d76ab4..2a924f4ad 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -1,6 +1,7 @@  set(SRCS              renderer_opengl/gl_rasterizer.cpp              renderer_opengl/gl_rasterizer_cache.cpp +            renderer_opengl/gl_shader_gen.cpp              renderer_opengl/gl_shader_util.cpp              renderer_opengl/gl_state.cpp              renderer_opengl/renderer_opengl.cpp @@ -21,8 +22,8 @@ set(HEADERS              renderer_opengl/gl_rasterizer.h              renderer_opengl/gl_rasterizer_cache.h              renderer_opengl/gl_resource_manager.h +            renderer_opengl/gl_shader_gen.h              renderer_opengl/gl_shader_util.h -            renderer_opengl/gl_shaders.h              renderer_opengl/gl_state.h              renderer_opengl/pica_to_gl.h              renderer_opengl/renderer_opengl.h diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 01b9c91c6..4f9865230 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -9,6 +9,7 @@  #include "common/color.h"  #include "common/file_util.h" +#include "common/make_unique.h"  #include "common/math_util.h"  #include "common/microprofile.h"  #include "common/profiler.h" @@ -20,7 +21,7 @@  #include "video_core/pica.h"  #include "video_core/utils.h"  #include "video_core/renderer_opengl/gl_rasterizer.h" -#include "video_core/renderer_opengl/gl_shaders.h" +#include "video_core/renderer_opengl/gl_shader_gen.h"  #include "video_core/renderer_opengl/gl_shader_util.h"  #include "video_core/renderer_opengl/pica_to_gl.h" @@ -54,20 +55,20 @@ void RasterizerOpenGL::InitObjects() {      state.Apply();      // Set vertex attributes -    glVertexAttribPointer(ShaderUtil::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); -    glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_POSITION); +    glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); +    glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION); -    glVertexAttribPointer(ShaderUtil::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); -    glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_COLOR); +    glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); +    glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR); -    glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); -    glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); -    glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); -    glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS); -    glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS + 1); -    glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS + 2); +    glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 0, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); +    glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); +    glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); +    glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 0); +    glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 1); +    glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 2); -    RegenerateShaders(); +    SetShader();      // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation      fb_color_texture.texture.Create(); @@ -117,8 +118,6 @@ void RasterizerOpenGL::InitObjects() {  }  void RasterizerOpenGL::Reset() { -    const auto& regs = Pica::g_state.regs; -      SyncCullMode();      SyncBlendEnabled();      SyncBlendFuncs(); @@ -127,7 +126,7 @@ void RasterizerOpenGL::Reset() {      SyncStencilTest();      SyncDepthTest(); -    RegenerateShaders(); +    SetShader();      res_cache.FullFlush();  } @@ -140,70 +139,12 @@ void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0,      vertex_batch.emplace_back(v2);  } -namespace ShaderCache { -extern std::string GenerateFragmentShader(const ShaderCacheKey& config); -} - -void RasterizerOpenGL::RegenerateShaders() { -    ShaderCacheKey config = ShaderCacheKey::CurrentShaderConfig(); - -    auto cached_shader = shader_cache.find(config); -    if (cached_shader != shader_cache.end()) { -        current_shader = &cached_shader->second; -        state.draw.shader_program = current_shader->shader.handle; -        state.Apply(); -    } else { -        LOG_CRITICAL(Render_OpenGL, "Creating new shader: %08X", hash(config)); - -        TEVShader shader; - -        std::string fragShader = ShaderCache::GenerateFragmentShader(config); -        shader.shader.Create(GLShaders::g_vertex_shader_hw, fragShader.c_str()); - -        shader.uniform_alphatest_ref = glGetUniformLocation(shader.shader.handle, "alphatest_ref"); -        shader.uniform_tex = glGetUniformLocation(shader.shader.handle, "tex"); -        shader.uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.shader.handle, "tev_combiner_buffer_color"); -        shader.uniform_tev_const_colors = glGetUniformLocation(shader.shader.handle, "const_color"); - -        current_shader = &shader_cache.emplace(config, std::move(shader)).first->second; - -        state.draw.shader_program = current_shader->shader.handle; -        state.Apply(); - -        // Set the texture samplers to correspond to different texture units -        if (shader.uniform_tex != -1) { -            glUniform1i(shader.uniform_tex, 0); -            glUniform1i(shader.uniform_tex + 1, 1); -            glUniform1i(shader.uniform_tex + 2, 2); -        } -    } - -    // Sync alpha reference -    if (current_shader->uniform_alphatest_ref != -1) -        glUniform1i(current_shader->uniform_alphatest_ref, Pica::g_state.regs.output_merger.alpha_test.ref); - -    // Sync combiner buffer color -    if (current_shader->uniform_tev_combiner_buffer_color != -1) { -        auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); -        glUniform4fv(current_shader->uniform_tev_combiner_buffer_color, 1, combiner_color.data()); -    } - -    // Sync TEV const colors -    if (current_shader->uniform_tev_const_colors != -1) { -        auto& tev_stages = Pica::g_state.regs.GetTevStages(); -        for (int tev_index = 0; tev_index < tev_stages.size(); ++tev_index) { -            auto const_color = PicaToGL::ColorRGBA8(tev_stages[tev_index].const_color); -            glUniform4fv(current_shader->uniform_tev_const_colors + tev_index, 1, const_color.data()); -        } -    } -} -  void RasterizerOpenGL::DrawTriangles() {      SyncFramebuffer();      SyncDrawState();      if (state.draw.shader_dirty) { -        RegenerateShaders(); +        SetShader();          state.draw.shader_dirty = false;      } @@ -519,6 +460,48 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::      state.Apply();  } +void RasterizerOpenGL::SetShader() { +    ShaderCacheKey config = ShaderCacheKey::CurrentConfig(); + +    // Find (or generate) the GLSL shader for the current TEV state +    auto cached_shader = shader_cache.find(config); +    if (cached_shader != shader_cache.end()) { +        current_shader = cached_shader->second.get(); + +        state.draw.shader_program = current_shader->shader.handle; +        state.Apply(); +    } else { +        LOG_DEBUG(Render_OpenGL, "Creating new shader: %08X", hash(config)); + +        std::unique_ptr<TEVShader> shader = Common::make_unique<TEVShader>(); + +        shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str()); +        shader->uniform_alphatest_ref = glGetUniformLocation(shader->shader.handle, "alphatest_ref"); +        shader->uniform_tex = glGetUniformLocation(shader->shader.handle, "tex"); +        shader->uniform_tev_combiner_buffer_color = glGetUniformLocation(shader->shader.handle, "tev_combiner_buffer_color"); +        shader->uniform_tev_const_colors = glGetUniformLocation(shader->shader.handle, "const_color"); + +        state.draw.shader_program = shader->shader.handle; +        state.Apply(); + +        // Set the texture samplers to correspond to different texture units +        if (shader->uniform_tex != -1) { +            glUniform1i(shader->uniform_tex, 0); +            glUniform1i(shader->uniform_tex + 1, 1); +            glUniform1i(shader->uniform_tex + 2, 2); +        } + +        current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); +    } + +    // Update uniforms +    SyncAlphaTest(); +    SyncCombinerColor(); +    auto& tev_stages = Pica::g_state.regs.GetTevStages(); +    for (int index = 0; index < tev_stages.size(); ++index) +        SyncTevConstColor(index, tev_stages[index]); +} +  void RasterizerOpenGL::SyncFramebuffer() {      const auto& regs = Pica::g_state.regs; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 5bc4a319f..de9e4d22e 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -4,6 +4,8 @@  #pragma once +#include <cstddef> +#include <memory>  #include <vector>  #include <unordered_map> @@ -15,21 +17,6 @@  #include "video_core/renderer_opengl/gl_state.h"  #include "video_core/shader/shader_interpreter.h" -template <typename T> -inline size_t hash(const T& o) { -    return std::hash<T>()(o); -} - -template <typename T> -inline size_t combine_hash(const T& o) { -    return hash(o); -} - -template <typename T, typename... Args> -inline size_t combine_hash(const T& o, const Args&... args) { -    return hash(o) * 3 + combine_hash(args...); -} -  struct ShaderCacheKey {      using Regs = Pica::Regs; @@ -49,7 +36,7 @@ struct ShaderCacheKey {          return (stage_index < 4) && ((combiner_buffer_input >> 4) & (1 << stage_index));      } -    static ShaderCacheKey CurrentShaderConfig() { +    static ShaderCacheKey CurrentConfig() {          const auto& regs = Pica::g_state.regs;          ShaderCacheKey config; @@ -94,8 +81,14 @@ struct ShaderCacheKey {  namespace std { +template<> struct hash<::Pica::Regs::CompareFunc> { +    std::size_t operator()(const ::Pica::Regs::CompareFunc& o) { +        return ::hash((unsigned)o); +    } +}; +  template<> struct hash<::Pica::Regs::TevStageConfig> { -    size_t operator()(const ::Pica::Regs::TevStageConfig& o) { +    std::size_t operator()(const ::Pica::Regs::TevStageConfig& o) {          return ::combine_hash(              ::hash(o.source_raw), ::hash(o.modifier_raw),              ::hash(o.op_raw), ::hash(o.scale_raw)); @@ -103,13 +96,14 @@ template<> struct hash<::Pica::Regs::TevStageConfig> {  };  template<> struct hash<::ShaderCacheKey> { -    size_t operator()(const ::ShaderCacheKey& o) const { +    std::size_t operator()(const ::ShaderCacheKey& o) const {          return ::combine_hash(o.alpha_test_func, o.combiner_buffer_input,              o.tev_stages[0], o.tev_stages[1], o.tev_stages[2],              o.tev_stages[3], o.tev_stages[4], o.tev_stages[5]);      }  }; -} + +} // namespace std  class RasterizerOpenGL : public HWRasterizer {  public: @@ -131,8 +125,6 @@ public:      /// Draw the current batch of triangles      void DrawTriangles() override; -    void RegenerateShaders(); -      /// Commit the rasterizer's framebuffer contents immediately to the current 3DS memory framebuffer      void CommitFramebuffer() override; @@ -245,6 +237,9 @@ private:      /// Reconfigure the OpenGL depth texture to use the given format and dimensions      void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height); +    /// Sets the OpenGL shader in accordance with the current PICA register state +    void SetShader(); +      /// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer      void SyncFramebuffer(); @@ -315,8 +310,8 @@ private:      TextureInfo fb_color_texture;      DepthTextureInfo fb_depth_texture; -    std::unordered_map<ShaderCacheKey, TEVShader> shader_cache; -    TEVShader* current_shader = nullptr; +    std::unordered_map<ShaderCacheKey, std::unique_ptr<TEVShader>> shader_cache; +    const TEVShader* current_shader = nullptr;      OGLVertexArray vertex_array;      OGLBuffer vertex_buffer; diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index 65034d40d..eb128966c 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h @@ -71,7 +71,7 @@ public:      /// Creates a new internal OpenGL resource and stores the handle      void Create(const char* vert_shader, const char* frag_shader) {          if (handle != 0) return; -        handle = ShaderUtil::LoadShaders(vert_shader, frag_shader); +        handle = GLShader::LoadProgram(vert_shader, frag_shader);      }      /// Deletes the internal OpenGL resource diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp new file mode 100644 index 000000000..059f127af --- /dev/null +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -0,0 +1,371 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "video_core/pica.h" +#include "video_core/renderer_opengl/gl_rasterizer.h" +#include "video_core/renderer_opengl/gl_shader_gen.h" + +namespace GLShader { + +static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) { +    return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace && +        stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace && +        stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous && +        stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous && +        stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor && +        stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha && +        stage.GetColorMultiplier() == 1 && +        stage.GetAlphaMultiplier() == 1); +} + +static void AppendSource(std::string& shader, Pica::Regs::TevStageConfig::Source source, const std::string& index_name) { +    using Source = Pica::Regs::TevStageConfig::Source; +    switch (source) { +    case Source::PrimaryColor: +        shader += "o[2]"; +        break; +    case Source::PrimaryFragmentColor: +        // HACK: Until we implement fragment lighting, use primary_color +        shader += "o[2]"; +        break; +    case Source::SecondaryFragmentColor: +        // HACK: Until we implement fragment lighting, use zero +        shader += "vec4(0.0, 0.0, 0.0, 0.0)"; +        break; +    case Source::Texture0: +        shader += "texture(tex[0], o[3].xy)"; +        break; +    case Source::Texture1: +        shader += "texture(tex[1], o[3].zw)"; +        break; +    case Source::Texture2: // TODO: Unverified +        shader += "texture(tex[2], o[5].zw)"; +        break; +    case Source::PreviousBuffer: +        shader += "g_combiner_buffer"; +        break; +    case Source::Constant: +        shader += "const_color[" + index_name + "]"; +        break; +    case Source::Previous: +        shader += "g_last_tex_env_out"; +        break; +    default: +        shader += "vec4(0.0)"; +        LOG_CRITICAL(Render_OpenGL, "Unknown source op %u", source); +        break; +    } +} + +static void AppendColorModifier(std::string& shader, Pica::Regs::TevStageConfig::ColorModifier modifier, +        Pica::Regs::TevStageConfig::Source source, const std::string& index_name) { +    using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier; +    switch (modifier) { +    case ColorModifier::SourceColor: +        AppendSource(shader, source, index_name); +        shader += ".rgb"; +        break; +    case ColorModifier::OneMinusSourceColor: +        shader += "vec3(1.0) - "; +        AppendSource(shader, source, index_name); +        shader += ".rgb"; +        break; +    case ColorModifier::SourceAlpha: +        AppendSource(shader, source, index_name); +        shader += ".aaa"; +        break; +    case ColorModifier::OneMinusSourceAlpha: +        shader += "vec3(1.0) - "; +        AppendSource(shader, source, index_name); +        shader += ".aaa"; +        break; +    case ColorModifier::SourceRed: +        AppendSource(shader, source, index_name); +        shader += ".rrr"; +        break; +    case ColorModifier::OneMinusSourceRed: +        shader += "vec3(1.0) - "; +        AppendSource(shader, source, index_name); +        shader += ".rrr"; +        break; +    case ColorModifier::SourceGreen: +        AppendSource(shader, source, index_name); +        shader += ".ggg"; +        break; +    case ColorModifier::OneMinusSourceGreen: +        shader += "vec3(1.0) - "; +        AppendSource(shader, source, index_name); +        shader += ".ggg"; +        break; +    case ColorModifier::SourceBlue: +        AppendSource(shader, source, index_name); +        shader += ".bbb"; +        break; +    case ColorModifier::OneMinusSourceBlue: +        shader += "vec3(1.0) - "; +        AppendSource(shader, source, index_name); +        shader += ".bbb"; +        break; +    default: +        shader += "vec3(0.0)"; +        LOG_CRITICAL(Render_OpenGL, "Unknown color modifier op %u", modifier); +        break; +    } +} + +static void AppendAlphaModifier(std::string& shader, Pica::Regs::TevStageConfig::AlphaModifier modifier, +        Pica::Regs::TevStageConfig::Source source, const std::string& index_name) { +    using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier; +    switch (modifier) { +    case AlphaModifier::SourceAlpha: +        AppendSource(shader, source, index_name); +        shader += ".a"; +        break; +    case AlphaModifier::OneMinusSourceAlpha: +        shader += "1.0 - "; +        AppendSource(shader, source, index_name); +        shader += ".a"; +        break; +    case AlphaModifier::SourceRed: +        AppendSource(shader, source, index_name); +        shader += ".r"; +        break; +    case AlphaModifier::OneMinusSourceRed: +        shader += "1.0 - "; +        AppendSource(shader, source, index_name); +        shader += ".r"; +        break; +    case AlphaModifier::SourceGreen: +        AppendSource(shader, source, index_name); +        shader += ".g"; +        break; +    case AlphaModifier::OneMinusSourceGreen: +        shader += "1.0 - "; +        AppendSource(shader, source, index_name); +        shader += ".g"; +        break; +    case AlphaModifier::SourceBlue: +        AppendSource(shader, source, index_name); +        shader += ".b"; +        break; +    case AlphaModifier::OneMinusSourceBlue: +        shader += "1.0 - "; +        AppendSource(shader, source, index_name); +        shader += ".b"; +        break; +    default: +        shader += "vec3(0.0)"; +        LOG_CRITICAL(Render_OpenGL, "Unknown alpha modifier op %u", modifier); +        break; +    } +} + +static void AppendColorCombiner(std::string& shader, Pica::Regs::TevStageConfig::Operation operation, +        const std::string& variable_name) { +    using Operation = Pica::Regs::TevStageConfig::Operation; + +    switch (operation) { +    case Operation::Replace: +        shader += variable_name + "[0]"; +        break; +    case Operation::Modulate: +        shader += variable_name + "[0] * " + variable_name + "[1]"; +        break; +    case Operation::Add: +        shader += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0))"; +        break; +    case Operation::AddSigned: +        shader += "clamp(" + variable_name + "[0] + " + variable_name + "[1] - vec3(0.5), vec3(0.0), vec3(1.0))"; +        break; +    case Operation::Lerp: +        shader += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])"; +        break; +    case Operation::Subtract: +        shader += "max(" + variable_name + "[0] - " + variable_name + "[1], vec3(0.0))"; +        break; +    case Operation::MultiplyThenAdd: +        shader += "min(" + variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2], vec3(1.0))"; +        break; +    case Operation::AddThenMultiply: +        shader += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]"; +        break; +    default: +        shader += "vec3(0.0)"; +        LOG_CRITICAL(Render_OpenGL, "Unknown color comb op %u", operation); +        break; +    } +} + +static void AppendAlphaCombiner(std::string& shader, Pica::Regs::TevStageConfig::Operation operation, +        const std::string& variable_name) { +    using Operation = Pica::Regs::TevStageConfig::Operation; +    switch (operation) { +    case Operation::Replace: +        shader += variable_name + "[0]"; +        break; +    case Operation::Modulate: +        shader += variable_name + "[0] * " + variable_name + "[1]"; +        break; +    case Operation::Add: +        shader += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0)"; +        break; +    case Operation::AddSigned: +        shader += "clamp(" + variable_name + "[0] + " + variable_name + "[1] - 0.5, 0.0, 1.0)"; +        break; +    case Operation::Lerp: +        shader += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])"; +        break; +    case Operation::Subtract: +        shader += "max(" + variable_name + "[0] - " + variable_name + "[1], 0.0)"; +        break; +    case Operation::MultiplyThenAdd: +        shader += "min(" + variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2], 1.0)"; +        break; +    case Operation::AddThenMultiply: +        shader += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]"; +        break; +    default: +        shader += "0.0"; +        LOG_CRITICAL(Render_OpenGL, "Unknown alpha combiner op %u", operation); +        break; +    } +} + +static void AppendAlphaTestCondition(std::string& shader, Pica::Regs::CompareFunc func) { +    using CompareFunc = Pica::Regs::CompareFunc; +    switch (func) { +    case CompareFunc::Never: +        shader += "true"; +        break; +    case CompareFunc::Always: +        shader += "false"; +        break; +    case CompareFunc::Equal: +        shader += "int(g_last_tex_env_out.a * 255.0f) != alphatest_ref"; +        break; +    case CompareFunc::NotEqual: +        shader += "int(g_last_tex_env_out.a * 255.0f) == alphatest_ref"; +        break; +    case CompareFunc::LessThan: +        shader += "int(g_last_tex_env_out.a * 255.0f) >= alphatest_ref"; +        break; +    case CompareFunc::LessThanOrEqual: +        shader += "int(g_last_tex_env_out.a * 255.0f) > alphatest_ref"; +        break; +    case CompareFunc::GreaterThan: +        shader += "int(g_last_tex_env_out.a * 255.0f) <= alphatest_ref"; +        break; +    case CompareFunc::GreaterThanOrEqual: +        shader += "int(g_last_tex_env_out.a * 255.0f) < alphatest_ref"; +        break; +    default: +        shader += "false"; +        LOG_CRITICAL(Render_OpenGL, "Unknown alpha test condition %u", func); +        break; +    } +} + +std::string GenerateFragmentShader(const ShaderCacheKey& config) { +    std::string shader = R"( +#version 150 core + +#define NUM_VTX_ATTR 7 +#define NUM_TEV_STAGES 6 + +in vec4 o[NUM_VTX_ATTR]; +out vec4 color; + +uniform int alphatest_ref; +uniform vec4 const_color[NUM_TEV_STAGES]; +uniform sampler2D tex[3]; + +uniform vec4 tev_combiner_buffer_color; + +void main(void) { +vec4 g_combiner_buffer = tev_combiner_buffer_color; +vec4 g_last_tex_env_out = vec4(0.0, 0.0, 0.0, 0.0); +)"; + +    // Do not do any sort of processing if it's obvious we're not going to pass the alpha test +    if (config.alpha_test_func == Pica::Regs::CompareFunc::Never) { +        shader += "discard;"; +        return shader; +    } + +    auto& tev_stages = config.tev_stages; +    for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { +        auto& tev_stage = tev_stages[tev_stage_index]; +        if (!IsPassThroughTevStage(tev_stage)) { +            std::string index_name = std::to_string(tev_stage_index); + +            shader += "vec3 color_results_" + index_name + "[3] = vec3[3]("; +            AppendColorModifier(shader, tev_stage.color_modifier1, tev_stage.color_source1, index_name); +            shader += ", "; +            AppendColorModifier(shader, tev_stage.color_modifier2, tev_stage.color_source2, index_name); +            shader += ", "; +            AppendColorModifier(shader, tev_stage.color_modifier3, tev_stage.color_source3, index_name); +            shader += ");\n"; + +            shader += "vec3 color_output_" + index_name + " = "; +            AppendColorCombiner(shader, tev_stage.color_op, "color_results_" + index_name); +            shader += ";\n"; + +            shader += "float alpha_results_" + index_name + "[3] = float[3]("; +            AppendAlphaModifier(shader, tev_stage.alpha_modifier1, tev_stage.alpha_source1, index_name); +            shader += ", "; +            AppendAlphaModifier(shader, tev_stage.alpha_modifier2, tev_stage.alpha_source2, index_name); +            shader += ", "; +            AppendAlphaModifier(shader, tev_stage.alpha_modifier3, tev_stage.alpha_source3, index_name); +            shader += ");\n"; + +            shader += "float alpha_output_" + index_name + " = "; +            AppendAlphaCombiner(shader, tev_stage.alpha_op, "alpha_results_" + index_name); +            shader += ";\n"; + +            shader += "g_last_tex_env_out = vec4(min(color_output_" + index_name + " * " + std::to_string(tev_stage.GetColorMultiplier()) + ".0, 1.0), min(alpha_output_" + index_name + " * " + std::to_string(tev_stage.GetAlphaMultiplier()) + ".0, 1.0));\n"; +        } + +        if (config.TevStageUpdatesCombinerBufferColor(tev_stage_index)) +            shader += "g_combiner_buffer.rgb = g_last_tex_env_out.rgb;\n"; + +        if (config.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)) +            shader += "g_combiner_buffer.a = g_last_tex_env_out.a;\n"; +    } + +    if (config.alpha_test_func != Pica::Regs::CompareFunc::Always) { +        shader += "if ("; +        AppendAlphaTestCondition(shader, config.alpha_test_func); +        shader += ") {\n discard;\n }\n"; +    } + +    shader += "color = g_last_tex_env_out;\n}"; +    return shader; +} + +std::string GenerateVertexShader() { +    static const std::string shader_str = R"( +#version 150 core + +#define NUM_VTX_ATTR 7 + +in vec4 vert_position; +in vec4 vert_color; +in vec2 vert_texcoords0; +in vec2 vert_texcoords1; +in vec2 vert_texcoords2; + +out vec4 o[NUM_VTX_ATTR]; + +void main() { +    o[2] = vert_color; +    o[3] = vec4(vert_texcoords0.xy, vert_texcoords1.xy); +    o[5] = vec4(0.0, 0.0, vert_texcoords2.xy); + +    gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w); +} +)"; +    return shader_str; +} + +} // namespace GLShaderGen diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h new file mode 100644 index 000000000..7fd18de6d --- /dev/null +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -0,0 +1,17 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <string> + +#include "video_core/renderer_opengl/gl_rasterizer.h" + +namespace GLShader { + +std::string GenerateVertexShader(); + +std::string GenerateFragmentShader(const ShaderCacheKey& config); + +} // namespace GLShader diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp index 8a6a51ad4..ce218b857 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.cpp +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp @@ -2,22 +2,15 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. - -#include "gl_shader_util.h" -#include "gl_rasterizer.h" -#include "common/logging/log.h" - -#include "video_core/pica.h" -  #include <algorithm>  #include <vector>  #include "common/logging/log.h"  #include "video_core/renderer_opengl/gl_shader_util.h" -namespace ShaderUtil { +namespace GLShader { -GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { +GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) {      // Create the shaders      GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); @@ -101,339 +94,4 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {      return program_id;  } -} - -namespace ShaderCache -{ - -static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) { -    return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace && -            stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace && -            stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous && -            stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous && -            stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor && -            stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha && -            stage.GetColorMultiplier() == 1 && -            stage.GetAlphaMultiplier() == 1); -} - -void AppendSource(std::string& shader, Pica::Regs::TevStageConfig::Source source, const std::string& index_name) { -    using Source = Pica::Regs::TevStageConfig::Source; -    switch (source) { -    case Source::PrimaryColor: -        shader += "o[2]"; -        break; -    case Source::PrimaryFragmentColor: -        // HACK: Until we implement fragment lighting, use primary_color -        shader += "o[2]"; -        break; -    case Source::SecondaryFragmentColor: -        // HACK: Until we implement fragment lighting, use zero -        shader += "vec4(0.0, 0.0, 0.0, 0.0)"; -        break; -    case Source::Texture0: -        shader += "texture(tex[0], o[3].xy)"; -        break; -    case Source::Texture1: -        shader += "texture(tex[1], o[3].zw)"; -        break; -    case Source::Texture2: // TODO: Unverified -        shader += "texture(tex[2], o[5].zw)"; -        break; -    case Source::PreviousBuffer: -        shader += "g_combiner_buffer"; -        break; -    case Source::Constant: -        shader += "const_color[" + index_name + "]"; -        break; -    case Source::Previous: -        shader += "g_last_tex_env_out"; -        break; -    default: -        shader += "vec4(0.0)"; -        LOG_CRITICAL(Render_OpenGL, "Unknown source op %u", source); -        break; -    } -} - -void AppendColorModifier(std::string& shader, Pica::Regs::TevStageConfig::ColorModifier modifier, Pica::Regs::TevStageConfig::Source source, const std::string& index_name) { -    using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier; -    switch (modifier) { -        case ColorModifier::SourceColor: -            AppendSource(shader, source, index_name); -            shader += ".rgb"; -            break; -        case ColorModifier::OneMinusSourceColor: -            shader += "vec3(1.0) - "; -            AppendSource(shader, source, index_name); -            shader += ".rgb"; -            break; -        case ColorModifier::SourceAlpha: -            AppendSource(shader, source, index_name); -            shader += ".aaa"; -            break; -        case ColorModifier::OneMinusSourceAlpha: -            shader += "vec3(1.0) - "; -            AppendSource(shader, source, index_name); -            shader += ".aaa"; -            break; -        case ColorModifier::SourceRed: -            AppendSource(shader, source, index_name); -            shader += ".rrr"; -            break; -        case ColorModifier::OneMinusSourceRed: -            shader += "vec3(1.0) - "; -            AppendSource(shader, source, index_name); -            shader += ".rrr"; -            break; -        case ColorModifier::SourceGreen: -            AppendSource(shader, source, index_name); -            shader += ".ggg"; -            break; -        case ColorModifier::OneMinusSourceGreen: -            shader += "vec3(1.0) - "; -            AppendSource(shader, source, index_name); -            shader += ".ggg"; -            break; -        case ColorModifier::SourceBlue: -            AppendSource(shader, source, index_name); -            shader += ".bbb"; -            break; -        case ColorModifier::OneMinusSourceBlue: -            shader += "vec3(1.0) - "; -            AppendSource(shader, source, index_name); -            shader += ".bbb"; -            break; -        default: -            shader += "vec3(0.0)"; -            LOG_CRITICAL(Render_OpenGL, "Unknown color modifier op %u", modifier); -            break; -    } -} - -void AppendAlphaModifier(std::string& shader, Pica::Regs::TevStageConfig::AlphaModifier modifier, Pica::Regs::TevStageConfig::Source source, const std::string& index_name) { -    using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier; -    switch (modifier) { -        case AlphaModifier::SourceAlpha: -            AppendSource(shader, source, index_name); -            shader += ".a"; -            break; -        case AlphaModifier::OneMinusSourceAlpha: -            shader += "1.0 - "; -            AppendSource(shader, source, index_name); -            shader += ".a"; -            break; -        case AlphaModifier::SourceRed: -            AppendSource(shader, source, index_name); -            shader += ".r"; -            break; -        case AlphaModifier::OneMinusSourceRed: -            shader += "1.0 - "; -            AppendSource(shader, source, index_name); -            shader += ".r"; -            break; -        case AlphaModifier::SourceGreen: -            AppendSource(shader, source, index_name); -            shader += ".g"; -            break; -        case AlphaModifier::OneMinusSourceGreen: -            shader += "1.0 - "; -            AppendSource(shader, source, index_name); -            shader += ".g"; -            break; -        case AlphaModifier::SourceBlue: -            AppendSource(shader, source, index_name); -            shader += ".b"; -            break; -        case AlphaModifier::OneMinusSourceBlue: -            shader += "1.0 - "; -            AppendSource(shader, source, index_name); -            shader += ".b"; -            break; -        default: -            shader += "vec3(0.0)"; -            LOG_CRITICAL(Render_OpenGL, "Unknown alpha modifier op %u", modifier); -            break; -    } -} - -void AppendColorCombiner(std::string& shader, Pica::Regs::TevStageConfig::Operation operation, const std::string& variable_name) { -    using Operation = Pica::Regs::TevStageConfig::Operation; - -    switch (operation) { -        case Operation::Replace: -            shader += variable_name + "[0]"; -            break; -        case Operation::Modulate: -            shader += variable_name + "[0] * " + variable_name + "[1]"; -            break; -        case Operation::Add: -            shader += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0))"; -            break; -        case Operation::AddSigned: -            shader += "clamp(" + variable_name + "[0] + " + variable_name + "[1] - vec3(0.5), vec3(0.0), vec3(1.0))"; -            break; -        case Operation::Lerp: -            shader += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])"; -            break; -        case Operation::Subtract: -            shader += "max(" + variable_name + "[0] - " + variable_name + "[1], vec3(0.0))"; -            break; -        case Operation::MultiplyThenAdd: -            shader += "min(" + variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2], vec3(1.0))"; -            break; -        case Operation::AddThenMultiply: -            shader += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]"; -            break; -        default: -            shader += "vec3(0.0)"; -            LOG_CRITICAL(Render_OpenGL, "Unknown color comb op %u", operation); -            break; -    } -} - -void AppendAlphaCombiner(std::string& shader, Pica::Regs::TevStageConfig::Operation operation, const std::string& variable_name) { -    using Operation = Pica::Regs::TevStageConfig::Operation; -    switch (operation) { -        case Operation::Replace: -            shader += variable_name + "[0]"; -            break; -        case Operation::Modulate: -            shader += variable_name + "[0] * " + variable_name + "[1]"; -            break; -        case Operation::Add: -            shader += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0)"; -            break; -        case Operation::AddSigned: -            shader += "clamp(" + variable_name + "[0] + " + variable_name + "[1] - 0.5, 0.0, 1.0)"; -            break; -        case Operation::Lerp: -            shader += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])"; -            break; -        case Operation::Subtract: -            shader += "max(" + variable_name + "[0] - " + variable_name + "[1], 0.0)"; -            break; -        case Operation::MultiplyThenAdd: -            shader += "min(" + variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2], 1.0)"; -            break; -        case Operation::AddThenMultiply: -            shader += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]"; -            break; -        default: -            shader += "0.0"; -            LOG_CRITICAL(Render_OpenGL, "Unknown alpha combiner op %u", operation); -            break; -    } -} - -void AppendAlphaTestCondition(std::string& shader, Pica::Regs::CompareFunc func) { -    using CompareFunc = Pica::Regs::CompareFunc; -    switch (func) { -        case CompareFunc::Never: -            shader += "true"; -            break; -        case CompareFunc::Always: -            shader += "false"; -            break; -        case CompareFunc::Equal: -            shader += "int(g_last_tex_env_out.a * 255.0f) != alphatest_ref"; -            break; -        case CompareFunc::NotEqual: -            shader += "int(g_last_tex_env_out.a * 255.0f) == alphatest_ref"; -            break; -        case CompareFunc::LessThan: -            shader += "int(g_last_tex_env_out.a * 255.0f) >= alphatest_ref"; -            break; -        case CompareFunc::LessThanOrEqual: -            shader += "int(g_last_tex_env_out.a * 255.0f) > alphatest_ref"; -            break; -        case CompareFunc::GreaterThan: -            shader += "int(g_last_tex_env_out.a * 255.0f) <= alphatest_ref"; -            break; -        case CompareFunc::GreaterThanOrEqual: -            shader += "int(g_last_tex_env_out.a * 255.0f) < alphatest_ref"; -            break; -        default: -            shader += "false"; -            LOG_CRITICAL(Render_OpenGL, "Unknown alpha test condition %u", func); -            break; -    } -} - -std::string GenerateFragmentShader(const ShaderCacheKey& config) { -    std::string shader = R"( -#version 150 core - -#define NUM_VTX_ATTR 7 -#define NUM_TEV_STAGES 6 - -in vec4 o[NUM_VTX_ATTR]; -out vec4 color; - -uniform int alphatest_ref; -uniform vec4 const_color[NUM_TEV_STAGES]; -uniform sampler2D tex[3]; - -uniform vec4 tev_combiner_buffer_color; - -void main(void) { -    vec4 g_combiner_buffer = tev_combiner_buffer_color; -    vec4 g_last_tex_env_out = vec4(0.0, 0.0, 0.0, 0.0); -)"; - -    // Do not do any sort of processing if it's obvious we're not going to pass the alpha test -    if (config.alpha_test_func == Pica::Regs::CompareFunc::Never) { -        shader += "discard;"; -        return shader; -    } - -    auto& tev_stages = config.tev_stages; -    for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { -        auto& tev_stage = tev_stages[tev_stage_index]; -        if (!IsPassThroughTevStage(tev_stage)) { -            std::string index_name = std::to_string(tev_stage_index); - -            shader += "vec3 color_results_" + index_name + "[3] = vec3[3]("; -            AppendColorModifier(shader, tev_stage.color_modifier1, tev_stage.color_source1, index_name); -            shader += ", "; -            AppendColorModifier(shader, tev_stage.color_modifier2, tev_stage.color_source2, index_name); -            shader += ", "; -            AppendColorModifier(shader, tev_stage.color_modifier3, tev_stage.color_source3, index_name); -            shader += ");\n"; - -            shader += "vec3 color_output_" + index_name + " = "; -            AppendColorCombiner(shader, tev_stage.color_op, "color_results_" + index_name); -            shader += ";\n"; - -            shader += "float alpha_results_" + index_name + "[3] = float[3]("; -            AppendAlphaModifier(shader, tev_stage.alpha_modifier1, tev_stage.alpha_source1, index_name); -            shader += ", "; -            AppendAlphaModifier(shader, tev_stage.alpha_modifier2, tev_stage.alpha_source2, index_name); -            shader += ", "; -            AppendAlphaModifier(shader, tev_stage.alpha_modifier3, tev_stage.alpha_source3, index_name); -            shader += ");\n"; - -            shader += "float alpha_output_" + index_name + " = "; -            AppendAlphaCombiner(shader, tev_stage.alpha_op, "alpha_results_" + index_name); -            shader += ";\n"; - -            shader += "g_last_tex_env_out = vec4(min(color_output_" + index_name + " * " + std::to_string(tev_stage.GetColorMultiplier()) + ".0, 1.0), min(alpha_output_" + index_name + " * " + std::to_string(tev_stage.GetAlphaMultiplier()) + ".0, 1.0));\n"; -        } - -        if (config.TevStageUpdatesCombinerBufferColor(tev_stage_index)) -            shader += "g_combiner_buffer.rgb = g_last_tex_env_out.rgb;\n"; - -        if (config.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)) -            shader += "g_combiner_buffer.a = g_last_tex_env_out.a;\n"; -    } - -    if (config.alpha_test_func != Pica::Regs::CompareFunc::Always) { -        shader += "if ("; -        AppendAlphaTestCondition(shader, config.alpha_test_func); -        shader += ") {\n discard;\n }\n"; -    } - -    shader += "color = g_last_tex_env_out;\n}"; -    return shader; -} -} +} // namespace GLShader diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h index ca62c83ba..6e2d007f8 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.h +++ b/src/video_core/renderer_opengl/gl_shader_util.h @@ -6,7 +6,7 @@  #include <glad/glad.h> -namespace ShaderUtil { +namespace GLShader {  enum Attributes {      ATTRIBUTE_POSITION  = 0, @@ -14,6 +14,6 @@ enum Attributes {      ATTRIBUTE_TEXCOORDS = 2,  }; -GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path); +GLuint LoadProgram(const char* vertex_file_path, const char* fragment_file_path); -} +} // namespace diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h deleted file mode 100644 index 2ba2c6b0f..000000000 --- a/src/video_core/renderer_opengl/gl_shaders.h +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -namespace GLShaders { - -const char g_vertex_shader[] = R"( -#version 150 core - -in vec2 vert_position; -in vec2 vert_tex_coord; -out vec2 frag_tex_coord; - -// This is a truncated 3x3 matrix for 2D transformations: -// The upper-left 2x2 submatrix performs scaling/rotation/mirroring. -// The third column performs translation. -// The third row could be used for projection, which we don't need in 2D. It hence is assumed to -// implicitly be [0, 0, 1] -uniform mat3x2 modelview_matrix; - -void main() { -    // Multiply input position by the rotscale part of the matrix and then manually translate by -    // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector -    // to `vec3(vert_position.xy, 1.0)` -    gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); -    frag_tex_coord = vert_tex_coord; -} -)"; - -const char g_fragment_shader[] = R"( -#version 150 core - -in vec2 frag_tex_coord; -out vec4 color; - -uniform sampler2D color_texture; - -void main() { -    color = texture(color_texture, frag_tex_coord); -} -)"; - -const char g_vertex_shader_hw[] = R"( -#version 150 core - -#define NUM_VTX_ATTR 7 - -in vec4 vert_position; -in vec4 vert_color; -in vec2 vert_texcoords0; -in vec2 vert_texcoords1; -in vec2 vert_texcoords2; - -out vec4 o[NUM_VTX_ATTR]; - -void main() { -    o[2] = vert_color; -    o[3] = vec4(vert_texcoords0.xy, vert_texcoords1.xy); -    o[5] = vec4(0.0, 0.0, vert_texcoords2.xy); - -    gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w); -} -)"; - -// TODO: Create a shader constructor and cache that builds this program with minimal conditionals instead of using tev_cfg uniforms -const char g_fragment_shader_hw[] = R"( -#version 150 core - -#define NUM_VTX_ATTR 7 -#define NUM_TEV_STAGES 6 - -#define SOURCE_PRIMARYCOLOR           0x0 -#define SOURCE_PRIMARYFRAGMENTCOLOR   0x1 -#define SOURCE_SECONDARYFRAGMENTCOLOR 0x2 -#define SOURCE_TEXTURE0               0x3 -#define SOURCE_TEXTURE1               0x4 -#define SOURCE_TEXTURE2               0x5 -#define SOURCE_TEXTURE3               0x6 -#define SOURCE_PREVIOUSBUFFER         0xd -#define SOURCE_CONSTANT               0xe -#define SOURCE_PREVIOUS               0xf - -#define COLORMODIFIER_SOURCECOLOR         0x0 -#define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1 -#define COLORMODIFIER_SOURCEALPHA         0x2 -#define COLORMODIFIER_ONEMINUSSOURCEALPHA 0x3 -#define COLORMODIFIER_SOURCERED           0x4 -#define COLORMODIFIER_ONEMINUSSOURCERED   0x5 -#define COLORMODIFIER_SOURCEGREEN         0x8 -#define COLORMODIFIER_ONEMINUSSOURCEGREEN 0x9 -#define COLORMODIFIER_SOURCEBLUE          0xc -#define COLORMODIFIER_ONEMINUSSOURCEBLUE  0xd - -#define ALPHAMODIFIER_SOURCEALPHA         0x0 -#define ALPHAMODIFIER_ONEMINUSSOURCEALPHA 0x1 -#define ALPHAMODIFIER_SOURCERED           0x2 -#define ALPHAMODIFIER_ONEMINUSSOURCERED   0x3 -#define ALPHAMODIFIER_SOURCEGREEN         0x4 -#define ALPHAMODIFIER_ONEMINUSSOURCEGREEN 0x5 -#define ALPHAMODIFIER_SOURCEBLUE          0x6 -#define ALPHAMODIFIER_ONEMINUSSOURCEBLUE  0x7 - -#define OPERATION_REPLACE         0 -#define OPERATION_MODULATE        1 -#define OPERATION_ADD             2 -#define OPERATION_ADDSIGNED       3 -#define OPERATION_LERP            4 -#define OPERATION_SUBTRACT        5 -#define OPERATION_MULTIPLYTHENADD 8 -#define OPERATION_ADDTHENMULTIPLY 9 - -#define COMPAREFUNC_NEVER              0 -#define COMPAREFUNC_ALWAYS             1 -#define COMPAREFUNC_EQUAL              2 -#define COMPAREFUNC_NOTEQUAL           3 -#define COMPAREFUNC_LESSTHAN           4 -#define COMPAREFUNC_LESSTHANOREQUAL    5 -#define COMPAREFUNC_GREATERTHAN        6 -#define COMPAREFUNC_GREATERTHANOREQUAL 7 - -in vec4 o[NUM_VTX_ATTR]; -out vec4 color; - -uniform bool alphatest_enabled; -uniform int alphatest_func; -uniform float alphatest_ref; - -uniform sampler2D tex[3]; - -uniform vec4 tev_combiner_buffer_color; - -struct TEVConfig -{ -    bool enabled; -    ivec3 color_sources; -    ivec3 alpha_sources; -    ivec3 color_modifiers; -    ivec3 alpha_modifiers; -    ivec2 color_alpha_op; -    ivec2 color_alpha_multiplier; -    vec4 const_color; -    bvec2 updates_combiner_buffer_color_alpha; -}; - -uniform TEVConfig tev_cfgs[NUM_TEV_STAGES]; - -vec4 g_combiner_buffer; -vec4 g_last_tex_env_out; -vec4 g_const_color; - -vec4 GetSource(int source) { -    if (source == SOURCE_PRIMARYCOLOR) { -        return o[2]; -    } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) { -        // HACK: Until we implement fragment lighting, use primary_color -        return o[2]; -    } else if (source == SOURCE_SECONDARYFRAGMENTCOLOR) { -        // HACK: Until we implement fragment lighting, use zero -        return vec4(0.0, 0.0, 0.0, 0.0); -    } else if (source == SOURCE_TEXTURE0) { -        return texture(tex[0], o[3].xy); -    } else if (source == SOURCE_TEXTURE1) { -        return texture(tex[1], o[3].zw); -    } else if (source == SOURCE_TEXTURE2) { -        // TODO: Unverified -        return texture(tex[2], o[5].zw); -    } else if (source == SOURCE_TEXTURE3) { -        // TODO: no 4th texture? -    } else if (source == SOURCE_PREVIOUSBUFFER) { -        return g_combiner_buffer; -    } else if (source == SOURCE_CONSTANT) { -        return g_const_color; -    } else if (source == SOURCE_PREVIOUS) { -        return g_last_tex_env_out; -    } - -    return vec4(0.0); -} - -vec3 GetColorModifier(int factor, vec4 color) { -    if (factor == COLORMODIFIER_SOURCECOLOR) { -        return color.rgb; -    } else if (factor == COLORMODIFIER_ONEMINUSSOURCECOLOR) { -        return vec3(1.0) - color.rgb; -    } else if (factor == COLORMODIFIER_SOURCEALPHA) { -        return color.aaa; -    } else if (factor == COLORMODIFIER_ONEMINUSSOURCEALPHA) { -        return vec3(1.0) - color.aaa; -    } else if (factor == COLORMODIFIER_SOURCERED) { -        return color.rrr; -    } else if (factor == COLORMODIFIER_ONEMINUSSOURCERED) { -        return vec3(1.0) - color.rrr; -    } else if (factor == COLORMODIFIER_SOURCEGREEN) { -        return color.ggg; -    } else if (factor == COLORMODIFIER_ONEMINUSSOURCEGREEN) { -        return vec3(1.0) - color.ggg; -    } else if (factor == COLORMODIFIER_SOURCEBLUE) { -        return color.bbb; -    } else if (factor == COLORMODIFIER_ONEMINUSSOURCEBLUE) { -        return vec3(1.0) - color.bbb; -    } - -    return vec3(0.0); -} - -float GetAlphaModifier(int factor, vec4 color) { -    if (factor == ALPHAMODIFIER_SOURCEALPHA) { -        return color.a; -    } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEALPHA) { -        return 1.0 - color.a; -    } else if (factor == ALPHAMODIFIER_SOURCERED) { -        return color.r; -    } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCERED) { -        return 1.0 - color.r; -    } else if (factor == ALPHAMODIFIER_SOURCEGREEN) { -        return color.g; -    } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEGREEN) { -        return 1.0 - color.g; -    } else if (factor == ALPHAMODIFIER_SOURCEBLUE) { -        return color.b; -    } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEBLUE) { -        return 1.0 - color.b; -    } - -    return 0.0; -} - -vec3 ColorCombine(int op, vec3 color[3]) { -    if (op == OPERATION_REPLACE) { -        return color[0]; -    } else if (op == OPERATION_MODULATE) { -        return color[0] * color[1]; -    } else if (op == OPERATION_ADD) { -        return min(color[0] + color[1], 1.0); -    } else if (op == OPERATION_ADDSIGNED) { -        return clamp(color[0] + color[1] - vec3(0.5), 0.0, 1.0); -    } else if (op == OPERATION_LERP) { -        return color[0] * color[2] + color[1] * (vec3(1.0) - color[2]); -    } else if (op == OPERATION_SUBTRACT) { -        return max(color[0] - color[1], 0.0); -    } else if (op == OPERATION_MULTIPLYTHENADD) { -        return min(color[0] * color[1] + color[2], 1.0); -    } else if (op == OPERATION_ADDTHENMULTIPLY) { -        return min(color[0] + color[1], 1.0) * color[2]; -    } - -    return vec3(0.0); -} - -float AlphaCombine(int op, float alpha[3]) { -    if (op == OPERATION_REPLACE) { -        return alpha[0]; -    } else if (op == OPERATION_MODULATE) { -        return alpha[0] * alpha[1]; -    } else if (op == OPERATION_ADD) { -        return min(alpha[0] + alpha[1], 1.0); -    } else if (op == OPERATION_ADDSIGNED) { -        return clamp(alpha[0] + alpha[1] - 0.5, 0.0, 1.0); -    } else if (op == OPERATION_LERP) { -        return alpha[0] * alpha[2] + alpha[1] * (1.0 - alpha[2]); -    } else if (op == OPERATION_SUBTRACT) { -        return max(alpha[0] - alpha[1], 0.0); -    } else if (op == OPERATION_MULTIPLYTHENADD) { -        return min(alpha[0] * alpha[1] + alpha[2], 1.0); -    } else if (op == OPERATION_ADDTHENMULTIPLY) { -        return min(alpha[0] + alpha[1], 1.0) * alpha[2]; -    } - -    return 0.0; -} - -void main(void) { -    g_combiner_buffer = tev_combiner_buffer_color; - -    for (int tex_env_idx = 0; tex_env_idx < NUM_TEV_STAGES; ++tex_env_idx) { -        if (tev_cfgs[tex_env_idx].enabled) { -            g_const_color = tev_cfgs[tex_env_idx].const_color; - -            vec3 color_results[3] = vec3[3](GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.x, GetSource(tev_cfgs[tex_env_idx].color_sources.x)), -                                            GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.y, GetSource(tev_cfgs[tex_env_idx].color_sources.y)), -                                            GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.z, GetSource(tev_cfgs[tex_env_idx].color_sources.z))); -            vec3 color_output = ColorCombine(tev_cfgs[tex_env_idx].color_alpha_op.x, color_results); - -            float alpha_results[3] = float[3](GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.x, GetSource(tev_cfgs[tex_env_idx].alpha_sources.x)), -                                              GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.y, GetSource(tev_cfgs[tex_env_idx].alpha_sources.y)), -                                              GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.z, GetSource(tev_cfgs[tex_env_idx].alpha_sources.z))); -            float alpha_output = AlphaCombine(tev_cfgs[tex_env_idx].color_alpha_op.y, alpha_results); - -            g_last_tex_env_out = vec4(min(color_output * tev_cfgs[tex_env_idx].color_alpha_multiplier.x, 1.0), min(alpha_output * tev_cfgs[tex_env_idx].color_alpha_multiplier.y, 1.0)); -        } - -        if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.x) { -            g_combiner_buffer.rgb = g_last_tex_env_out.rgb; -        } - -        if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.y) { -            g_combiner_buffer.a = g_last_tex_env_out.a; -        } -    } - -    if (alphatest_enabled) { -        if (alphatest_func == COMPAREFUNC_NEVER) { -            discard; -        } else if (alphatest_func == COMPAREFUNC_ALWAYS) { - -        } else if (alphatest_func == COMPAREFUNC_EQUAL) { -            if (g_last_tex_env_out.a != alphatest_ref) { -                discard; -            } -        } else if (alphatest_func == COMPAREFUNC_NOTEQUAL) { -            if (g_last_tex_env_out.a == alphatest_ref) { -                discard; -            } -        } else if (alphatest_func == COMPAREFUNC_LESSTHAN) { -            if (g_last_tex_env_out.a >= alphatest_ref) { -                discard; -            } -        } else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) { -            if (g_last_tex_env_out.a > alphatest_ref) { -                discard; -            } -        } else if (alphatest_func == COMPAREFUNC_GREATERTHAN) { -            if (g_last_tex_env_out.a <= alphatest_ref) { -                discard; -            } -        } else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) { -            if (g_last_tex_env_out.a < alphatest_ref) { -                discard; -            } -        } -    } - -    color = g_last_tex_env_out; -} -)"; - -} diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index f1313b54f..ac0a058db 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -21,9 +21,44 @@  #include "video_core/debug_utils/debug_utils.h"  #include "video_core/renderer_opengl/gl_rasterizer.h"  #include "video_core/renderer_opengl/gl_shader_util.h" -#include "video_core/renderer_opengl/gl_shaders.h"  #include "video_core/renderer_opengl/renderer_opengl.h" +static const char vertex_shader[] = R"( +#version 150 core + +in vec2 vert_position; +in vec2 vert_tex_coord; +out vec2 frag_tex_coord; + +// This is a truncated 3x3 matrix for 2D transformations: +// The upper-left 2x2 submatrix performs scaling/rotation/mirroring. +// The third column performs translation. +// The third row could be used for projection, which we don't need in 2D. It hence is assumed to +// implicitly be [0, 0, 1] +uniform mat3x2 modelview_matrix; + +void main() { +    // Multiply input position by the rotscale part of the matrix and then manually translate by +    // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector +    // to `vec3(vert_position.xy, 1.0)` +    gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); +    frag_tex_coord = vert_tex_coord; +} +)"; + +static const char fragment_shader[] = R"( +#version 150 core + +in vec2 frag_tex_coord; +out vec4 color; + +uniform sampler2D color_texture; + +void main() { +    color = texture(color_texture, frag_tex_coord); +} +)"; +  /**   * Vertex structure that the drawn screen rectangles are composed of.   */ @@ -207,7 +242,7 @@ void RendererOpenGL::InitOpenGLObjects() {      glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f);      // Link shaders and get variable locations -    program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader); +    program_id = GLShader::LoadProgram(vertex_shader, fragment_shader);      uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix");      uniform_color_texture = glGetUniformLocation(program_id, "color_texture");      attrib_position = glGetAttribLocation(program_id, "vert_position"); | 
