5

I want a vertex array object in OpenGL ES 2.0 to hold two attributes from different buffers, the second buffer being read from client memory (glBindBuffer(GL_ARRAY_BUFFER, 0)) But I get a runtime error:

GLuint my_vao;
GLuint my_buffer_attrib0;
GLfloat attrib0_data[] = { 0, 0, 0, 0 };
GLfloat attrib1_data[] =  { 1, 1, 1, 1 };

void init()
{
    // setup vao
    glGenVertexArraysOES(1, &my_vao);
    glBindVertexArrayOES(my_vao);

    // setup attrib0 as a vbo
    glGenBuffers( 1, &my_buffer_attrib0 );
    glBindBuffer(GL_ARRAY_BUFFER, my_buffer_attrib0);
    glBufferData( GL_ARRAY_BUFFER, sizeof(attrib0_data), attrib0_data, GL_STATIC_DRAW );
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);

    glEnableVertexAttribArray( 0 );
    glEnableVertexAttribArray( 1 );

    // "end" vao
    glBindVertexArrayOES( 0 );

}

void draw()
{

    glBindVertexArrayOES(my_vao);
    // (now I assume attrib0 is bound to my_buffer_attrib0, 
    //  and attrib1 is not bound. but is this assumption true?)

    // setup attrib1
    glBindBuffer( GL_ARRAY_BUFFER, 0 );
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, attrib1_data);

    // draw using attrib0 and attrib1
    glDrawArrays( GL_POINTS, 0, 1 );  // runtime error: Thread1: EXC_BAD_ACCESS (code=2, address=0x0)

}

What I want to achieve is to wrap the binding of two attributes as a vertex array buffer:

void draw_ok()
{
    glBindVertexArrayOES( 0 );

    // setup attrib0
    glBindBuffer( GL_ARRAY_BUFFER, my_buffer_attrib0 );
    glVertexAttribPointer( 0, 4, GL_FLOAT, GL_FALSE, 0, 0);

    // setup attrib1
    glBindBuffer( GL_ARRAY_BUFFER, 0 );
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, attrib1_data);

    glEnableVertexAttribArray( 0 );
    glEnableVertexAttribArray( 1 );

    // draw using attrib0 and attrib1
    glDrawArrays( GL_POINTS, 0, 1);  // ok
}

Is it possible to bind two different buffers in a vertex array object? Are OES_vertex_array_object's different from (plain) OpenGL vertex array objects? Also note that I get this error in XCode running the iOS simulator. These are related links:

Community
  • 1
  • 1
telephone
  • 1,061
  • 10
  • 26

4 Answers4

7

Well, a quote from the extension specifications explains it quite simply:

Should a vertex array object be allowed to encapsulate client vertex arrays?

RESOLVED: No. The OpenGL ES working group agreed that compatibility with OpenGL and the ability to to guide developers to more performant drawing by enforcing VBO usage were more important than the possibility of hurting adoption of VAOs.

So you can indeed bind two different buffers in a VAO, (well, the buffer binding isn't stored in the VAO, anyway, only the source buffers of the individual attributes, set through glVertexAttribPointer) but you cannot use client space memory in a VAO, only VBOs. This is the same for desktop GL.

So I would advise you to store all your vertex data in VBOs. If you want to use client memory because the data is updated dynamically and you think VBOs won't buy you anything there, that's still the wrong approach. Just use a VBO with a dynamic usage (GL_DYNAMIC_DRAW or even GL_STREAM_DRAW) and update it using glBuffer(Sub)Data or glMapBuffer (or the good old glBufferData(..., NULL); glMapBuffer(GL_WRITE_ONLY) combination).

Christian Rau
  • 43,206
  • 10
  • 106
  • 177
  • You get the accepted answer since you are not me and also answered if OES-VAO are the same as desktop-VAO :) thank you. – telephone Mar 04 '12 at 16:54
1

The functionality you desire has now been accepted by the community as an extension to WebGL:

http://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/

pyrotechnick
  • 391
  • 3
  • 5
  • This answer does not seem relevant to the question. The link indicates that WebGL now supports OES_vertex_array_object. Good, but not addressing the question. The accepted answer explains why VAOs can't be used in the way asked about, and gives advice as to what to do instead. – ToolmakerSteve May 05 '15 at 14:19
1

Remove the following line:

glBindBuffer( GL_ARRAY_BUFFER, 0 );

from the draw() function. You didn't bind any buffer before and it may mess up buffer state.

arul
  • 13,742
  • 1
  • 53
  • 76
  • I want the second attribute (attrib1) to be read from client memory, so GL_ARRAY_BUFFER must be unbound before calling glVertexAttribPointer. But this seems to mess up things, and I am unsure why. An example of what I want to achieve is to let the VAO store geometry, and then just set another attribute of that VAO to my custom colors, after binding the VAO. – telephone Mar 03 '12 at 23:56
  • @telephone You just cannot use client memory with VAOs, see my answer. – Christian Rau Mar 04 '12 at 16:56
1

After some digging (reading), answers was found found in OES_vertex_array_object. It seems that OES_vertex_array_object's focus on state on the server side, and client state are used if and only if the zero object is bound. It remains to answer if OES_vertex_array_object's are the same as plain OpenGL VAO's. Please comment if you know the answer to this. Below are quotations from OES_vertex_array_object:

     This extension introduces vertex array objects which encapsulate
     vertex array states on the server side (vertex buffer objects).



     * Should a vertex array object be allowed to encapsulate client
     vertex arrays?

     RESOLVED: No. The OpenGL ES working group agreed that compatibility
     with OpenGL and the ability to to guide developers to more
     performant drawing by enforcing VBO usage were more important than
     the possibility of hurting adoption of VAOs.



     An INVALID_OPERATION error is generated if
     VertexAttribPointer is called while a non-zero vertex array object
     is bound, zero is bound to the <ARRAY_BUFFER> buffer object binding
     point and the pointer argument is not NULL [fn1].
       [fn1: This error makes it impossible to create a vertex array
       object containing client array pointers, while still allowing
       buffer objects to be unbound.]



     And the presently attached vertex array object has the following
     impacts on the draw commands:

       While a non-zero vertex array object is bound, if any enabled
       array's buffer binding is zero, when DrawArrays or
       DrawElements is called, the result is undefined.

So EXC_BAD_ACCESS was the undefined result!

telephone
  • 1,061
  • 10
  • 26
  • 1
    +1 for "So EXC_BAD_ACCESS was the undefined result!". I've been chasing a bug for *days*. For some reason the client state GL_VERTEX_ARRAY was disabled by who knows who after a while, so re-enabling it after glDrawArray saved me: glEnableClientState(GL_VERTEX_ARRAY); I've never though of EXC_BAD_ACCESS as an undefined result, but as an unexpected memory release, but no, no memory was released here. Thanks for your hint, it was very helpful :) – Gonzalo Larralde Sep 02 '13 at 06:39