c# - 为什么两个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 的缓冲区。
解决方案
一种快速简单的方法是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
and的构造或配置有关glControl2
。
推荐阅读
- google-apps-script - Google sheet onOpen() 触发器不会在移动浏览器或移动应用程序上触发
- google-chrome - Chrome devtools 不显示所有控制台错误
- typescript - 我如何告诉打字稿元组中的最后一个参数始终是一个函数?
- javascript - 滚动页面 selenium webdriver JS
- mdriven - MDriven中的继承规则?
- swift - 创建会话管理器以快速了解超时
- c# - 使用 Linq 为每个 ID 选择具有最大日期的所有对象
- go - 我正在尝试对 openshift 服务进行 2 部分 API 调用。GET 的结果用作 POST 的有效负载
- javascript - 返回 Angular 上的预览页面
- c - 后增量作为索引混淆