c42f/displaz

3D artifacts with Intel integrated GPUs

Closed this issue · 20 comments

c42f commented

Displaz doesn't seem to work well with intel graphics drivers on windows (+ possibly other platforms): points in the foreground go missing, and the depth testing is messed up with foreground points sometimes appearing behind background points.

c42f commented

The missing points can be made to come back by removing the use of gl_FragDepth from the fragment shader. Not sure about the depth testing yet, it's mysterious.

c42f commented

@scottcarpenter FYI, I plan to stop brushing this one off ;-)

c42f commented

Ok, there's at least two separate things going on here:

  • The Intel drivers are somehow unhappy about glBlitFramebuffer(), or about the format of the incremental framebuffer itself. It looks like depth testing is off for the incremental framebuffer. Disabling incremental rendering "fixes" this for small datasets.
  • The Intel driver seems to have a bug which causes the storage for gl_FragDepth and gl_PointSize to alias each other or otherwise interfere somehow. Whatever it is, setting gl_FragDepth causes gl_PointSize to be corrupted. Example shader:
#version 130
// Copyright 2015, Christopher J. Foster and the other displaz contributors.
// Use of this code is governed by the BSD-style license found in LICENSE.txt

uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 modelViewProjectionMatrix;

//------------------------------------------------------------------------------
#if defined(VERTEX_SHADER)

uniform float pointRadius = 0.1;   //# uiname=Point Radius; min=0.001; max=10
// Point size multiplier to get from a width in projected coordinates to the
// number of pixels across as required for gl_PointSize
uniform float pointPixelScale = 0;


in vec3 position;

void main()
{
    vec4 p = modelViewProjectionMatrix * vec4(position,1.0);
    float pointScreenSize = clamp(2*pointPixelScale*pointRadius / p.w, 0, 400);

    gl_PointSize = pointScreenSize;
    gl_Position = p;
}


//------------------------------------------------------------------------------
#elif defined(FRAGMENT_SHADER)

out vec4 fragColor;

void main()
{
    gl_FragDepth = gl_FragCoord.z;
    fragColor = vec4(vec3(gl_PointCoord.y), 1);
}

#endif

Confrming the same visual artifacts on Intel(R) HD Graphics 3000, driver 9.17.10.3190, Windows 7 Service Pack 1(6.1.7601).

c42f commented

Have you every encountered the gl_PointSize/gl_FragDepth conflict? It's a bizarre one, and I couldn't find any reference to it online. Basically, the line

gl_FragDepth = glFragCoord.z;

Should be a noop, but it causes the fragColor to be set to something completely different.

Yeah, seems like a driver bug, on the face of it. It probably won't hurt to log the GLSL compiler output, to see if there are any breadcrumbs there. (ShaderProgram::setShader)

Nope, no joy from the GLSL logs. Oh well, it was worth checking.

c42f commented

cheers, thanks for looking. My only thought is to disable gl_FragDepth on intel using some #ifdefs. It's not too much of a loss (other than making the shader ugly). I probably should figure out how to report it to intel too.

I guess the framebuffer issue is probably my bug (or qt's)

Bingo! I added some checking for QGLFramebufferObject, to check that the requested QGLFramebufferObjectFormat depth buffer was successfully attached. Alas, QGLFramebufferObject.attachment() == QGLFramebufferObject::NoAttachment

So it it reasonable to disable incremental rendering if FBO depth attachment isn't available?

  • Nigel
c42f commented

I guess we could just render the first frame - people won't see all the points; I guess that's too bad.

Better though - figure out why the attachment fails, and whether it can be worked around.

c42f commented

Maybe QGLFramebufferObject isn't doing some necessary incantation required for Intel - it could be abandoned, or maybe qt5 has fixed it.

Updating the Intel HD 3000 driver did not seem to resolve either issue.
inteldriver
inteldrivernew

Is this resolved?

c42f commented

There's still the need to disable the use of gl_FragDepth for intel cards, or figure out a workaround.

I tried some shader fiddling and I couldn't get gl_FragDepth and gl_PointSize to work together, so that will be a bug report to intel I guess, and just disable the use of gl_FragDepth for now on Intel + windows drivers.

Can you describe the visual manifestation of that issue? My impression was that the FBO workaround fixed that too, but perhaps I was only noticing the depth buffering problem.

c42f commented

It's definitely a distinct issue from the FBO problem. Visually, the points are not rounded in the foreground with the default shader, and all the low intensity points disappear when you zoom in. The oddness seems to boil down to the shader which I pasted in above: setting gl_FragDepth seems to mangle the value of gl_PointCoord so that values calculated from it come out wrong. One of those values is used to discard fragments, which results in the wrong fragments getting discarded.

My test box has Intel HD graphics 4600. It looks like I have an old version of the driver since the official Lenovo version of the intel driver is old. I'll try installing the generic version from Intel to see whether that fixes things.

c42f commented

attaching screenshot
intel_4600_fragdepth_bug

In this screenshot you can see the dark points in the background - in the foreground only light points remain. The foreground points are also square rather than rounded.

I don't think I've seen those artifacts on this Lenovo E430 with Intel HD 3000 GPU. I'd suggest installing the latest Intel GPU driver, as a next step.

c42f commented

I've installed what seems to be the latest driver (reported as 10.18.14.4222), but that doesn't help things. Must be hardware-dependent. Fun times :-/

c42f commented

On my test hardware, the remaining problems are worked around by 3e16ff7, so I went ahead and made a new release 0.3.2 containing the fixes. I'll keep this issue open to nag myself into reporting it to Intel...