sjoerd222's picture

VBO + drawArray -> AccessViolation Exception

Hi

I'm trying to use VBOs and get an AccesVioaltion Exception. Not immediately but after spinning my 3D object around long enough. For me it's not so clear what happens here.

I think the problem lies in the buffer creation or in the rendering function:

public void CreateBuffer(ref float[] vertices_LAB, int vertices_LAB_count)
        {
            // Format of array : x,y,z
 
            v_LAB = vertices_LAB;
 
            v_LAB_count = vertices_LAB_count;
 
            GL.GenBuffers(1, out vbo);
            GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
            GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(sizeof(float)*v_LAB.Length),v_LAB ,BufferUsageHint.DynamicDraw);
            GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(v_LAB_count * 3 * sizeof(float)), v_LAB, BufferUsageHint.DynamicDraw);
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
        }
 public void Render(ref Matrix4 mvpMatrix)
        {
            GL.Enable(EnableCap.AlphaTest);
            GL.Enable(EnableCap.Blend);
 
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.One);
 
            GL.UseProgram(shaderProg.GetId());
 
 
            GL.EnableClientState(ArrayCap.VertexArray);
            GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
 
            foreach (int id in dict_attrib.Values)
            {
                GL.EnableVertexAttribArray(id);
            }
 
            GL.UniformMatrix4(dict_uniform["u_mvpMatrix"], false, ref mvpMatrix);
            GL.Uniform1(dict_uniform["u_useTrueColor"], useTrueColor);
            GL.Uniform1(dict_uniform["u_useTransparence"], useTransparence);
            GL.Uniform4(dict_uniform["u_color"], pointColor);
 
            GL.VertexAttribPointer(dict_attrib["a_position"], 3, VertexAttribPointerType.Float, false, sizeof(float)*3, sizeof(float)*0);
 
            GL.VertexPointer(3, VertexPointerType.Float, 3 * sizeof(float), new IntPtr(0));
            GL.DrawArrays(BeginMode.Lines, 0, 12); //<--- Hardcoded for testing there are 36 elements in the array, 3d, meaning 12 'items'
 
            GL.DisableClientState(ArrayCap.VertexArray);
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
            GL.Disable(EnableCap.AlphaTest);
            GL.Disable(EnableCap.Blend);
        }

I'm also not sure if I need this calls at all:

GL.VertexPointer(3, VertexPointerType.Float, 3 * sizeof(float), new IntPtr(0));
GL.EnableClientState(ArrayCap.VertexArray);

Cause they don't change anything. What I tried is to play around with GL.DrawArrays(BeginMode.Lines, 0, n); and change n to lower numbers like 6, but even then crashes seem to occur. I also investigated the content of the vertices_LAB array in the CreateBuffer function while debugging. He contains 36 values. vertices_LAB_count is 12.

Thank you very much for reading!


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
reibisch's picture

Are you sure that v_LAB.Length equals v_LAB_count? If not, that could be causing some problems. I would rely exclusively on v_LAB.Length unless you only wanted to use a subset (in which case you might consider using a start and length). Also, from my understanding, you're immediately overwriting the content that you wrote to your vbo buffer.

GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(sizeof(float)*v_LAB.Length),v_LAB ,BufferUsageHint.DynamicDraw);
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(v_LAB_count * 3 * sizeof(float)), v_LAB, BufferUsageHint.DynamicDraw);

EDIT: Missed the last part of your post there, sorry.

If vertices_LAB.Length is 36 and vertices_LAB_count is 12 and you try to draw 12 lines (which require 24 vertices), then you'd likely have an issue (though I'm not sure how it would manifest itself).

Also, these calls are crucially important.

GL.VertexPointer(3, VertexPointerType.Float, 3 * sizeof(float), new IntPtr(0));
GL.EnableClientState(ArrayCap.VertexArray);
sjoerd222's picture

Thx for your respond!

GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(sizeof(float)*v_LAB.Length),v_LAB ,BufferUsageHint.DynamicDraw); is the call I use. The other should have been commented out.

reibisch wrote:

If vertices_LAB.Length is 36 and vertices_LAB_count is 12 and you try to draw 12 lines (which require 24 vertices), then you'd likely have an issue (though I'm not sure how it would manifest itself).

When I draw 12 lines and each point takes x,y,z (3) then I then whole array of vertices's should have I count of 36 and not 24.

reibisch wrote:

Also, these calls are crucially important.
GL.VertexPointer(3, VertexPointerType.Float, 3 * sizeof(float), new IntPtr(0));
GL.EnableClientState(ArrayCap.VertexArray);

Why are this calls crucial? The crash seems not related to this calls.

I found this example:

void drawPrimitiveWithVBOs(GLint numVertices, GLfloat *vtxBuf,
GLint vtxStride, GLint numIndices,
GLushort *indices)
{
GLuint offset = 0;
GLuint vboIds[2];
// vboIds[0] – used to store vertex attribute data
// vboIds[1] – used to store element indices
glGenBuffers(2, vboIds);
glBindBuffer(GL_ARRAY_BUFFER, vboIds[0]);
glBufferData(GL_ARRAY_BUFFER, vtxStride * numVertices,
vtxBuf, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIds[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
sizeof(GLushort) * numIndices,
indices, GL_STATIC_DRAW);
glEnableVertexAttribArray(VERTEX_POS_INDX);
glEnableVertexAttribArray(VERTEX_NORMAL_INDX);
glEnableVertexAttribArray{VERTEX_TEXCOORD0_INDX);
glVertexAttribPointer(VERTEX_POS_INDX, VERTEX_POS_SIZE,
GL_FLOAT, GL_FALSE, vtxStride,
(const void*)offset);
offset += VERTEX_POS_SIZE * sizeof(GLfloat);
glVertexAttribPointer(VERTEX_NORMAL_INDX, VERTEX_NORMAL_SIZE,
GL_FLOAT, GL_FALSE, vtxStride,
(const void*)offset);
offset += VERTEX_NORMAL_SIZE * sizeof(GLfloat);
glVertexAttribPointer(VERTEX_TEXCOORD0_INDX,
VERTEX_TEXCOORD0_SIZE,
GL_FLOAT, GL_FALSE, vtxStride,
(const void*)offset);
glBindAttribLocation(program, VERTEX_POS_INDX, "v_position");
glBindAttribLocation(program, VERTEX_NORMAL_INDX, "v_normal");
glBindAttribLocation(program, VERTEX_TEXCOORD0_INDX,
"v_texcoord");
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0);
glDeleteBuffers(2, vboIds);
}

But so, what's the big difference to my code except that they use an indices and thus glDrawElements instead of glDrawArray. (Btw. I tried it with glDrawElements with a stupied indices array of 0,1,2,...,11 and the same behavior, crash after spinning around the 3D object long enough.

sjoerd222's picture

Problem resolved:

various missing GL.DisableVertexAttribArray(id) caused the exception.

GL.VertexPointer(3, VertexPointerType.Float, 3 * sizeof(float), new IntPtr(0));
GL.EnableClientState(ArrayCap.VertexArray);

are NOT crucial to my understanding. I think that the call is even wrong here as I use vertexAttribPointer INSTEAD.
Important is to call GL.DisableVertexAttribArray(id) after GL.EnableVertexAttribArray(id). Maybe the crashed occurred, cause I mixed VBO with non VBO rendering.

the Fiddler's picture

You are right, this code is not needed when using generic vertex attributes (VertexAttribPointer). You need to call DisableVertexAttribArray to disable any ids you are not using, otherwise OpenGL will try to read from those (and crash, if the bound VBO has a different layout from what it expected).

Starting with OpenGL 3.x, you can VAOs (Vertex Array Objects) to encapsulate this information and avoid calling Disable/EnableVertexAttribArray for each and every VBO.