首页 > 解决方案 > 为什么两个glcontrols的OnPaint事件不同步运行 - opentk c#

问题描述

我有两个 glControls。每个都有它的油漆事件。但在完整运行paint1事件的功能之前,系统调用了paint2事件。我认为每个事件中的函数将完全同步调用。我可以那样做吗。意思是,paint2 事件应该在完成paint1 事件后调用?

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);
  }
}

现在在运行此代码时,paint1 会引发以下异常。这是因为 render2() 在完成 render() 之前调用。

OpenTK.Graphics.GraphicsContextException:'无法交换当前上下文 131072 的缓冲区。

标签: c#openglsynchronizationopentkonpaint

解决方案


一种快速简单的方法是lock在您的代码中添加...

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();
    }

}

当一个代码块锁定时locker,任何其他锁定尝试都将被延迟,直到第一个锁定被清除。

如果您需要进一步控制锁的顺序,您可以使用队列来保存一个标识符,该标识符是哪个代码块试图获得锁,如果它不是您想要的第一个,则延迟该锁直到正确一个先锁。但是,如果由于某种原因没有发生预期的“第一个”锁定,这可能会导致问题。然后第二个不会,除非您添加等待超时。

编辑:

在你的Render职能...

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();
}

我相信你打电话GL.Clear()太多了。它实际上只需要在每个循环中调用一次。另外,由于您是双重缓冲,因此我认为不会GL.Flush()为您做任何事情。

除此之外,我认为问题不在于您提供的代码,而可能与您的glControl1and的构造或配置有关glControl2


推荐阅读