Skip to content

Commit e2f90c1

Browse files
committed
opengl: Work around buggy booleans in Mesa
Mesa 10.2.9 and older versions are oblivious to a behavior change in the CMP instruction on Intel CPU SandyBridge and newer. On SandyBridge and newer ones, CMP instruction sets all bits to one in dst register (-1) as boolean true value. Before that, only the LSB is set to one with other bits being undefined. Mesa 10.2.9 and older use XOR instruction on the LSB for the logical not operator, which produces -2 as boolean value for !true. The value is then used by SEL instruction in mix(), which compares the value with zero and does not clear high bits before that, selecting wrong components. A macro MESA_BUGGY_BOOL_CMP is added to forcibly convert -1 to 1 for Mesa 10.2.9 and older before logical not result is used for mix(). The rest of comparison operators and conditionals are safe from this behavior. I could not independently reproduce this behavior in a seperate standalone problem. It is possibly because instruction generation varies from optimization. This behavior was fixed in Mesa upstream 2e51dc838be177a09f60958da7d1d904f1038d9c, only appearing in 10.3+.
1 parent 2b8d356 commit e2f90c1

File tree

7 files changed

+40
-22
lines changed

7 files changed

+40
-22
lines changed

examples/protonect/src/opengl_depth_packet_processor.cpp

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <fstream>
3535
#include <string>
3636
#include <map>
37+
#include <cstdlib>
3738

3839
#include <stdint.h>
3940

@@ -124,27 +125,53 @@ struct ShaderProgram : public WithOpenGLBindings
124125

125126
char error_buffer[2048];
126127

128+
std::string defines;
129+
bool is_mesa_checked;
130+
127131
ShaderProgram() :
128132
program(0),
133+
is_mesa_checked(false),
129134
vertex_shader(0),
130135
fragment_shader(0)
131136
{
132137
}
133138

139+
void checkMesaBug()
140+
{
141+
if (is_mesa_checked)
142+
return;
143+
is_mesa_checked = true;
144+
std::string ren((const char*)glGetString(GL_RENDERER));
145+
std::string ver((const char*)glGetString(GL_VERSION));
146+
if (ren.find("Mesa DRI Intel") == 0)
147+
{
148+
size_t mesa_pos = ver.rfind("Mesa ");
149+
if (mesa_pos != std::string::npos)
150+
{
151+
double mesa_ver = atof(ver.substr(mesa_pos + 5).c_str());
152+
if (mesa_ver < 10.3)
153+
{
154+
defines += "#define MESA_BUGGY_BOOL_CMP\n";
155+
LOG_WARNING << "Working around buggy boolean instructions in your Mesa driver. Mesa DRI 10.3+ is recommended.";
156+
}
157+
}
158+
}
159+
}
160+
134161
void setVertexShader(const std::string& src)
135162
{
136-
const char* src_ = src.c_str();
137-
int length_ = src.length();
163+
checkMesaBug();
164+
const GLchar *sources[] = {"#version 140\n", defines.c_str(), src.c_str()};
138165
vertex_shader = gl()->glCreateShader(GL_VERTEX_SHADER);
139-
gl()->glShaderSource(vertex_shader, 1, &src_, &length_);
166+
gl()->glShaderSource(vertex_shader, 3, sources, NULL);
140167
}
141168

142169
void setFragmentShader(const std::string& src)
143170
{
144-
const char* src_ = src.c_str();
145-
int length_ = src.length();
171+
checkMesaBug();
172+
const GLchar *sources[] = {"#version 140\n", defines.c_str(), src.c_str()};
146173
fragment_shader = gl()->glCreateShader(GL_FRAGMENT_SHADER);
147-
gl()->glShaderSource(fragment_shader, 1, &src_, &length_);
174+
gl()->glShaderSource(fragment_shader, 3, sources, NULL);
148175
}
149176

150177
void bindFragDataLocation(const std::string &name, int output)

examples/protonect/src/shader/debug.fs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#version 140
2-
31
uniform sampler2DRect Data;
42

53
in vec2 TexCoord;
@@ -11,4 +9,4 @@ void main(void)
119
ivec2 uv = ivec2(TexCoord.x, TexCoord.y);
1210

1311
Color = texelFetch(Data, uv);
14-
}
12+
}
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#version 140
2-
31
in vec2 InputPosition;
42
in vec2 InputTexCoord;
53

@@ -9,4 +7,4 @@ void main(void)
97
{
108
gl_Position = vec4(InputPosition, 0.0, 1.0);
119
TexCoord = InputTexCoord;
12-
}
10+
}

examples/protonect/src/shader/filter1.fs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#version 140
2-
31
struct Parameters
42
{
53
float ab_multiplier;
@@ -121,4 +119,4 @@ void main(void)
121119
float i = min(dot(norm, vec3(0.333333333 * Params.ab_multiplier * Params.ab_output_multiplier)), 65535.0);
122120

123121
Debug = vec4(vec3(i, i, i) / 65535.0, 1);
124-
}
122+
}

examples/protonect/src/shader/filter2.fs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#version 140
2-
31
struct Parameters
42
{
53
float ab_multiplier;

examples/protonect/src/shader/stage1.fs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#version 140
2-
31
struct Parameters
42
{
53
float ab_multiplier;
@@ -104,6 +102,9 @@ void main(void)
104102
vec2 ab1 = processMeasurementTriple(uv, P0Table1, 3, Params.ab_multiplier_per_frq.y, saturated.y);
105103
vec2 ab2 = processMeasurementTriple(uv, P0Table2, 6, Params.ab_multiplier_per_frq.z, saturated.z);
106104

105+
#ifdef MESA_BUGGY_BOOL_CMP
106+
valid_pixel = valid_pixel ? true : false;
107+
#endif
107108
bvec3 invalid_pixel = bvec3(!valid_pixel);
108109

109110
A = mix(vec3(ab0.x, ab1.x, ab2.x), vec3(0.0), invalid_pixel);

examples/protonect/src/shader/stage2.fs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#version 140
2-
31
struct Parameters
42
{
53
float ab_multiplier;
@@ -154,4 +152,4 @@ void main(void)
154152
DepthAndIrSum = vec2(Depth, ir_sum);
155153

156154
Debug = vec4(vec3(Depth / Params.max_depth), 1.0);
157-
}
155+
}

0 commit comments

Comments
 (0)