Почему событие OnPaint двух glcontrols не работает синхронно - opentk c # - PullRequest
0 голосов
/ 28 мая 2019

У меня есть два 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.

1 Ответ

0 голосов
/ 28 мая 2019

Быстрый и простой способ - добавить 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() что-то делает для вас, поскольку вы используете двойную буферизацию.

Кроме того, я не думаю, что проблема заключается в коде, который вы предоставили, но, скорее всего, что-то с конструкцией или конфигурацией ваших glControl1 и glControl2.

...