简体   繁体   中英

Can't render to GtkGLArea

I try to render a triangle to a GtkGLArea but I only see the color with which I cleared the frame with glClearColor().

Please note:

  • I know that the triangle is so big that it would fill the whole screen, but I also tried smaller ones and it didn't work either.
  • I also know that I should normally not create the program before each rendering, I only did it here to keep the example short.
  • I'm fairly certain that the error is neither in LoadShaders nor in the shaders themselves because I've tried the exact same functions with GLFW and they've worked fine their.

Things which might cause the problem:

  • I'm not flushing the frame currently or swapping framebuffers because the documentation ( https://developer.gnome.org/gtk3/stable/GtkGLArea.html ) doesn't mention that I have to. I've tried glFlush() but it didn't help either.

  • I assume that the screen coordinates go from -1 to 1 on all axis like in normal OpenGL. Maybe that's wrong but I couldn't find anything in the documentation there either.

Could somebody help me?

This is how I compile it:

g++ -O3 -s -o main main.cpp -isystem include -Llibs -DNDEBUG `pkg-config --cflags gtk+-3.0` `pkg-config --libs gtk+-3.0` -lepoxy -lm

This is my code:

#include <gtk/gtk.h>
#include <epoxy/gl.h>
#include <epoxy/glx.h>
#include <iostream>
#include <vector>

GLuint LoadShaders(char const* vertex, char const* fragment){

    // Create the shaders
    GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

    GLint Result = GL_FALSE;
    int InfoLogLength;

    // Compile Vertex Shader
    glShaderSource(VertexShaderID, 1, &vertex , NULL);
    glCompileShader(VertexShaderID);

    // Check Vertex Shader
    glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    if ( InfoLogLength > 0 ){
        std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
        glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
        printf("%s\n", &VertexShaderErrorMessage[0]);
    }

    // Compile Fragment Shader
    glShaderSource(FragmentShaderID, 1, &fragment , NULL);
    glCompileShader(FragmentShaderID);

    // Check Fragment Shader
    glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    if ( InfoLogLength > 0 ){
        std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
        glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
        printf("%s\n", &FragmentShaderErrorMessage[0]);
    }

    // Link the program
    GLuint ProgramID = glCreateProgram();
    glAttachShader(ProgramID, VertexShaderID);
    glAttachShader(ProgramID, FragmentShaderID);
    glLinkProgram(ProgramID);

    // Check the program
    glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
    glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    if ( InfoLogLength > 0 ){
        std::vector<char> ProgramErrorMessage(InfoLogLength+1);
        glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
        printf("%s\n", &ProgramErrorMessage[0]);
    }

    glDetachShader(ProgramID, VertexShaderID);
    glDetachShader(ProgramID, FragmentShaderID);

    glDeleteShader(VertexShaderID);
    glDeleteShader(FragmentShaderID);

    return ProgramID;
}

char const* vertShader = R"GLSL(
#version 330 core
void main(){
    gl_Position.z = 0.0;
    gl_Position.w = 1.0;
    if (0 == gl_VertexID) {
        gl_Position.x = -100.0;
        gl_Position.y = -100.0;
    }
    if (2 == gl_VertexID) {
        gl_Position.x =  0.0;
        gl_Position.y =  100.0;
    }
    if (1 == gl_VertexID) {
        gl_Position.x =  100.0;
        gl_Position.y = -100.0;
    }
}
)GLSL";

char const* fragShader = R"GLSL(
#version 330 core
layout(location = 0) out vec4 color;
void main(){
    color = vec4(1.0, 0.0, 0.0, 1.0);
}
)GLSL";

gboolean
render(GtkGLArea*, GdkGLContext*, gpointer) {
    glClearColor(0.5, 0.5, 0.5, 0);
    glClear(GL_COLOR_BUFFER_BIT);

    GLuint programID;
    programID = LoadShaders(vertShader, fragShader);

    glUseProgram(programID);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    //glFlush();
    glDeleteProgram(programID);
    return TRUE;
}

