简体   繁体   中英

Why OnPaint event of two glcontrols not running synchronously - opentk c#

I have two glControls. Each have it's on paint event. But before completely running the functions of paint1 event, system calls paint2 event. I thought the functions inside each event will be called completely synchronously. Can I make that way. Means, paint2 event should be called after completing paint1 event?

private void Form3_Load(object sender, EventArgs e)
    {
       glControl1.Visible = true;
       glControl2.Visible = true;
       GL.Enable(EnableCap.DepthTest);
    }
    private void glControl1_Load(object sender, EventArgs e)
    {
        if (glControl2.Created &&
                                glControl2.Context.IsCurrent)
        { glControl2.Context.MakeCurrent(null); }

        if (glControl1.Context.IsCurrent == false)
        {
            glControl1.MakeCurrent();
        }
        obj_openTK.Init();
    }

    private void glControl2_Load(object sender, EventArgs e)
    {
        if (glControl1.Created &&
         glControl1.Context.IsCurrent)
        { glControl1.Context.MakeCurrent(null); }

        if (glControl2.Context.IsCurrent == false)
        { glControl2.MakeCurrent(); }

        obj_openTK.Init();
    }
    private void glControl1_Paint(object sender, PaintEventArgs e)
    {
            if (glControl2.Created &&
                     glControl2.Context.IsCurrent)
            { glControl2.Context.MakeCurrent(null); }

            if (glControl1.Context.IsCurrent == false)
            { glControl1.MakeCurrent(); }

            Render();
    }
     private void glControl2_Paint(object sender, PaintEventArgs e)
    {
          try{
            if (glControl1.Created &&
            glControl1.Context.IsCurrent)
            { glControl1.Context.MakeCurrent(null); }

            if (glControl2.Context.IsCurrent == false)
            { glControl2.MakeCurrent(); }
            Render2();
             }
            catch(Exception ex)
           {
            string exx = ex.ToString();
            string stacktrace = ex.StackTrace.ToString();
           }
        }
    private void Render()//for first image
    {
        GL.DeleteTextures(1, ref texture);
        texture = obj_openTK.LoadTexture(image);
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        obj_openTK.DrawImage(texture,glControl1);
        GL.Flush();
        glControl1.SwapBuffers();
    }
    private void Render2()// for second image
    {
        GL.DeleteTextures(1, ref texture);
        texture = obj_openTK.LoadTexture(image2);
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);         
        obj_openTK.DrawImage(texture, glControl2);
        GL.Flush();
        glControl2.SwapBuffers();
    }
    ===============openTK class========================

class openTK
{
int positionLocation1;
int program;
int positionLocation;
int vertShader;
int fragShader;
int buffer;
float[] vertices = {
    // Left bottom triangle
    -1f, -1f, 0f,
    1f, -1f, 0f,
    1f, 1f, 0f,
    // Right top triangle
    1f, 1f, 0f,
   -1f, 1f, 0f,
   -1f, -1f, 0f
};

public int LoadTexture(Bitmap bitmap)
{
int tex = -1;
if (bitmap != null)
{
    GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);

    GL.GenTextures(1, out tex);
    GL.BindTexture(TextureTarget.Texture2D, tex);

    bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
    BitmapData data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
   ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

    GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,
    OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
    bitmap.UnlockBits(data);

    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
}
return tex;
}
public void DrawImage(int image, GLControl glControl)
{
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadIdentity();
GL.Disable(EnableCap.Lighting);
GL.Enable(EnableCap.Texture2D);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, image);
GL.Uniform1(positionLocation1, 0);

RunShaders();

GL.Disable(EnableCap.Texture2D);
GL.PopMatrix();

GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();

GL.MatrixMode(MatrixMode.Modelview);

ErrorCode ec = GL.GetError();
if (ec != 0)
    System.Console.WriteLine(ec.ToString());
Console.Read();            
}
  private void RunShaders()
 {
 GL.UseProgram(program);
 GL.DrawArrays(PrimitiveType.Triangles, 0, vertices.Length / 3);
 ErrorCode ec = GL.GetError();
 if (ec != 0)
 System.Console.WriteLine(ec.ToString());
 Console.Read();
 }   
 private void Init()
 {
 CreateShaders();
 CreateProgram();   
 InitBuffers();
 }  
 private void CreateProgram()
 {
 program = GL.CreateProgram();
 GL.AttachShader(program, vertShader);
 GL.AttachShader(program, fragShader);
 GL.LinkProgram(program);
 }
private void InitBuffers()
{
buffer = GL.GenBuffer();
positionLocation = GL.GetAttribLocation(program, "a_position");
positionLocation1 = GL.GetUniformLocation(program, "sTexture");
GL.EnableVertexAttribArray(positionLocation);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float, false, 0, 0);
}
private void CreateShaders()
{
/***********Vert Shader********************/
vertShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertShader, @"attribute vec3 a_position;
                    varying vec2 vTexCoord;
                    void main() {
                    vTexCoord = (a_position.xy+1)/2 ;
                    gl_Position = vec4(a_position, 1);
                    }");
GL.CompileShader(vertShader);

/***********Frag Shader ****************/
fragShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragShader, @"precision highp float;
uniform sampler2D sTexture;varying vec2 vTexCoord; 
             void main ()
             {
           vec4    color   = texture2D (sTexture, vTexCoord);
           gl_FragColor    = color;                 
             }");
GL.CompileShader(fragShader);
  }
}

Now when running this code , paint1 throws below exception. It is because render2() is calling before completing render().

OpenTK.Graphics.GraphicsContextException: 'Failed to swap buffers for context 131072 current.

A quick and simple way would be by adding a lock to your code...

private object locker = new object();

private void glControl1_Paint(object sender, PaintEventArgs e)
{
    lock(locker) {
       if (glControl2.Created &&
                 glControl2.Context.IsCurrent)
       { glControl2.Context.MakeCurrent(null); }

       if (glControl1.Context.IsCurrent == false)
       { glControl1.MakeCurrent(); }

       Render();
    }         
}

private void glControl2_Paint(object sender, PaintEventArgs e)
{
    lock(locker) {
       if (glControl1.Created &&
          glControl1.Context.IsCurrent)
       { glControl1.Context.MakeCurrent(null); }

       if (glControl2.Context.IsCurrent == false)
       { glControl2.MakeCurrent(); }

       Render2();
    }

}

When one block of code gets a lock on locker , then any other attempt to lock will be delayed until the first lock is cleared.

If you need to control further the order of the lock, you could use a queue to hold an identifier on which block of code is trying to get a lock, if it isn't the one you want first, delay that lock until the correct one locks first. This could cause issues however, if for some reason the expected "first" lock does not happen. Then the second will not, unless you add a wait timeout.

EDIT:

In your Render functions...

private void Render()
{
    GL.DeleteTextures(1, ref texture);
    texture = obj_openTK.LoadTexture(image);

    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
    obj_openTK.DrawImage(texture,glControl1);
    GL.Flush();
    glControl1.SwapBuffers();
}
private void Render2()
{
    GL.DeleteTextures(1, ref texture2);
    texture2 = obj_openTK.LoadTexture(image2);

    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

    obj_openTK.DrawImage(texture2, glControl2);
    GL.Flush();
    glControl2.SwapBuffers();
}

I believe you are calling GL.Clear() too much. It really only needs to be called once per loop. Also, I do not think GL.Flush() is doing anything for you since you are double buffering.

Beyond that, I do not believe the problem lies in the code you have provided, but likely something with the construction or configuration of your glControl1 and glControl2 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM