3 Replies Latest reply on Oct 22, 2012 6:10 AM by nilsk

    glsl clipPlane bugs

    nilsk

      Using geometry shaders results in all kinds of strange behaviour regarding clip planes. I cobbled together a small test case demonstrating the issues.

      First in case 0 it looks like gl_ClipVertex gets ignored completely if it is written in the geometry shader. If only a vertex shader is used or if neither the vertex shader nor the geometry shader write to ClipVertex clipping works as expected.

      In case 1 writing to gl_ClipDistance[i] fails for all indices but 0, unrolling the loop works though.

      Case 2 shouldn't work at all, pos should be vec4[3] but the program compiles, links and is validated but visual studio reports two access violations while debugging and following draw calls with that shader fail and generate errors.

      I experimented with different #version settings but got buggy results whatever i tried.

       

      Os: Windows 7 64

      Graphics Chipset    ATI Radeon HD 5800 Series

      Device ID    6898

      Driver Packaging Version    8.982-120727a-145524C-ATI

      Catalyst Version: 12.8

      OpenGL Version: 6.14.10.11762

       

       

      Header 1

      #include "stdafx.h"

      #include "GL/glew.h"

      #include "GL/glut.h"

      #include <vector>

       

      GLuint program;

       

       

      #define CASE_0

      //#define CASE_1

      //#define CASE_2

       

      #define WORKING

      //#define BUGED

       

      //adding a geometry shader and writing gl_ClipVertex will be ignored

      #ifdef CASE_0

      #ifdef WORKING

      #define USE_GEOMETRY_SHADER

      const char *vs_source =

      "#version 120\n"

      "void main(void) {                        "

      "  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"

      "}";

      const char *gs_source =

      "//#extension GL_EXT_geometry_shader4 : require\n"

      "void main(void) {\n        "

      "    for(int i = 0; i < 3; ++i){\n"

      "        gl_Position = gl_PositionIn[i];\n"

      "    EmitVertex();\n"

      "    }"

      "}\n";

      #endif

      #ifdef BUGED

      #define USE_GEOMETRY_SHADER

      const char *vs_source =

      "#version 120\n"

      "void main(void) {                        "

      "  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"

      "  gl_ClipVertex = gl_ModelViewMatrix*gl_Vertex;\n"

      "}";

      const char *gs_source =

      "//#extension GL_EXT_geometry_shader4 : require\n"

      "void main(void) {\n        "

      "    for(int i = 0; i < 3; ++i){\n"

      "        gl_Position = gl_PositionIn[i];\n"

      "        gl_ClipVertex = gl_ClipVertexIn[i];\n"

      "    EmitVertex();\n"

      "    }"

      "}\n";

      #endif

      #endif

       

      //writing gl_ClipDistance[i] in a loop ignores the ClipDistance[1], unrolling the loop works as expected

      #ifdef CASE_1

      #define USE_GEOMETRY_SHADER

      const char *vs_source =

      "#version 120\n"

      "varying vec4 pos\n;"

      "void main(void) {"

      "  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"

      "  pos = gl_ModelViewMatrix * gl_Vertex;\n"

      "}\n";

      #ifdef WORKING

      const char *gs_source =

      "//#version 150\n"

      "#extension GL_EXT_geometry_shader4 : require\n"

      "varying in vec4 pos[3];\n"

      "void main(void) {\n"

      "    for(int i = 0; i < 3; ++i){\n"

      "        gl_Position = gl_PositionIn[i];\n"

      "        gl_ClipDistance[0] = dot(pos[i], gl_ClipPlane[0]);\n"

      "        gl_ClipDistance[1] = dot(pos[i], gl_ClipPlane[1]);\n"

      "        EmitVertex();\n"

      "    }"

      "}\n";

      #endif

      #ifdef BUGED

      #define USE_GEOMETRY_SHADER

      const char *gs_source =

      "//#version 150\n"

      "#extension GL_EXT_geometry_shader4 : require\n"

      "varying in vec4 pos[3];\n"

      "void main(void) {\n"

      "    for(int i = 0; i < 3; ++i){\n"

      "        gl_Position = gl_PositionIn[i];\n"

      "        for(int k = 0; k < 2; ++k){\n"

      "            gl_ClipDistance[k] = dot(pos[i], gl_ClipPlane[k]);\n"

      "        }\n"

      "        EmitVertex();\n"

      "    }"

      "}\n";

      #endif

      #endif

       

       

      //pos should be vec4[3] but it compiles, links and validates but genaretes access violation at runtime and drawing fails afterwards

      #ifdef CASE_2

      #define USE_GEOMETRY_SHADER

      const char *vs_source =

      "#version 120\n"

      "varying vec4 pos\n;"

      "void main(void) {"

      "  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"

      "  pos = gl_ModelViewMatrix * gl_Vertex;\n"

      "}\n";

      #ifdef BUGED

      const char *gs_source =

      "//#version 150\n"

      "#extension GL_EXT_geometry_shader4 : require\n"

      "varying in vec4 pos;\n"

      "void main(void) {\n"

      "    for(int i = 0; i < 3; ++i){\n"

      "        gl_Position = gl_PositionIn[i];\n"

      "        gl_ClipDistance[0] = dot(pos, gl_ClipPlane[0]);\n"

      "        EmitVertex();\n"

      "    }"

      "}\n";

      #endif

      #endif

       

      const char *fs_source =

      "#version 120\n"

      "void main(void) {\n"

      "  gl_FragColor = vec4(1.0, 0,0,1);\n"

      "}\n";

       

      void printCompileError(GLuint obj){

          GLint logLength;

          glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logLength);

          std::vector<GLcharARB> errorLog(logLength,0);

          glGetInfoLogARB(obj, logLength,0,&errorLog[0]);

          fprintf(stderr, &errorLog[0]);

      }

       

      int init_resources(){

          GLint compile_ok = GL_FALSE, link_ok = GL_FALSE;

          program = glCreateProgram();

       

          GLuint vs = glCreateShader(GL_VERTEX_SHADER);

          glShaderSource(vs, 1, &vs_source, NULL);

          glCompileShader(vs);

          glGetShaderiv(vs, GL_COMPILE_STATUS, &compile_ok);

          if (0 == compile_ok){

              fprintf(stderr, "Error in vertex shader\n");

              printCompileError(vs);

              return 0;

          }

       

          GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);

          glShaderSource(fs, 1, &fs_source, NULL);

          glCompileShader(fs);

          glGetShaderiv(fs, GL_COMPILE_STATUS, &compile_ok);

          if (!compile_ok){

              fprintf(stderr, "Error in fragment shader\n");

              printCompileError(fs);

              return 0;

          }

       

          glAttachShader(program, vs);

          glAttachShader(program, fs);

       

      #ifdef USE_GEOMETRY_SHADER

          GLuint gs = glCreateShader(GL_GEOMETRY_SHADER);

          glShaderSource(gs, 1, &gs_source, NULL);

          glCompileShader(gs);

          glGetShaderiv(gs, GL_COMPILE_STATUS, &compile_ok);

          if (!compile_ok){

              fprintf(stderr, "Error in geometry shader\n");

              printCompileError(gs);

              return 0;

          }

          glAttachShader(program, gs);

       

          glProgramParameteriARB(program, GL_GEOMETRY_INPUT_TYPE_ARB, GL_TRIANGLES);

          glProgramParameteriARB(program, GL_GEOMETRY_OUTPUT_TYPE_ARB, GL_TRIANGLE_STRIP);

          glProgramParameteriARB(program, GL_GEOMETRY_VERTICES_OUT_ARB, 3);

      #endif

       

          glLinkProgram(program);

          glGetProgramiv(program, GL_LINK_STATUS, &link_ok);

          if (!link_ok) {

              fprintf(stderr, "glLinkProgram:");

              printCompileError(program);

              return 0;

          }           

          glutReportErrors();

          return 1;

      }

       

       

      void onDisplay()

      {

          glClearColor(0.0, 0.0, 0.0, 1.0);

          glClear(GL_COLOR_BUFFER_BIT);

          double plane0[4] = {1.0, 0.0, 0.0, 0.3};

          double plane1[4] = {-1.0, 0.0, 0.0, 0.3};

          glEnable(GL_CLIP_PLANE0);

          glClipPlane(GL_CLIP_PLANE0, plane0);

          glEnable(GL_CLIP_PLANE1);

          glClipPlane(GL_CLIP_PLANE1, plane1);

       

       

          glUseProgram(program);

          glValidateProgram(program);

          int valid;

          glGetObjectParameterivARB(program, GL_OBJECT_VALIDATE_STATUS_ARB, &valid);

          if(!valid){

              fprintf(stderr, "validation failed");

              return;

          }

       

          glutSolidOctahedron();

          glutReportErrors();

          glutSwapBuffers();

      }

       

      int main(int argc, char** argv)

      {

          glutInit(&argc, argv);

          glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);

          glutInitWindowSize(640, 480);

          glutCreateWindow("gltestcase");

       

          GLenum glew_status = glewInit();

          if (glew_status != GLEW_OK)

          {

              fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status));

              return EXIT_FAILURE;

          }

       

          if (1 == init_resources())    {

              glutDisplayFunc(onDisplay);

              glutMainLoop();

          }

       

          return 0;

      }