0
$\begingroup$

I'm not sure this is the best place to post this, but it definitely seemed more appropriate than programming. I'm one of the developers of Performous, essentially a karaoke (and instruments) game. We use mostly 2D graphics in OpenGL, I don't think anything particularly strange.

On most machines, everything works perfectly. There's a subset of Intel iGPUs (from what I've been able to ascertain, certain models ranging from around the Ivy Bridge generation to somewhere around Broadwell) that render incredibly distorted, on Windows machines. I've seen it happen on Windows 7 and 10 (presumably it also does on Win8)... never in Linux or OSX, I attempted to reproduce it on a mac mini (that should have been affected) running bootcamp, and was unable to.

P.S. If you want to see the code, it's on github at https://github.com/performous/performous

Relevant files most likely would be (under game/) video_driver.cc/hh, surface.cc/hh, glutil.cc/hh, glshader.cc/hh and the actual shaders that live in data/shaders

Distorted graphics on a win7 PC

Edit: actual drawing call,

void VertexArray::draw(GLint mode) {
    GLErrorChecker glerror("VertexArray::draw");
    if (empty()) return;
    unsigned stride = sizeof(VertexInfo);
    GLint program;
    glGetIntegerv(GL_CURRENT_PROGRAM, &program);
    GLint vertPos = glGetAttribLocation(program, "vertPos");
    GLint vertTexCoord = glGetAttribLocation(program, "vertTexCoord");
    GLint vertNormal = glGetAttribLocation(program, "vertNormal");
    GLint vertColor = glGetAttribLocation(program, "vertColor");
    glerror.check("program and attribs");
    glBindVertexArray(m_vao);
    glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(VertexInfo) * size(), &m_vertices.front(), GL_STATIC_DRAW);
    glerror.check("bind");
    if (vertPos != -1) {
        glEnableVertexAttribArray(vertPos);
        const GLvoid* ptr = m_vbo ? (GLvoid*)offsetof(VertexInfo, position) : &m_vertices[0].position;
        glVertexAttribPointer(vertPos, 3, GL_FLOAT, GL_FALSE, stride, ptr);
    }
    if (vertTexCoord != -1) {
        const GLvoid* ptr = m_vbo ? (GLvoid*)offsetof(VertexInfo, texCoord) : &m_vertices[0].texCoord;
        glEnableVertexAttribArray(vertTexCoord);
        glVertexAttribPointer(vertTexCoord, 2, GL_FLOAT, GL_FALSE, stride, ptr);
    }
    if (vertNormal != -1) {
        const GLvoid* ptr = m_vbo ? (GLvoid*)offsetof(VertexInfo, normal) : &m_vertices[0].normal;
        glEnableVertexAttribArray(vertNormal);
        glVertexAttribPointer(vertNormal, 3, GL_FLOAT, GL_FALSE, stride, ptr);
    }
    if (vertColor != -1) {
        const GLvoid* ptr = m_vbo ? (GLvoid*)offsetof(VertexInfo, color) : &m_vertices[0].color;
        glEnableVertexAttribArray(vertColor);
        glVertexAttribPointer(vertColor, 4, GL_FLOAT, GL_FALSE, stride, ptr);
    }
    glerror.check("enable arrays");
    glDrawArrays(mode, 0, size());

    if (vertPos != -1) glDisableVertexAttribArray(vertPos);
    if (vertTexCoord != -1) glDisableVertexAttribArray(vertTexCoord);
    if (vertNormal != -1) glDisableVertexAttribArray(vertNormal);
    if (vertColor != -1) glDisableVertexAttribArray(vertColor);
    if (m_vbo) glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

Client-side vertex struct:

struct VertexInfo {
    glmath::vec3 position{};
    glmath::vec2 texCoord{};
    glmath::vec3 normal{};
    glmath::vec4 color{ 1.0, 1.0, 1.0, 1.0 };
};

Distorted graphics on a win10 laptop

Expected appearance, on my mac

