Geometry shader grief

I’m still learning but this geometry shader is giving me no end of trouble and asking for some help.

My system is a MacBook Pro 2015 with Intel Iris which supports OpenGL 4.1

I’m drawing a plane using an index buffer with

glDrawElements(GL_TRIANGLE_STRIP, this->size(), GL_UNSIGNED_SHORT, 0);

Which using a the following vertex and fragment shader works perfectly. But when the geometry shader comes in I get nothing. I’ve tried all kinds of combination but it still gives me absolutely nothing as output. Anyone got ideas what I am doing wrong?

Here’s the shaders (should simply be pass through)


    // Vertex
    const char* vert = R"glsl(
    #version 410
    
    layout (location = 0) in vec2 in_position;
    
    uniform mat4 MVP;
    
    void main() {
        gl_Position = MVP * vec4(in_position.x, 0.0f, in_position.y, 1.0f);
    }
    
    )glsl";
    
    // Geometry
    const char* geom = R"glsl(
    #version 410
    
    layout(triangles) in;
    layout(triangle_strip, max_vertices = 3) out;
    
    void main() {
        
        for (int i = 0; i < 3; ++i) {
            gl_Position = gl_in[i].gl_Position;
            EmitVertex();
        }
        EndPrimitive();
    }
    )glsl";
    
    // Fragment
    const char* frag = R"glsl(
    #version 410
   
    out vec4 out_color;
    
    void main() {
        out_color = vec4(1.0f);
    }
    )glsl";

I’ve tried passing the colour through from vertex-geom-fragment, varying inputs, not using an MVP transform and all kinds of things. Am I missing something vital with this simple setup? I’m not setting up and glProgramParameteri because I assumed they were not necessary with geom layouts.

Thanks
Fred

What you posted does not look bad.

So:
as usual, check for any OpenGL errors
copy/paste a GS example from the net and compare with what you have

Good thinking. It seems like I am actually getting error code 0x502 which is GL_INVALID_OPERATION when drawing this shape. I tried to create a minimal working example but I don’t really know what I am doing wrong at this point. Been doing trial and error the last 2 days without luck. Here’s the code in it’s entirety:

It works perfectly without the geometry shader but with it I get error 0x502. How would I go about hunting this down? Could it somehow be that geometry shaders are not supported on my GPU or something similarly silly?

OpenGL 4.1, latest glbinding and glfw



#include <iostream>

#define GLFW_INCLUDE_NONE
#include <glbinding/gl/gl.h>
#include <glbinding/Binding.h>

#define GLFW_DLL
#include <GLFW/glfw3.h>

using namespace gl;


void error_callback(int error, const char* description) {
    fprintf(stderr, "Error: %s
", description);
}


void create_program(GLuint &handle, GLuint *shaders) {

    handle = glCreateProgram();

    for (int i = 0; i < (sizeof(shaders) / sizeof(shaders[0])); ++i) {
        glAttachShader(handle, shaders[i]);
    }

    glLinkProgram(handle);

    // clean up after successful linking
    for (int i = 0; i < (sizeof(shaders) / sizeof(shaders[0])); ++i) {
        glDetachShader(handle, shaders[i]);
    }
}

// Comment to toggle geometry shader
#define GEOMETRY_SHADER


#ifdef GEOMETRY_SHADER
#define NUM_SHADERS 3
#else
#define NUM_SHADERS 2
#endif

// Globals
GLuint prog;
GLuint vbo[1];
GLuint vao; // not needed?
GLuint shaders[NUM_SHADERS];


// Vertex shader
const char* vert = R"glsl(
#version 410

layout (location = 0) in vec2 in_position;

out gs_PerVertex {
    vec4 color;
} vs_out;

//uniform mat4 MVP;

void main() {

    gl_Position = vec4(in_position.x, in_position.y, 0.0f, 1.0f);
//    vs_out.color = vec4(1.0f); // white
}

)glsl";

// Geometry shader
const char* geom = R"glsl(
#version 410

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

// Input block
in gs_PerVertex {
    vec4 color;
} gs_in[];

// Output block
out gs_PerVertex {
    vec4 color;
} gs_out;

void main() {

    for (int i = 0; i < 3; ++i) {
        gl_Position = gl_in[i].gl_Position + vec4(0.3);
//        gs_out.color = gs_in[i].color;
        EmitVertex();
    }
    EndPrimitive();

}
)glsl";

// Fragment shader
const char* frag = R"glsl(
#version 410

in gs_PerVertex {
    vec4 color;
} gs_in;

//    in vec4 color;
out vec4 out_color;

void main() {

//    out_color = gs_in.color;
    out_color = vec4(1.0f);

}
)glsl";


void compile_info(const GLuint shader) {
    GLint status(0);
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);

    if (1 != status) {
        GLint maxLength(0);
        GLint logLength(0);

        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);

        GLchar log[maxLength];
        glGetShaderInfoLog(shader, maxLength, &logLength, log);
        fprintf(stderr, "Compiling shader %u failed: %s", shader, log);

    }
}

void create_shader(GLuint &shader, GLenum type, const char* src) {

    shader = glCreateShader(type);

    glShaderSource(shader, 1, &src, NULL);
    glCompileShader(shader);

    // check for errors
    compile_info(shader);
}

