What I want to do:
The main goal: Use SkiaSharp and OpenTK together. Render 2D and 3D.
What is the problem: SkiaSharp messes up the state of OpenGL, so I can't use it for 3D without saving and restoring some states.
Old solution (with OpenGL < 4): I used GL.PushClientAttrib(ClientAttribMask.ClientAllAttribBits); + some additional values (saved/restored them).
Now i read that this is not necessary the best solution and OpenGL 4 does not have GL.PushClientAttrib anymore. The usual way seems to be that you should use a seperate OpenGL context.
Have seen already: OpenTK multiple GLControl with a single Context
I am not using GLControl because I am not using WinForms. So this is not really helpful. What I tried:
internal class Program
{
public static void Main(string[] args)
{
new Program().Run();
}
private readonly GameWindow _gameWindow;
private IGraphicsContext _context2;
private GlObject _glObject;
private int _programId;
private GlObject _glObject2;
private int _programId2;
public Program()
{
_gameWindow = new GameWindow(800,600,
GraphicsMode.Default, "", GameWindowFlags.Default,
DisplayDevice.Default,
4, 2, GraphicsContextFlags.ForwardCompatible);
_gameWindow.Resize += OnResize;
_gameWindow.RenderFrame += OnRender;
_gameWindow.Load += OnLoad;
}
public void Run()
{
_gameWindow.Run();
}
private void OnLoad(object sender, EventArgs e)
{
_programId = ShaderFactory.CreateShaderProgram();
_glObject = new GlObject(new[]
{
new Vertex(new Vector4(-0.25f, 0.25f, 0.5f, 1f), Color4.Black),
new Vertex(new Vector4(0.0f, -0.25f, 0.5f, 1f), Color4.Black),
new Vertex(new Vector4(0.25f, 0.25f, 0.5f, 1f), Color4.Black),
});
_context2 = new GraphicsContext(GraphicsMode.Default, _gameWindow.WindowInfo, 4, 2,
GraphicsContextFlags.Default);
_context2.MakeCurrent(_gameWindow.WindowInfo);
_programId2 = ShaderFactory.CreateShaderProgram();
_glObject2 = new GlObject(new[]
{
new Vertex(new Vector4(-0.25f, 0.25f, 0.5f, 1f), Color4.Yellow),
new Vertex(new Vector4(0.0f, -0.25f, 0.5f, 1f), Color4.Yellow),
new Vertex(new Vector4(0.25f, 0.25f, 0.5f, 1f), Color4.Yellow),
});
_gameWindow.MakeCurrent();
}
private void OnRender(object sender, FrameEventArgs e)
{
_gameWindow.Context.MakeCurrent(_gameWindow.WindowInfo);
GL.Viewport(0, 0, _gameWindow.Width, _gameWindow.Height);
GL.ClearColor(0.3f,0.1f,0.1f,1);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.UseProgram(_programId);
_glObject.Render();
GL.Flush();
_gameWindow.SwapBuffers();
// i tried different combinations here
// as i read GL.Clear will always clear the whole window
_context2.MakeCurrent(_gameWindow.WindowInfo);
GL.Viewport(10,10,100,100);
//GL.ClearColor(0f, 0.8f, 0.1f, 1);
//GL.Clear(ClearBufferMask.ColorBufferBit);
GL.UseProgram(_programId2);
_glObject2.Render();
GL.Flush();
_context2.SwapBuffers();
}
private void OnResize(object sender, EventArgs e)
{
var clientRect = _gameWindow.ClientRectangle;
GL.Viewport(0, 0, clientRect.Width, clientRect.Height);
}
}
Vertex shader:
#version 450 core
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 color;
out vec4 vs_color;
void main(void)
{
gl_Position = position;
vs_color = color;
}
Fragment shader:
#version 450 core
in vec4 vs_color;
out vec4 color;
void main(void)
{
color = vs_color;
}
Works fine with a single context, when I use both contexts what happens is: first context gets rendered but flickers. There is no second triangle visible at all (as i understand GL.Viewport it should be visible on the lower left corner of the screen).
You could help me by answering one or more of the following questions:
After trying some more combinations what did the trick was:
Call SwapBuffers only on the last used context in render (even when you use 3 contexts). Then no flicker will occur and rendering seems to work fine. State seems to be independent from each other.