3
\$\begingroup\$

Quick outline:

  • Test program that loads and displays big (3k x 4k) 16bit gray scale images (ca. 32MB).
  • Using modern OpenGL (eg. 3.3 or so) with shaders VBOs VAOs etc.
  • Running on Windows with OpenTK (WinForms inside WPF) - C#
  • developing on ATI FireGL and Nvidia Quadro FX
  • using MipMapping

My test program is actually working quite well (seems like I am doing not so much wrong). I've written a load test to find threading errors and resource leaks. So ater a while of loading and closing viewers and their images, sporadically glBindVertexArray() fails in one viewer instance and works in another viewer instance. Speak: Different OpenGL contexts, same graphics card, same process, same thread.

Visually I see my OpenGL HWND filled with a red cross and a red frame.

The failing viewers become more over time. Never the less some still keep working.

  • My background loading of textures is currently disabled. So threading issues should be out of scope.
  • I do 'MakeCurrent()' the context before I draw.
  • As of WPF law, all my Viewers work in the same UI thread. (that's what I think)

So what is wrong?

It seems little like a resource problem... because the problems become more over runtime. But what could be the reasons why glBindVertexArray() fails. My workflow should be most of the time OK. So are there any data operations I have to glFlush() before I call?

Actually I tried to add a glFlush() before it but it did not resolve it.

My Program flow is a little convoluted by OO patterns but essentially boils down to that:

Creation of VAO:

int a =GL.GenVertexArray();
GL.BindVertexArray(a);
int b1= GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, b1);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(BufferSize), data, BufferUsageHint.StaticDraw);

int b2= GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, b2);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(BufferSize), data, BufferUsageHint.StaticDraw);
//->vertex data  (OO implication of multi calls)
GL.BindBuffer(BufferTarget.ArrayBuffer, b1); 
GL.BindBuffer(BufferTarget.ArrayBuffer, b1);
GL.EnableVertexAttribArray(0);
//-> texcoords
GL.VertexAttribPointer(0, elements, attrType, normalized, stride, offset);
GL.BindBuffer(BufferTarget.ArrayBuffer, b2); 
GL.BindBuffer(BufferTarget.ArrayBuffer, b2);
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, elements, attrType, normalized, stride, offset);

consider generic valid parameters.

The Draw happens about like that sequence of calls (which I hopefully reflect correctly)

MakeCurrent();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.UseProgram(prg);

// Set texture uniform
GL.Uniform1(Handle);
GL.ActiveTexture(unitnumber);
GL.BindTexture(Texture2D, Handle);

//... set some more Uniforms...
GL.GetError(); // returns NoError
// then it is over
GL.BindVertexArray(a);  // <<-- this is where it crashes sometimes!!

// this is my LUT-data but does not matter after the failing call
GL.ActiveTexture(1);
GL.BindTexture(TexTarget.TextureArray, Handle);

GL.DrawArrays(PrimitiveType.TRIANGLES, first, count);
\$\endgroup\$
  • \$\begingroup\$ As I already found out the red cross on white appearance of a viewer is caused due to any exception in the OnPaint method. Either OpenTK's GLControl or WinForms does that. \$\endgroup\$ – Robetto Mar 25 '15 at 15:37
  • \$\begingroup\$ Define "glBindVertexArray() fails". What does that actually mean? Is OpenGL reporting an error? What is the error message, if so? \$\endgroup\$ – Trevor Powell Mar 26 '15 at 7:30
  • \$\begingroup\$ It causes GL.GetError() to returen InvalidOperation. That in turn causes one of my utility methods to throw up and thus cause the red cross. -- But more importantly, during my evening I had the inspiration - I solved it. see below. \$\endgroup\$ – Robetto Mar 26 '15 at 8:08
1
\$\begingroup\$

Well.. sometimes you have to formulate a question and stop work until you find your answer yourself.

In the evening I had some thoughts about resource management. We're talking about .Net ... thus a GC is involved. What if the finalizer thread comes along at a wrong time or state. Well - that would be actually a double fault. Not more right therefore, though. We're talking about unmanaged (because external) resources that need management with IDisposable. This is also what I implemented. Unless I call Dispose() on removed viewers I'll run quickly in resource problems on the graphics card. So I do it and nothing seems wrong about it.

The real cause lies in my Dispose()-Implementation, though. And it only appears, if you use multiple viewers (thus multiple OpenGL contexts) at once. Accoring to the docs of OpenTK and it's GLControl, one has to call MakeCurrent() every so often as one uses GL-functions to work on the right context. This applies to Dispose() as well.

So what actually happened was this:

My VertexArrayObject was actually disposed (GL.DeleteVertexArray(Handle); )by another viewer that incidentally hat the same "name" in it's OpenGL-context. The problem is, my OpenGL-implementation has "name-tables" per context and so every VertexArrayObject allocated in a new viewer gets a name like 1,2,3,4 and collisions are programmed.

So changing my Dispose to something like that solved it:

    protected override void Dispose(bool disposeCall)
    {
        if (disposeCall)
        {
            this.MakeCurrent();
            _overlay.Dispose();
            _drawing.Dispose();
            _shaderProgram.Dispose();
            _texture.TryDispose();
            _lutTexBuffer.Dispose();
        }
        base.Dispose(disposeCall);
    }

Now I make sure to only delete my own resources to (colliding) names

\$\endgroup\$
  • 1
    \$\begingroup\$ So this was nothing to do with garbage collection at all. The problem was that you had multiple OpenGL contexts in one process, and you weren't setting the OpenGL context to use, before telling OpenGL to destroy objects. This meant that sometimes you were unintentionally deleting objects out of the wrong context. Which unsurprisingly leads to errors when you subsequently tried to draw using those deleted objects. \$\endgroup\$ – Trevor Powell Mar 26 '15 at 12:47
  • \$\begingroup\$ Very well said. A helper/disturber was the high collision probability of OpenGL names. \$\endgroup\$ – Robetto Mar 27 '15 at 8:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.