Drawing a single point without VAO on NVIDIA and AMD

Assume I would want to draw a single point on the screen. I prepared a minimalistic test case for this. My initial solutions was the following:


void DisplayWithOutVAO()
{
  glUseProgram(program);

  glVertexAttrib2f(0, 0.0f, 0.0f);
  glDrawArrays(GL_POINTS, 0, 1); // Draw dot at 0,0

  glUseProgram(0);

  glutSwapBuffers();
}

I do not bind any buffers and use glVertexAttrib to set the position of the point. This works well on NVIDIA, but when I tested on AMD I could NOT see the point.

The alternative is to store the single point in a VBO and create an appropriate VAO:


void DisplayWithVAO()
{
  glUseProgram(program);

  glBindVertexArray(vao);
  glDrawArrays(GL_POINTS, 0, 1); // Draw dot at 0,0
  glBindVertexArray(0);

  glUseProgram(0);

  glutSwapBuffers();
}

void InitVAO() {
  glGenBuffers(1, &vbo);
  glGenVertexArrays(1, &vao);

  float pos[] = { 0.0f, 0.0f };

  glBindVertexArray(vao);
  glEnableVertexAttribArray(0);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBufferData(GL_ARRAY_BUFFER, 2 * sizeof(float), &pos, GL_DYNAMIC_DRAW);
  glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
  glBindVertexArray(0);
}

This way of drawing a SINGLE point works on both NVIDIA and AMD. But I’m not satisfied with the overhead of creating VBO and VAO. Especially if the single point changes its position from frame to frame, the solution without VAO (i.e., using glVertexAttrib) is far more elegant.

Here are my questions:

  1. Am I allowed to render a single point without using a VAO, but using only glVertexAttrib?
  2. Could it be that the solution without VAO does NOT work on AMD due to a driver problem?
  3. What would be the most practical solution of drawing a single point?

Thanks for your suggestions and comments!

I’m working under Ubuntu 12.10 with OpenGL 3 (core). For completeness, here is the full test case:


#include <stdio.h>
#include <string.h>
#include <GL/glew.h>
#include <GL/freeglut.h>

GLint program;
GLuint vbo;
GLuint vao;

void DisplayWithOutVAO()
{
    glUseProgram(program);

    glVertexAttrib2f(0, 0.0f, 0.0f);
    glDrawArrays(GL_POINTS, 0, 1); // Draw dot at 0,0

    glUseProgram(0);

    glutSwapBuffers();
}

void DisplayWithVAO()
{
    glUseProgram(program);

    glBindVertexArray(vao);
    glDrawArrays(GL_POINTS, 0, 1); // Draw dot at 0,0
    glBindVertexArray(0);

    glUseProgram(0);

    glutSwapBuffers();
}

void InitProgram() {
    // Create very simple vertex shader
    const GLchar* vsh_src[] = {"#version 330 
 layout(location=0) in vec2 pos; 
 void main() { 
 gl_Position = vec4(pos, 0, 1); 
 } 
"};
    const GLint vsh_len[] = {strlen(vsh_src[0])};
    GLuint vsh = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vsh, 1, vsh_src, vsh_len);
    glCompileShader(vsh);

    // Create very simple fragment shader
    const GLchar* fsh_src[] = {"#version 330 
 out vec4 col; 
 void main() { 
 col = vec4(1, 0, 0, 1); 
 } 
"};
    const GLint fsh_len[] = {strlen(fsh_src[0])};
    GLuint fsh = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fsh, 1, fsh_src, fsh_len);
    glCompileShader(fsh);

    // Create program, attach shaders, and bind frag data location
    program = glCreateProgram();
    glAttachShader(program, vsh);
    glAttachShader(program, fsh);
    glBindFragDataLocation(program, 0, "col");
    glLinkProgram(program);
}

void InitVAO() {
    glGenBuffers(1, &vbo);
    glGenVertexArrays(1, &vao);

    float pos[] = { 0.0f, 0.0f };

    glBindVertexArray(vao);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, 2 * sizeof(float), &pos, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
    glBindVertexArray(0);
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
    glutInitWindowSize(1024, 768);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("OpenGL");

    glutDisplayFunc(DisplayWithVAO);

    GLenum status = glewInit();

    InitProgram();
    InitVAO();
  
    glutMainLoop();
    
    return 0;
}

The answer actually depends on the GL profile you use. In a core profile the glDrawArrays without bound vertex array should work, but in a compatibility profile the glDrawArrays call requires a bound Vertex or VertexAttrib(0) array. So in fact the AMD driver would be correct here.

I see, I have to check for the correct profile. I added two lines to my test case to force the “core” profile.


    glutInitContextVersion (3, 3);
    glutInitContextFlags (GLUT_CORE_PROFILE);

And indeed the test case works fine when using glVertexAttrib only. So it was no driver problem, but a question of selecting the correct profile.

Thanks a lot for the advice!

If you see gl spec 3.2, it requires VAO to use else Drawarrays will throw “GL_INVALID_OPERATION” …

Only in the core profile (as was said). The compatibility profile doesn’t require VAOs.

If you’re running on NVidia, you can get better perf through bindless anyway.