PDA

View Full Version : glDrawArrays race condition



weak
10-11-2008, 09:31 AM
Hello everybody,

I'm experiencing a strange problem with glDrawArrays()on the Ipod Touch (OS version 2.0, OGL ES 1.1), and while I think I've already found a working solution, I still don't really understand why it actually works. I was hoping somebody could clarify the following for me:



void Foo::drawSome()
{
GLfloat *vertices = new GLfloat[strLength*12];
GLfloat *coordinates = new GLfloat[strLength*18];

// fill with correct verts and coords...

// draw stuff
glPushMatrix();

glTranslatef(x, y, 0.0f);

glBindTexture(GL_TEXTURE_2D, m_fontTex.name);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
glDrawArrays(GL_TRIANGLES, 0, strLength*6);

glPopMatrix();

// here it crashes, basically complaining that I'm freeing memory still in use
delete [] vertices;
delete [] coordinates;
}


The crash occurs as soon as I reach a certain amount of verts. Obviously the arrays are still in use when I try to free the memory.

The solution is to use static arrays like this:


void Foo::drawSome()
{
GLfloat vertices[256*18];
GLfloat coordinates[256*12];

// fill with correct verts and coords...

// draw stuff
glPushMatrix();

glTranslatef(x, y, 0.0f);

glBindTexture(GL_TEXTURE_2D, m_fooTex.name);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
glDrawArrays(GL_TRIANGLES, 0, strLength*6);

glPopMatrix();
}


I don't understand why this works and dynamically allocated arrays don't. Shouldn't the static arrays be gone as soon as the function returns?
So what's the real difference? Does the data on the stack live longer? Long enough for it to work?

Please explain...

oddhack
10-11-2008, 10:04 PM
I don't know the guts of their implementation, so I'm just speculating: it's possible that delete[] can detect that the GL driver is still using that memory, while stack memory is freed just by adjusting the stack pointer, which might not be detected and/or detectable.

It's risky to do either, since the only way to know that the driver is done with the vertices you pass in is to do a server round trip such as glFinish() - which itself may kill performance, as may dynamic allocations on every call. Especially if the arrays are as tiny as your code suggests.

I suggest you instead look at using either vertex buffer objects, or client memory that doesn't get reallocated every time you call your draw routine.

weak
10-12-2008, 05:49 AM
I don't know the guts of their implementation, so I'm just speculating: it's possible that delete[] can detect that the GL driver is still using that memory, while stack memory is freed just by adjusting the stack pointer, which might not be detected and/or detectable.

It's risky to do either, since the only way to know that the driver is done with the vertices you pass in is to do a server round trip such as glFinish() - which itself may kill performance, as may dynamic allocations on every call. Especially if the arrays are as tiny as your code suggests.

I suggest you instead look at using either vertex buffer objects, or client memory that doesn't get reallocated every time you call your draw routine.

Well, I have to admit that I didn't read the specification in detail. So glDrawArrays() returning doesn't guarantee that the vertex data has been transfered to the GL?

oddhack
10-12-2008, 01:20 PM
Well, I have to admit that I didn't read the specification in detail. So glDrawArrays() returning doesn't guarantee that the vertex data has been transfered to the GL?

According to the GL spec, data binding should happen when you call DrawArrays. But the error you report is consistent with the implementation not actually doing this, and implementations have been known to do a lot of wacky things (I'm envisioning something like a command buffer that just stores a command token and pointer value, that doesn't get emptied by the driver until well after you call delete[] / return from your draw routine).

Whether or not that's happening, allocating vertex buffer memory in your inner drawing loop is still something to avoid.