I tried to get SkiaSharp to work with an OpenGL backend in a Windows App, so I found this example on the internet https://gist.github.com/d-kr/eeced4157bf926accc9c6ad435d37a37.
On my laptop running a GTX1050 everything works fine, but on my Desktop running a GTX1060 it doesn't. Both systems run Windows. As You can see in the image below an OpenTK GameWindow is created and filled.
On my laptop you can see circles being drawn, but on my desktop it throws an error message saying ERROR creating stencil attachment. Draw skipped
. I was able to track down the error to OnRenderFrame()
, occurring when canvas.DrawCircle()
is called.
I know SkiaSharp quite well but I'm quite new to OpenTK. What am I missing here? On Google I only found this post https://groups.google.com/forum/#!topic/skia-discuss/m53JH2scDh4 which suggests that this is some kind of setup or hardware problem. So where do I start debugging this? These are my dependencies:
Thanks in advance!
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using SkiaSharp;
using System;
using System.Diagnostics;
// https://gist.github.com/d-kr/eeced4157bf926accc9c6ad435d37a37
namespace NetCoreDesktop
{
public sealed class MainWindow : GameWindow
{
private GRContext context;
private GRBackendRenderTargetDesc renderTarget;
public MainWindow()
: base(1280, // initial width
720, // initial height
GraphicsMode.Default,
"window", // initial title
GameWindowFlags.Default,
DisplayDevice.Default,
1, // OpenGL major version
0, // OpenGL minor version
GraphicsContextFlags.ForwardCompatible) {
Title += ": OpenGL Version: " + GL.GetString(StringName.Version);
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
var glInterface = GRGlInterface.CreateNativeGlInterface();
Debug.Assert(glInterface.Validate());
this.context = GRContext.Create(GRBackend.OpenGL, glInterface);
Debug.Assert(this.context.Handle != IntPtr.Zero);
this.renderTarget = CreateRenderTarget();
CursorVisible = true;
}
protected override void OnUnload(EventArgs e) {
base.OnUnload(e);
this.context?.Dispose();
this.context = null;
}
protected override void OnResize(EventArgs e) {
GL.Viewport(0, 0, Width, Height);
}
protected override void OnUpdateFrame(FrameEventArgs e) {
HandleKeyboard();
}
private void HandleKeyboard() {
var keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Key.Escape)) {
Exit();
}
}
public static GRBackendRenderTargetDesc CreateRenderTarget() {
GL.GetInteger(GetPName.FramebufferBinding, out int framebuffer);
GL.GetInteger(GetPName.StencilBits, out int stencil);
GL.GetInteger(GetPName.Samples, out int samples);
int bufferWidth = 0;
int bufferHeight = 0;
GL.GetRenderbufferParameter(RenderbufferTarget.Renderbuffer, RenderbufferParameterName.RenderbufferWidth, out bufferWidth);
GL.GetRenderbufferParameter(RenderbufferTarget.Renderbuffer, RenderbufferParameterName.RenderbufferHeight, out bufferHeight);
return new GRBackendRenderTargetDesc {
Width = bufferWidth,
Height = bufferHeight,
Config = GRPixelConfig.Bgra8888, // Question: Is this the right format and how to do it platform independent?
Origin = GRSurfaceOrigin.TopLeft,
SampleCount = samples,
StencilBits = stencil,
RenderTargetHandle = (IntPtr)framebuffer,
};
}
protected override void OnRenderFrame(FrameEventArgs e) {
base.OnRenderFrame(e);
Title = $"(Vsync: {VSync}) FPS: {1f / e.Time:0}";
Color4 backColor;
backColor.A = 1.0f;
backColor.R = 0.1f;
backColor.G = 0.1f;
backColor.B = 0.3f;
GL.ClearColor(backColor);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
this.renderTarget.Width = this.Width;
this.renderTarget.Height = this.Height;
using (var surface = SKSurface.Create(this.context, this.renderTarget)) {
Debug.Assert(surface != null);
Debug.Assert(surface.Handle != IntPtr.Zero);
var canvas = surface.Canvas;
canvas.Flush();
var info = this.renderTarget;
//canvas.Clear(SKColors.Beige);
using (SKPaint paint = new SKPaint {
Style = SKPaintStyle.Stroke,
Color = SKColors.Red,
StrokeWidth = 25
}) {
canvas.DrawCircle(info.Width / 2, info.Height / 2, 100, paint);
paint.Style = SKPaintStyle.Fill;
paint.Color = SKColors.Blue;
canvas.DrawCircle(info.Width / 2, info.Height / 2, 100, paint);
}
canvas.Flush();
}
this.context.Flush();
SwapBuffers();
}
}
}
For some reason, StencilBits is set to zero, which is not valid. Setting it to a fixed value (like 1) helps.
public static GRBackendRenderTargetDesc CreateRenderTarget() {
...
return new GRBackendRenderTargetDesc {
...
StencilBits = 1,
...
};
}