Iluvatar's picture

RenderingContexts and Resource-Sharing with Multiple glControls?? HOW??

Hi, I didn't find anything on the Forums/Documentation that really fits :(.

I already found some informations in the documenatation, saying that all resources should be shared by default. Well that would be reeeeealy fine - since I want to write a "modeler"-program that contains two glControls!
My Controls are not exactly "glControls" but they are a objects from an inherited Class from glControl with additional Variables, like "Loaded" and "Camera" to maky things easier.
I use the .NET-Framework 4.0 with VS 2010 Ultimate and Winforms!

What I do is the following in pseudo-Code:

  1. Create two glControls with an OpenGL 3.2 Context
  2. handle the "load"-Events of the Controls
            /// <summary>
            /// Initialization when the Control is loaded
            /// </summary>
            /// <param name="sender">Event sender</param>
            /// <param name="e">Event arguments</param>
            private void glControl_Load(object sender, EventArgs e)
            {
                ///Activate the actually defined CustomGlControl
                if (!((CustomGLControl)sender).Context.IsCurrent)
                {
                    ((CustomGLControl)sender).MakeCurrent();
                }
                ///Set the Variable
                ((CustomGLControl)sender).Loaded = true;
     
                ///Set the Camera-Size
                ((CustomGLControl)sender).myCamera.SetSize(((CustomGLControl)sender).Width, ((CustomGLControl)sender).Height);
     
                ///save the values
                ((CustomGLControl)sender).PreviousWidth = ((CustomGLControl)sender).Width;
                ((CustomGLControl)sender).PreviousHeight = ((CustomGLControl)sender).Height;
     
                ///Load the needed Texture if both GLControls are loaded
                if (this.mainGlControl.Loaded && this.additionalGlControl.Loaded)
                {
                    ///Initialize the Texture to a Base-White
     
                    ImageCalculations.LoadTexture("StartUp");
                }
                ///Initialize the Renderer
                else
                {
                    ///Initialize OpenGL and set the Viewport-Size for rendering
                    Render.InitializeRenderer();
                }
            }

    "Render" is a helper-Class in my Project!
    when the Eventhandler is called the first time (for the "main"glControl) I set some GL-states (like ClearColor....) and create one Shader Program (nothing special)
    when the Eventhandler is called the second time (for the "addional"glControl) I automatically load (generate) a simle 2.x white texture

  3. The loading of the texture causes my program to generate a simple cuboid-object (VBOs and a VAO) with the same x/y aspect-ratio as the texture (so this happens always after a new texture was loaded)
            /// <summary>
            /// Sets the absolute values through the ImageCalculations-Eventhandler
            /// </summary>
            /// <param name="xSize">x-Size of the Texture</param>
            /// <param name="ySize">y-Size of the Texture</param>
            private static void SetAbsoluteValues(int xSize, int ySize)
            {
                ///Calculate the Absolute y-Factor
                float yFactor = (float)ySize / (float)xSize;
     
                ///Set the Absolute Values
                XAbsoluteValue = 1.0f;
                YAbsoluteValue = yFactor;
     
                ///TODO: CHANGE, this is only for TESTING
                if (Render.Cuboid != null)
                {
                    Render.Cuboid.Dispose();
                    GC.WaitForPendingFinalizers();
                    Render.Cuboid = null;
                }
                ///Create a new BaseShape
                Render.Cuboid = new BaseShape(ShaderManager.GetShaderProgram("Default"), new OpenTK.Vector3(XAbsoluteValue, YAbsoluteValue, 0.1f));
     
                ///Fire the Event
                Render.NeedToRender();
            }
  4. After the texture was loaded and a new Cuboid-object was created with the right dimensions the Cuboid should be rendered with the loaded texture in both glContexts

My Problem now is, that the rendering of the "Rende.Cuboid" object with the Command "GL.DrawElements" fails with this Exception:

A first chance exception of type 'System.AccessViolationException' occurred in OpenTK.dll
An unhandled exception of type 'System.AccessViolationException' occurred in OpenTK.dll
 
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

