gl_device: Disable precise in fragment shaders on bugged drivers

This commit is contained in:
ReinUsesLisp 2019-08-31 03:03:35 -03:00
parent 03276e7490
commit 9cf52d027d
3 changed files with 43 additions and 15 deletions

View file

@ -14,12 +14,22 @@
namespace OpenGL { namespace OpenGL {
namespace { namespace {
template <typename T> template <typename T>
T GetInteger(GLenum pname) { T GetInteger(GLenum pname) {
GLint temporary; GLint temporary;
glGetIntegerv(pname, &temporary); glGetIntegerv(pname, &temporary);
return static_cast<T>(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 } // Anonymous namespace
Device::Device() { Device::Device() {
@ -32,6 +42,11 @@ Device::Device() {
has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array; has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
has_variable_aoffi = TestVariableAoffi(); has_variable_aoffi = TestVariableAoffi();
has_component_indexing_bug = TestComponentIndexingBug(); 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) { Device::Device(std::nullptr_t) {
@ -42,30 +57,21 @@ Device::Device(std::nullptr_t) {
has_vertex_viewport_layer = true; has_vertex_viewport_layer = true;
has_variable_aoffi = true; has_variable_aoffi = true;
has_component_indexing_bug = false; has_component_indexing_bug = false;
has_precise_bug = false;
} }
bool Device::TestVariableAoffi() { 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. // This is a unit test, please ignore me on apitrace bug reports.
uniform sampler2D tex; uniform sampler2D tex;
uniform ivec2 variable_offset; uniform ivec2 variable_offset;
out vec4 output_attribute; out vec4 output_attribute;
void main() { void main() {
output_attribute = textureOffset(tex, vec2(0), variable_offset); 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() { bool Device::TestComponentIndexingBug() {
constexpr char log_message[] = "Renderer_ComponentIndexingBug: {}";
const GLchar* COMPONENT_TEST = R"(#version 430 core const GLchar* COMPONENT_TEST = R"(#version 430 core
layout (std430, binding = 0) buffer OutputBuffer { layout (std430, binding = 0) buffer OutputBuffer {
uint output_value; uint output_value;
@ -105,12 +111,21 @@ void main() {
GLuint result; GLuint result;
glGetNamedBufferSubData(ssbo.handle, 0, sizeof(result), &result); glGetNamedBufferSubData(ssbo.handle, 0, sizeof(result), &result);
if (result != values.at(index)) { if (result != values.at(index)) {
LOG_INFO(Render_OpenGL, log_message, true);
return true; return true;
} }
} }
LOG_INFO(Render_OpenGL, log_message, false);
return 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 } // namespace OpenGL

View file

@ -46,9 +46,14 @@ public:
return has_component_indexing_bug; return has_component_indexing_bug;
} }
bool HasPreciseBug() const {
return has_precise_bug;
}
private: private:
static bool TestVariableAoffi(); static bool TestVariableAoffi();
static bool TestComponentIndexingBug(); static bool TestComponentIndexingBug();
static bool TestPreciseBug();
std::size_t uniform_buffer_alignment{}; std::size_t uniform_buffer_alignment{};
std::size_t shader_storage_alignment{}; std::size_t shader_storage_alignment{};
@ -58,6 +63,7 @@ private:
bool has_vertex_viewport_layer{}; bool has_vertex_viewport_layer{};
bool has_variable_aoffi{}; bool has_variable_aoffi{};
bool has_component_indexing_bug{}; bool has_component_indexing_bug{};
bool has_precise_bug{};
}; };
} // namespace OpenGL } // namespace OpenGL

View file

@ -957,8 +957,15 @@ private:
if (!IsPrecise(operation)) { if (!IsPrecise(operation)) {
return {std::move(value), type}; 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(); 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}; return {std::move(temporary), type};
} }