diff options
| -rw-r--r-- | src/video_core/renderer_opengl/gl_device.cpp | 43 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_device.h | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 9 | 
3 files changed, 43 insertions, 15 deletions
| diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 03d434b28..4f59a87b4 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -14,12 +14,22 @@  namespace OpenGL {  namespace { +  template <typename T>  T GetInteger(GLenum pname) {      GLint temporary;      glGetIntegerv(pname, &temporary);      return static_cast<T>(temporary);  } + +bool TestProgram(const GLchar* glsl) { +    const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl)}; +    GLint link_status; +    glGetProgramiv(shader, GL_LINK_STATUS, &link_status); +    glDeleteProgram(shader); +    return link_status == GL_TRUE; +} +  } // Anonymous namespace  Device::Device() { @@ -32,6 +42,11 @@ Device::Device() {      has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;      has_variable_aoffi = TestVariableAoffi();      has_component_indexing_bug = TestComponentIndexingBug(); +    has_precise_bug = TestPreciseBug(); + +    LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi); +    LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug); +    LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug);  }  Device::Device(std::nullptr_t) { @@ -42,30 +57,21 @@ Device::Device(std::nullptr_t) {      has_vertex_viewport_layer = true;      has_variable_aoffi = true;      has_component_indexing_bug = false; +    has_precise_bug = false;  }  bool Device::TestVariableAoffi() { -    const GLchar* AOFFI_TEST = R"(#version 430 core +    return TestProgram(R"(#version 430 core  // This is a unit test, please ignore me on apitrace bug reports.  uniform sampler2D tex;  uniform ivec2 variable_offset;  out vec4 output_attribute;  void main() {      output_attribute = textureOffset(tex, vec2(0), variable_offset); -} -)"; -    const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &AOFFI_TEST)}; -    GLint link_status{}; -    glGetProgramiv(shader, GL_LINK_STATUS, &link_status); -    glDeleteProgram(shader); - -    const bool supported{link_status == GL_TRUE}; -    LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", supported); -    return supported; +})");  }  bool Device::TestComponentIndexingBug() { -    constexpr char log_message[] = "Renderer_ComponentIndexingBug: {}";      const GLchar* COMPONENT_TEST = R"(#version 430 core  layout (std430, binding = 0) buffer OutputBuffer {      uint output_value; @@ -105,12 +111,21 @@ void main() {          GLuint result;          glGetNamedBufferSubData(ssbo.handle, 0, sizeof(result), &result);          if (result != values.at(index)) { -            LOG_INFO(Render_OpenGL, log_message, true);              return true;          }      } -    LOG_INFO(Render_OpenGL, log_message, false);      return false;  } +bool Device::TestPreciseBug() { +    return !TestProgram(R"(#version 430 core +in vec3 coords; +out float out_value; +uniform sampler2DShadow tex; +void main() { +    precise float tmp_value = vec4(texture(tex, coords)).x; +    out_value = tmp_value; +})"); +} +  } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index 3ef7c6dd8..ba6dcd3be 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h @@ -46,9 +46,14 @@ public:          return has_component_indexing_bug;      } +    bool HasPreciseBug() const { +        return has_precise_bug; +    } +  private:      static bool TestVariableAoffi();      static bool TestComponentIndexingBug(); +    static bool TestPreciseBug();      std::size_t uniform_buffer_alignment{};      std::size_t shader_storage_alignment{}; @@ -58,6 +63,7 @@ private:      bool has_vertex_viewport_layer{};      bool has_variable_aoffi{};      bool has_component_indexing_bug{}; +    bool has_precise_bug{};  };  } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 9e050347a..50aa73d0e 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -957,8 +957,15 @@ private:          if (!IsPrecise(operation)) {              return {std::move(value), type};          } +        // Old Nvidia drivers have a bug with precise and texture sampling. These are more likely to +        // be found in fragment shaders, so we disable precise there. There are vertex shaders that +        // also fail to build but nobody seems to care about those. +        // Note: Only bugged drivers will skip precise. +        const bool disable_precise = device.HasPreciseBug() && stage == ProgramType::Fragment; +          std::string temporary = code.GenerateTemporary(); -        code.AddLine("precise {} {} = {};", GetTypeString(type), temporary, value); +        code.AddLine("{}{} {} = {};", disable_precise ? "" : "precise ", GetTypeString(type), +                     temporary, value);          return {std::move(temporary), type};      } | 