What??
Please help me, I don't know what to do :(
Whenever I render into one of my Controls I check the bound Context and make the one of the Control current if it is not already!
Another info: When i only use one Control everything is fine and works!

Thank you
Iluvatar


Comments

Comment viewing options

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

Well, in the meantime I found a threa here on the forum saying that VAOs are NOT shared between the contexts?? ;(
I think I simply will change my Project, so that only one Context and one glControl will be used.
I am going to "split" the viewport, to get it to work - I think this is the easiest way to get what I want....

the Fiddler's picture

Using a single GLControl is indeed the simplest solution and it also works on Intel cards (which cannot share contexts).

Depending on your drivers, you might have to make the first context non-current before creating the second one for the context sharing to work. You can do that by calling glControl.Context.MakeCurrent(null).

Note that you can use a single context to draw on many different windows. How? Call glControl.Context.MakeCurrent(IWindowInfo) for each window (i.e. make current and render on the first, make current and render on the second, etc). You just need to be careful that you don't send drawing commands to the wrong window. To create the necessary IWindowInfos, use OpenTK.Platform.CreateWinWindowInfo() and store the results. (Note that you may wish to do that in the HandleCreated event for extra robustness).

Iluvatar's picture

Hi, thank you for your good description! This was the thing I didn't find here (restrictions/tips for sharing contexts....)!!

I think I want to try to use one Context on both glControls, so i added a HandleCreated - Eventhandler to both glControls like this:

            this.mainGlControl.HandleCreated += new System.EventHandler(this.glControl_HandleCreated);
            this.additionalGlControl.HandleCreated += new System.EventHandler(this.glControl_HandleCreated);

I added an Platform.IWindowInfo Variable to my Custom-Controls and used the HandleCreated-Event to get the Info I need.
I only added a few Lines to handle the "HandleCreated"-Event:

        private void glControl_HandleCreated(object sender, EventArgs e)
        {
            ((CustomGLControl)sender).WinInfo = OpenTK.Platform.Utilities.CreateWindowsWindowInfo(((CustomGLControl)sender).Handle);
        }

That easy?
When the Load-Event is handled for every glControl I just added a few Lines:

            ///Set the Context of the "Main"-Control current on the actually handled Control
            if (this.mainGlControl.WinInfo != null)
            {
                this.mainGlControl.Context.MakeCurrent(((CustomGLControl)sender).WinInfo);
            }
            else
            {
                Logger.Logger.SendToLog("\"Main\"-Context was not found, check the Sequence of the glConrtols!", LogType.Errors);
            }

Do I need to do that?

But what I get now is:
No Error any more :) YAY!!!!
One Problem is, that i need to do THAT:

            this.mainGlControl.Context.MakeCurrent(this.mainGlControl.WinInfo);      ///or this.mainGlControl.Context.MakeCurrent(this.additionalGlControl.WinInfo), depending on where the rendering should go to!

Every Time??
The second Problem i get is that the mainGlControl works fine and smooth, but if i render something on the other Control (using the main-Context) i get about 2 FPS with 12 Triangles ;(

Thanks again,
Iluvatar

PS: which method to render to more than one glControl do you prefer?

Iluvatar's picture

Well that's weird :D
Now it works... (without changing anything....)
I hope this will be a stable state ;)

Thanks
Iluvatar

the Fiddler's picture

Each GLControl creates its own context, so you actually need one GLControl only. The rest can be regular Controls or UserControls.

Iluvatar's picture

Thanks for the additional Info :)
Maybe I'm going to change that, too!
Is there any "noticable" performance-problem if I use two glControls instead of one glControl and one "Panel"?

the Fiddler's picture

About 30-50ms and 50KB-5MB of memory, depending on drivers and hardware. Might come useful if you ever need to optimize startup times and memory use.

Iluvatar's picture

Ok, I think i want to stay with my two gl_Controls :) - for now :)