OpenGL ES 2.0: the most efficient installation for VBO with GL_STREAM_DRAW?

I am using Vertex Buffer Object (VBO) in OpenGL ES 2.0.

I have a vertex dataset that is permanently stored in regular RAM. The reason is that calculating vertex positions from scratch is expensive, but a delta can be added to the last position to update it cheaply.

The actual number of vertices to be drawn changes rapidly over time. In one frame I can have 1000 and in the next 2500. Following the tips I got here earlier, I now specify integer UPPER as the upper bound on the number of vertices that will ever be drawn. I malloc arrays of vertices and indexes of arrays only once at startup based on this value.

I pass the prompt GL_STREAM_DRAW for each glBindBuffer call to indicate that the data is changing every frame.

Trying to be as efficient as possible, I created the following setup:

 // SETUP: Called only once. glBindBuffer(GL_ARRAY_BUFFER,...); glBufferData(GL_ARRAY_BUFFER,...); // Pass vertex data for UPPER vertices. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,...); glBufferData(GL_ELEMENT_ARRAY_BUFFER,...); // Pass index values 0 - (UPPER-1). glEnableVertexAttribArray(...); // Setup vertex attributes. glVertexAttribPointer(...); glUseProgram(...); // Use program with custom shaders. glUniformMatrix4fv(...); // Identify shader uniforms. // UPDATE: Called when vertex data changes (on each frame). glBindBuffer(GL_ARRAY_BUFFER,...); glBufferSubData(GL_ARRAY_BUFFER,...); // Update VBO data. // RENDER: Called on each frame. glDrawElements(GL_TRIANGLES, numberOfVerticesThisFrame, ...); // Number of vertices and indices to be used is inherently specified in here. 

However, this breaks down from EXC_BAD_ACCESS to glDrawElements , and I know this because of my ordering of the gl commands.

I had a similar installation that previously worked:

 // UPDATE: Called when vertex data changes (on each frame). glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,...); glBufferData(GL_ELEMENT_ARRAY_BUFFER,...); // Pass index values 0 - (actual number of vertices to draw - 1) // RENDER: Called on each frame. glBindBuffer(GL_ARRAY_BUFFER,...); glBufferData(GL_ARRAY_BUFFER,...); // Pass vertex data for actual number of vertices (not UPPER). glEnableVertexAttribArray(...); // Setup vertex attributes. glVertexAttribPointer(...); glUseProgram(...); // Use program with custom shaders. glUniformMatrix4fv(...); // Identify shader uniforms. glDrawElements(GL_TRIANGLES, numberOfVerticesThisFrame, ...); 

However, this installation requires a lot more work for each frame, and as you can see, this is due to the resizing of the VBO (since it uses the actual size, not UPPER ), which I was told is a big performance gap.

Can someone explain to me any obvious problems with my new setup, and most importantly, which commands should I call each frame before glDrawElements ? My assumption that I can prepare all possible indexes in advance and then pass the actual number of vertices to glDrawElements is clearly wrong.

+6
source share
1 answer

To answer the question asked in the title of the question, there is no โ€œmost effectiveโ€ buffer setting for streaming vertex data. Especially not on ES 2.0, which covers a wide range of different hardware, each with its own characteristics.

To answer the question of why your code stops working, probably because you do not respect what these functions actually do.

For example, glUseProgram causes a given program object to become a program object that will be used by any subsequent calls to glDraw* until you call glDraw* again. Think about most of the features of OpenGL that cause global state because it works. glUseProgram sets a global variable that glDraw* reads to find out which shader to use.

Therefore, if you want a specific drawing call to use a specific shader, you must mask glUseProgram in advance. Or, at least recently, enough for you to know that you have not changed it elsewhere. Typically, the rendering for an object is as follows:

  • Set the vertex attributes to render the object.
  • Set the current program and change any unified form for each object (matrix, etc.).
  • Binds textures for the program, if any.
  • Bind another state to the program, if any.
  • Render.
  • Deactivate Attributes

The first step uses glEnableVertexAttribArray , glBindBuffer and glVertexAttribPointer . These functions, like glUseProgram , set the global state. You should use glDisableVertexAttribArray after rendering with the object, and you should decouple any buffers that you may have used.

+9
source

Source: https://habr.com/ru/post/896610/


All Articles