void link_info(const GLuint program) {
    GLint status(0);
    glGetProgramiv(program, GL_LINK_STATUS, &status);

    if (1 != status) {
        GLint maxLength(0);
        GLint logLength(0);

        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);

        GLchar log[maxLength];
        glGetProgramInfoLog(program, maxLength, &logLength, log);

        fprintf(stderr, "Linking of program failed: %s
", log);
    }
}

void create_program(GLuint &_p, GLint *_s) {
    _p = glCreateProgram();

    if(_p == 0)
        fprintf(stderr, "Could not create shader program.
");

    for (int i = 0; i < (sizeof(_s) / sizeof(_s[0])); ++i) {
        glAttachShader(_p, _s[i]);
    }

    glLinkProgram(_p);

    // Check for errors.
    link_info(_p);

    // Clean up.
    for (int i = 0; i < (sizeof(_s) / sizeof(_s[0])); ++i) {
        glDetachShader(_p, _s[i]);
    }
}


/// Check for errors. Poll gl for all error messages and print to
/// stderr.
// TODO convert these messages to strings (with glfw?)
void check_errors() {
    GLenum err;
    while ((err = glGetError()) != GL_NO_ERROR) {
        fprintf(stderr, "OpenGl encountered an error with code: %d
", err);
    }
}

struct Point2D {
    float x, y;
};

const Point2D vertices_data[] = {
    {-0.5, -0.5},
    {0.5, -0.5},
    {-0.5, 0.5},
    
    {-0.5, 0.5},
    {0.5, -0.5},
    {0.5, 0.5}
};

int init_resources() {
    
    // Generate shader and shader program handles
#ifdef GEOMETRY_SHADER
    create_shader(shaders[0], GL_VERTEX_SHADER, vert);
    create_shader(shaders[1], GL_GEOMETRY_SHADER, geom);
    create_shader(shaders[2], GL_FRAGMENT_SHADER, frag);
#else
    create_shader(shaders[0], GL_VERTEX_SHADER, vert);
    create_shader(shaders[1], GL_FRAGMENT_SHADER, frag);
#endif
    
    create_program(prog, shaders);
    
    GLint a_pos = glGetAttribLocation(prog, "in_position");

    if (a_pos == -1) {
        fprintf(stderr, "Could not find attribute in shader.");
    }
    
    glGenBuffers(1, vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_data), vertices_data, GL_STATIC_DRAW);
    
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    
    glEnableVertexAttribArray(a_pos);
    glVertexAttribPointer(/*index:*/a_pos, /*size:*/2, /*type:*/GL_FLOAT, /*norm:*/GL_FALSE, 0, 0);
    
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    
    glBindVertexArray(0);
    
    check_errors();
    
    return 1;
}

void draw_scene() {
    glBindVertexArray(vao);
    glUseProgram(prog);
   
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
    
    glBindVertexArray(0);
 
    check_errors();    
}


void free_resources() {
    glDeleteProgram(prog);
}


int main(int argc, const char * argv[]) {
    GLFWwindow *window;
    int width, height;
    
    glfwSetErrorCallback(error_callback);
    
    if (!glfwInit())
        return -1;
    
    glfwDefaultWindowHints(); // ?
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true);
    glfwWindowHint(GLFW_RESIZABLE, false);
    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true); // ?
    
    window = glfwCreateWindow(640, 480, "Hello", NULL, NULL);
    
    if (!window) {
        glfwTerminate();
        return -1;
    }
    
    glfwGetFramebufferSize(window, &width, &height);
    glfwMakeContextCurrent(window);
    glbinding::Binding::initialize(false);
    
    init_resources();
    
    // Just draw once to check for errors
    draw_scene();
    glfwSwapBuffers(window);
    
    // Main loop
    while(!glfwWindowShouldClose(window)) {
        glfwPollEvents();
//        draw_scene();
//        glfwSwapBuffers(window);
    }
    
    // Clean up.
    free_resources();
    
    glUseProgram(0);
    glDisableVertexAttribArray(0);
    
    glfwDestroyWindow(window);
    glfwTerminate();
    
    return 0;
}



Find which command generates the error. Set a breakpoint inside check_errors() when, then start adding more calls. Once you’ve identified the command (a call to check_errors() immediately before it succeeds, a call immediately after reports an error), refer to its documentation in the reference pages or (preferably) the specification to see the conditions which can cause that particular error.

Geometry shaders are a requirement of OpenGL 3.2 and above.

Your error has nothing to do with OpenGL. You need to understand how pointers work:


void create_program(GLuint &handle, GLuint *shaders) {
...
    for (int i = 0; i < (sizeof(shaders) / sizeof(shaders[0])); ++i)

On x86_64, sizeof(GLuint *) is 8, and sizeof((GLuint *)[0]) is 4, so this always loops twice.

How would I go about hunting this down?

  • Learn to use your platform’s debugger.

  • Learn how to introspect GL state. You’re checking errors, compile state, and link state. But not the object state; glGetProgram will tell you everything about your linked program (like how many shaders are attached to it). glValidateProgram’s log in this case would have helpfully informed you: “Validation Failed: Program does not contain fragment shader. Results will be undefined.”

Holy sweet jesus, I didn’t realise I just passing a pointer. This was the issue. There was another create_program() function that I was calling as well. I didn’t think to look there. Thanks a million!

[QUOTE=arekkusu;1289811]

Thank you for the link, I’ve been looking how to debug on macOS for ages.

Programming is like a giant game of Where’s Waldo sometimes…

Cheers
Fred