0

I'm trying to make a cross-platform WinForms software, with a GUI and a 3D window inside of it. Currently, I have a TabControl with two tabs, and the second one needs to contain the GLControl (3D Window). However, when I switch to the second tab, the program hangs while the GLControl is loaded, presumably because they are on the same thread.

I've tried resolving it with a BackgroundWorker like this:

    private void onTabSwitch(object sender, EventArgs e)
    {
        if (tabControl.SelectedIndex == 1)
            if (area3D == null)
                this.worker.RunWorkerAsync();
    }

    ...
    ...
    ...

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        area3D = new GLControl();

        area3D.Load += new EventHandler(area3D_Load);
        area3D.Paint += new PaintEventHandler(area3D_Paint);
        area3D.BackColor = Color.Black;
        area3D.Size = new Size(438, 435);
        area3D.Location = new Point(200, 0);

        this.Invoke((MethodInvoker)delegate
        {
           secondTab.Controls.Add(area3D); // runs on UI thread
        });
    }

But it still hangs, because the second tab is still on the main GUI thread. How can I resolve this?

Bottomline, I need a 3D window in another tab that will load asynchronously, or just not cause my program to hang.

1 Answers1

0

GLControl is a WinForms control, so it has to be created on the main thread. There are various possible solutions. I would try these, in order:

  1. Switch to OpenTK 1.1 which loads faster (2x-3x times faster on Windows, depending on the GPU and CPU.)

  2. If it is just a single GLControl, force it to be created on application startup. Cache this instance and attach it to the tab manually (don't destroy and recreate it whenever you switch to/from the tab.)

    OpenGL rendering contexts are heaveweight objects, so this will be a huge win. Chances are this will resolve the issue:

    public MainForm : Form
    {
        readonly GLControl glControl = new GLControl();
    
        public MainForm()
        {
            InitializeComponent();
            glControl.CreateControl(); // Force the GLControl to be created
        }
    
        // ...
    }
    
  3. Create your own, asynchronous GLControl. GLControl consists of two parts: a System.Windows.Forms.Control (which has to be created on the main thread) and an OpenTK.GraphicsContext (which can be created on a separate thread.)

    The relevant code can be found in: opentk/Source/GLControl/GLControl.cs:203

    As you can see, this is only using public APIs of WinForms and OpenTK, so this approach is feasible. However, I would suggest trying 1 and 2 first, and only going for the nuclear solution if those fail to yield the performance improvement you are seeking.

The Fiddler
  • 2,726
  • 22
  • 28