int
main(int argc, char** argv) {
    gtk_init(&argc, &argv);

    auto window{gtk_window_new(GTK_WINDOW_TOPLEVEL)};
    auto glWidget{gtk_gl_area_new()};
    gtk_container_add(GTK_CONTAINER(window), glWidget);
    g_signal_connect (glWidget, "render", G_CALLBACK(render), nullptr);
    gtk_widget_show_all(window);

    gtk_main();

    return EXIT_SUCCESS;
}

Two things I can think of:

  • You aren't requesting a Core context from the OS. Looks like you have to override create-context & create + return a gdk_gl_context_set_required_version 'd GdkGLContext .
  • When you do get a Core context up & going I'm pretty sure you still need a VAO bound even if you're generating geometry entirely within your vertex shader.

RE: missing VAOs:

With this GLFW program and the VAO creation/bind commented out:

#include <glad/glad.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <iostream>

void CheckStatus( GLuint obj, bool isShader )
{
    GLint status = GL_FALSE, log[ 1 << 11 ] = { 0 };
    ( isShader ? glGetShaderiv : glGetProgramiv )( obj, isShader ? GL_COMPILE_STATUS : GL_LINK_STATUS, &status );
    ( isShader ? glGetShaderInfoLog : glGetProgramInfoLog )( obj, sizeof( log ), NULL, (GLchar*)log );
    if( status == GL_TRUE ) return;
    std::cerr << (GLchar*)log << "\n";
    std::exit( EXIT_FAILURE );
}

void AttachShader( GLuint program, GLenum type, const char* src )
{
    GLuint shader = glCreateShader( type );
    glShaderSource( shader, 1, &src, NULL );
    glCompileShader( shader );
    CheckStatus( shader, true );
    glAttachShader( program, shader );
    glDeleteShader( shader );
}

const char* vert = 1 + R"GLSL(
#version 330 core
void main(){
    gl_Position.z = 0.0;
    gl_Position.w = 1.0;
    if (0 == gl_VertexID) {
        gl_Position.x = -100.0;
        gl_Position.y = -100.0;
    }
    if (2 == gl_VertexID) {
        gl_Position.x =  0.0;
        gl_Position.y =  100.0;
    }
    if (1 == gl_VertexID) {
        gl_Position.x =  100.0;
        gl_Position.y = -100.0;
    }
}
)GLSL";

const char* frag = 1 + R"GLSL(
#version 330 core
layout(location = 0) out vec4 color;
void main(){
    color = vec4(1.0, 0.0, 0.0, 1.0);
}
)GLSL";

int main( int, char** )
{
    glfwSetErrorCallback( []( int, const char* desc ) { std::cerr << desc << "\n"; std::exit( EXIT_FAILURE ); } );
    glfwInit();
    glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
    glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
    glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE );
    glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
    GLFWwindow* window = glfwCreateWindow( 640, 480, "GLFW", NULL, NULL );
    glfwMakeContextCurrent( window );
    gladLoadGLLoader( (GLADloadproc)glfwGetProcAddress );

    //GLuint vao = 0;
    //glGenVertexArrays( 1, &vao );
    //glBindVertexArray( vao );

    GLuint prog = glCreateProgram();
    AttachShader( prog, GL_VERTEX_SHADER, vert );
    AttachShader( prog, GL_FRAGMENT_SHADER, frag );
    glLinkProgram( prog );
    CheckStatus( prog, false );

    while( !glfwWindowShouldClose( window ) )
    {
        glfwPollEvents();
        int w, h;
        glfwGetFramebufferSize( window, &w, &h );
        glViewport( 0, 0, w, h );

        glClearColor( 0.5, 0.5, 0.5, 0 );
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glUseProgram( prog );
        glDrawArrays( GL_TRIANGLES, 0, 3 );
        glfwSwapBuffers( window );
    }

    glfwTerminate();
}

Running on Linux with Mesa 13.0.6's llvmpipe backend & the MESA_DEBUG=1 envvar gives me a grey window and this message on stdout:

Mesa: User error: GL_INVALID_OPERATION in glDrawArrays(no VAO bound)

Restoring the VAO gives the expected red window.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM