luca-piccioni / OpenGL.Net

Modern OpenGL bindings for C#.
MIT License
568 stars 108 forks source link

Other control not refreshed #74

Open antoinecla opened 6 years ago

antoinecla commented 6 years ago

Steps to reproduce:

This is a simple example but in my own application with a complex user interface most of the other controls are not refreshed at all.

I just discovered the issue when integrating to my main application the GlControl / Scene I developed separately. Problem: I am due to present the prototype at the end of the week!!

This presentation is critical for me and I am stuck. I am unable to debug the issue and have no enough time to switch to an other binding.

Let me know if you can look into this issue.

luca-piccioni commented 6 years ago

This seems related to other issue #70. Tonight I'll investigate on this.

luca-piccioni commented 6 years ago

Are you setting Animation to true? Do you have tried to use a Forms.Timer calling Invalidate() on GlControl?

antoinecla commented 6 years ago

Many thanks for replying so quickly.

Just tried to disable Animation and use a Timer instead. This solve the issue.

What I don't understand is that the first thing I tried is to disable Animation and still had the refresh issue on the rest of the UI. Now, it seems to work.

In between, I tried many different things. Maybe I changed something else that had a positive side effect. In any case, try the steps above to reproduce the issue.

At least, I now have a working solution! Thanks again for your feedback.

antoinecla commented 6 years ago

I am not sure this is related.

I have a strange behavior when using two GlControl in the same form. Both controls use the OwnContext property. It seems anyway that setting a texture in one control affects the other one. Is this expected?

On a side note, I have checked the ContextSharing/SimpleSharing sample and get an exception on start:

System.InvalidOperationException: no GlControl sharing with TestGroup
   at OpenGL.GlControl.ReuseOtherContext() in GlControl.cs:line 836
   at OpenGL.GlControl.CreateContext() in GlControl.cs:line 668
   at OpenGL.GlControl.OnHandleCreated(EventArgs e) in GlControl.cs:line 1108
   at System.Windows.Forms.Control.WmCreate(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   at System.Windows.Forms.ContainerControl.WndProc(Message& m)
   at System.Windows.Forms.UserControl.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
antoinecla commented 6 years ago

I have found an explanation for the first part of my last comment.

Here is what I am doing:

Since everything is happening on the same thread, the approach appeared valid to me. Wrong! Obviously, this cannot work. There is no way to guaranty that an OpenGL resource is created on the DeviceContext of the corresponding GlControl.

A call to MakeCurrentContext() prior to creating the GL resource solve the issue.

What can be confusing is that you do not need to do that inside OnContextCreated(), OnRender(), the related events and all methods called by them. The problem arises when one of this methods is also called from the "outside".

A note in the Common Mistakes section in your wiki could be useful!

luca-piccioni commented 6 years ago

I have a strange behavior when using two GlControl in the same form. Both controls use the OwnContext property. It seems anyway that setting a texture in one control affects the other one. Is this expected?

Leaving ContextSharing to OwnContext, creates a GL context for each GlControl; and they share the same namespace using wglShareLists. Indeed textures and other objects exists for every GL context. This behavior is expected: contexts shares resources.

A call to MakeCurrentContext() prior to creating the GL resource solve the issue.

I suspect that the thread executing the event handle is not the UI thread. Normally all UserControl methods are called by the UI thread, which the context is current due the OnPaint override. What is the value of DeviceContext.GetCurrentContext() in the event handler? What is the thread ID?

Normally this issue is solved by having a dirty bit that command a GL operation in ContextUpdate.

antoinecla commented 6 years ago

I suspect that the thread executing the event handle is not the UI thread. Normally all UserControl methods are called by the UI thread, which the context is current due the OnPaint override. What is the value of DeviceContext.GetCurrentContext() in the event handler? What is the thread ID?

Remember there are two GlControl in the same form. At any moment, the Context can switch from one to the other. Here is a scenario:

Normally this issue is solved by having a dirty bit that command a GL operation in ContextUpdate.

Totally agree. I was thinking about something like that.

antoinecla commented 6 years ago

Assuming a Form with two GlControl and the following code:

    public partial class Form1 : Form
    {
        uint _Shader;

        public Form1()
        {
            InitializeComponent();
        }

        private void glControl1_ContextCreated(object sender, GlControlEventArgs e)
        {
        }

        private void glControl1_ContextDestroying(object sender, GlControlEventArgs e)
        {
        }

        private void glControl2_ContextCreated(object sender, GlControlEventArgs e)
        {
            _Shader = Gl.CreateShader(ShaderType.VertexShader);
        }

        private void glControl2_ContextDestroying(object sender, GlControlEventArgs e)
        {
            IntPtr context = DeviceContext.GetCurrentContext();
            if(context != IntPtr.Zero)
            {
                Gl.DeleteShader(_Shader);
            }
        }
    }

When closing the form and upon deletion of the shader, I get the GL error: InvalidValue (call stack below).

Inspecting the CurrentContext in glControl2_ContextDestroying() shows it is different from both the glControl1 and glControl2 context.

What is this third context? Why the shader cannot be deleted?

If I move the code from glControl2 to glControl1, the shader is deleted without issue.

Partial Call Stack:

>   OpenGL.Net.dll!OpenGL.Gl.CheckErrors() Line 499 C#
    OpenGL.Net.dll!OpenGL.Gl.DebugCheckErrors(object returnValue) Line 511  C#
    OpenGL.Net.dll!OpenGL.Gl.DeleteShader(uint shader) Line 1227    C#
    GlNetDualControlTest.exe!GlNetDualControlTest.Form1.glControl2_ContextDestroying(object sender, OpenGL.GlControlEventArgs e) Line 47    C#
    OpenGL.Net.WinForms.dll!OpenGL.GlControl.OnContextDestroying() Line 1024    C#
    OpenGL.Net.WinForms.dll!OpenGL.GlControl.OnHandleDestroyed(System.EventArgs e) Line 1130    C#
    System.Windows.Forms.dll!System.Windows.Forms.Control.WmDestroy(ref System.Windows.Forms.Message m) Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.ScrollableControl.WndProc(ref System.Windows.Forms.Message m) Unknown
    System.Windows.Forms.dll!System.Windows.Forms.ContainerControl.WndProc(ref System.Windows.Forms.Message m)  Unknown
    System.Windows.Forms.dll!System.Windows.Forms.UserControl.WndProc(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam)  Unknown
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    System.Windows.Forms.dll!System.Windows.Forms.UnsafeNativeMethods.DestroyWindow(System.Runtime.InteropServices.HandleRef hWnd)  Unknown
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DestroyHandle()  Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.DestroyHandle()   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.Dispose(bool disposing)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Form.Dispose(bool disposing)  Unknown