Square artifacts on Nvidia GPU's[screenshots, code, win32 demo]

I have encountered a problem when GLSL shader generates incorrect image on following GPU’s:
GT 430
GT 770
GTX 570
GTX 760

But works normally on these:
Intel HD Graphics 2500
Intel HD 4000
Intel 4400
GTX 740M
Radeon HD 6310M
Radeon HD 8850

Shader code is as follows:

bool PointProjectionInsideTriangle(vec3 p1, vec3 p2, vec3 p3, vec3 point)
{
  vec3 n = cross((p2 - p1), (p3 - p1));

  vec3 n1 = cross((p2 - p1), n);
  vec3 n2 = cross((p3 - p2), n);
  vec3 n3 = cross((p1 - p3), n);

  float proj1 = dot((point - p2), n1);
  float proj2 = dot((point - p3), n2);
  float proj3 = dot((point - p1), n3);

  if(proj1 > 0.0)
    return false;
  if(proj2 > 0.0)
    return false;
  if(proj3 > 0.0)
    return false;
  return true;
}

struct Intersection
{
  vec3 point;
  vec3 norm;
  bool valid;
};

Intersection GetRayTriangleIntersection(vec3 rayPoint, vec3 rayDir, vec3 p1, vec3 p2, vec3 p3)
{
  vec3 norm = cross(p1 - p2, p1 - p3);
  norm /= (length(norm) + 1e-5);

  Intersection res;
  res.norm = norm;
  res.point = vec3(rayPoint.xy, 0.0);
  res.valid = PointProjectionInsideTriangle(p1, p2, p3, res.point);
  return res;
}

#define raysCount 15
void main(void)
{
  vec2 radius = (gl_FragCoord.xy / vec2(800.0, 600.0)) - vec2(0.5, 0.5);

  struct ColoredIntersection
  {
    Intersection geomInt;
    vec4 color;
  };
  ColoredIntersection ints[raysCount];

  vec3 randomPoints[raysCount];
  int i, j;


  for(int i = 0; i < raysCount; i++)
  {
    float theta = 0.5 * float(i);
    float phi = 3.1415 / 2.0;
    float r = 1.0;
    randomPoints[i] = vec3(r * sin(phi) * cos(theta),  r * sin(phi)*sin(theta), r * cos(phi));

    vec3 tangent = cross(vec3(0.0, 0.0, 1.0), randomPoints[i]);
    tangent /= (length(tangent) + 1e-5);
    vec3 trianglePoint1 = randomPoints[i] * 2.0 + tangent * 0.2;
    vec3 trianglePoint2 = randomPoints[i] * 2.0 - tangent * 0.2;

    ints[i].geomInt = GetRayTriangleIntersection(vec3(radius, -10.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, 0.0), trianglePoint1, trianglePoint2);
    if(ints[i].geomInt.valid) //1
    {
      float c = length(ints[i].geomInt.point);
      ints[i].color = vec4(c, c, c, 1.0);
    }
  }

  for(i = 0; i < raysCount; i++) //2
  {
    for(j = i + 1; j < raysCount; j++)
    {
      if(ints[i].geomInt.point.z < ints[i].geomInt.point.z - 10.0)
      {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
        return;
        ColoredIntersection tmp = ints[j];
        ints[j] = ints[i];
        ints[i] = tmp;
      }
    }
  }

  vec4 resultColor = vec4(0.0, 0.0, 0.0, 0.0);
  for(i = 0; i < raysCount + 0; i++)
  {
    if(ints[i].geomInt.valid)
      resultColor += ints[i].color;
  }

  gl_FragColor = resultColor;
}

The code is a simplified version of an actual shader, expected image is:

http://img.owely.com/screens/131316/original_owely20140426-19006-1w4w4ye.?1398554177

But what I get is:

http://img.owely.com/screens/131315/original_owely20140426-18968-a7fuxu.?1398553652
(both are direct links to images, change to http)

Random rotations of the code remove artifacts completely. For example if I change the line

if(ints[i].geomInt.valid) //1

to

if(ints[i].geomInt.valid == true) //1

or completely remove double cycle that does nothing (marked as 2) artifacts vanish. Even though these code rotations do not affect logic in any way, they somehow affect the artifacts.

if(ints[i].geomInt.point.z < ints[i].geomInt.point.z - 10.0)
{
  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  return;
  ColoredIntersection tmp = ints[j];
  ints[j] = ints[i];
  ints[i] = tmp;
}

Can never be satisfied(left and right sides have index i, not i, j) and there’s no NaN’s. This code does absolutely nothing yet somehow produces artifacts.

You can test the shader and demo on your own using this project(full MSVS 2010 project + sources + compiled binary and a shader, uses included SFML):

https://dl.dropboxusercontent.com/u/25635148/ShaderTest.zip (remove space in http)

I use sfml in this test project, but that’s 100% irrelevant because the actual project I’ve enountered this problem does not use this lib.

What I want to know is why these artifacts appear and how to reliably avoid them.

I can’t answer your question directly; but there a few steps I take with unusual problems in shaders

  1. use vec4 rather than vec3 in structures
  2. use explicit condition in if tests ( (a==true) rather than (a))
  3. simplify statements - avoid things like a = min(fnc(a),fnc(b)) + max(a,fn2(b))
  4. delete or comment out any nop code

Since this problem is on nVidia you could use nSight to debug the shader in real-time

I have actually worked around the problem by moving bool valid; to the beginning of the structure struct Intersecion. Looks like some compiler bug that can be avoided this way.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.