$\endgroup$
  • 1
    $\begingroup$ My first guess would be overflows in one of the shaders. OpenGL numbers don't have the same range on different implementations and it's easy to get caught out that way. Check your shaders don't deliberately rely on overflow being a modulo, and try increasing everything to highp and see if the behaviour changes. $\endgroup$ – Dan Hulme Jun 17 '18 at 16:26
  • $\begingroup$ I hadn't had a chance to actually look into this. I just did, I'm not really sure what to look for in the shaders, but I ran a project-wide search and found only a couple uses of mod, fmod, % (mostly used as a literal in strings) and for some reason C remainder used mostly in unrelated things. There was a line using modulo to normalize coordinates but I tried reverting that commit (from 2010 or so) and behavior was largely the same. Using highp also didn't really change anything. $\endgroup$ – Gregorio Litenstein Jul 8 '18 at 18:25
  • $\begingroup$ Were is the vertex format specified and were are vertices prepared on the CPU side, that would be the first place I would look. $\endgroup$ – PaulHK Jul 9 '18 at 6:19
  • $\begingroup$ game/glutil.hh and glutil.cc. As I said on the bounty explanation, I know I'm currently doing some outdated/inefficient things but I'd rather fix it first and then correct those. $\endgroup$ – Gregorio Litenstein Jul 9 '18 at 15:03
  • $\begingroup$ Yesterday I was playing around with using colors as debugging (as explained on several answers scattered around the web) and noticed that I'm getting widly different values (and representations for most things when comparing MacOS and Windows) Also, while using colors I see them making out the shapes of the distorted graphics as they were in the first screenshot. Definitely the vertex position is being affected as is the normal. In mac, normals are always 0, in Windows, they're... not. $\endgroup$ – Gregorio Litenstein Jul 9 '18 at 15:25
1
$\begingroup$

As mentioned on a comment, after talking about it on IRC, they helped me realize the bug was in the geometry shader that was being used for Stereo 3D.

Due to the way it was conceived (which was apparently a really bad idea), the shader was always compiled and linked if the hardware reported supporting OpenGL3.30 and GL_arb_viewport_array.

When the stereo3d option was disabled, via a very hacky solution, the shader was put into a "pass-through" mode which is supposed to do nothing but (still not sure if it's a bug in the shader itself or a hardware/driver issue) it was sending a lot of undefined values to the fragment shader, instead.

Here's the offending code:

#version 330 core
#extension GL_ARB_viewport_array : require

uniform float sepFactor;
uniform float z0;

layout(triangles) in;
layout(triangle_strip, max_vertices = 6) out;

struct vData {
    vec3 lightDir;
    vec2 texCoord;
    vec3 normal;
    vec4 color;
};

in vData vertex[];
out vData fragv;

void passthru(int i) {
    gl_Position = gl_in[i].gl_Position;
    fragv = vertex[i];
}

// Process all the vertices, applying code to them before emitting (do-while to convince Nvidia of the code getting executed)
#define PROCESS(code) i = 0; do { passthru(i); code; EmitVertex(); } while (++i < 3); EndPrimitive();

void main() {
    int i = 0;
    if (sepFactor == 0.0) {
        gl_ViewportIndex = 0; PROCESS(;); // No stereo
    } else {
        gl_ViewportIndex = 1; PROCESS(gl_Position.x -= sepFactor * (gl_Position.z - z0));  // Left eye
        gl_ViewportIndex = 2; PROCESS(gl_Position.x += sepFactor * (gl_Position.z - z0));  // Right eye
    }
}

I have sort-of solved it by actually recompiling and relinking the shaders to include the geometry shader or not when stereo3d is toggled.

I've also rewritten the shader to look like this (it still produces skewed geometry but atleast akin to the first screenshot, instead of the second),

#version 330 core
#extension GL_ARB_viewport_array : require

uniform highp float sepFactor;
uniform highp float z0;

layout(triangles) in;
layout(triangle_strip, max_vertices = 6) out;

in vData {
    highp vec3 lightDir;
    highp vec2 texCoord;
    highp vec3 normal;
    highp vec4 color;
} vertices[];

out vData {
    highp vec3 lightDir;
    highp vec2 texCoord;
    highp vec3 normal;
    highp vec4 color;
} fragv;

void passthru(int vp, int i) {
        gl_Position = gl_in[i].gl_Position;
        gl_ViewportIndex = (sepFactor == 0.0) ? 0 : vp;
        gl_Position.x -= (sepFactor * (gl_Position.z - z0));
        fragv.lightDir = vertices[i].lightDir;
        fragv.texCoord = vertices[i].texCoord;
        fragv.normal = vertices[i].normal;
        fragv.color = vertices[i].color;
}

void main() {
        // Render the left eye
    int i = 0;
    do {
        passthru(1, i);
        gl_Position.x -= (sepFactor * (gl_Position.z - z0));
        EmitVertex();       
        } while (++i < 3);
        EndPrimitive();

    i = 0;
        // Render the right eye
    do {
        passthru(2, i);
        gl_Position.x += (sepFactor * (gl_Position.z - z0));
        EmitVertex();       
        } while (++i < 3);
        EndPrimitive();
}

In order to provide a more complete answer, in case somebody faces the same issue: I finally realized the issue appears to be with the way the loop was written. For some reason, not defining i in the loop itself resulted in trying to access undefined members of vertices

Rewriting as follows fixed the issue:

for (int i=0; i < gl_in.length(); i++) {
    passthru(1, i);
    gl_Position = gl_in[i].gl_Position;
    gl_Position.x -= (sepFactor * (gl_in[i].gl_Position.z - z0));
    EmitVertex();   
}
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.