使用SkiaSharp的Silk.NET窗口出现闪烁问题求助
Silk.NET + SkiaSharp 窗口闪烁问题
我想在Silk.NET窗口里用SkiaSharp做一个能改变矩形圆角的程序,但运行时窗口一直闪烁。
我的代码:
using Silk.NET.Windowing; using Silk.NET.OpenGL; using SkiaSharp; class Program { private static IWindow window; private static GL gl; private static GRGlInterface grgInterface; private static GRContext grContext; private static SKSurface surface; private static SKCanvas canvas; private static GRBackendRenderTarget renderTarget; private static SKPaint TestBrush; static void Main(string[] args) { var options = WindowOptions.Default; options.Size = new Silk.NET.Maths.Vector2D<int>(800, 600); options.Title = "Silk.NET with SkiaSharp Triangle"; window = Window.Create(options); window.Load += OnLoad; window.Render += OnRender; window.Run(); } private static void OnLoad() { grgInterface = GRGlInterface.Create(); grContext = GRContext.CreateGl(grgInterface); renderTarget = new GRBackendRenderTarget(window.Size.X, window.Size.Y, 0, 8, new GRGlFramebufferInfo(0, (uint)SizedInternalFormat.Rgba8)); surface = SKSurface.Create(grContext, renderTarget, GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888); canvas = surface.Canvas; TestBrush = new SKPaint { Color = SKColors.White, IsAntialias = true, Style = SKPaintStyle.Fill, TextAlign = SKTextAlign.Center, TextSize = 24 }; } private static void OnRender(double delta) { canvas.Clear(SKColors.CornflowerBlue); TestBrush.Color = SKColors.White; canvas.DrawRoundRect(new SKRoundRect(new SKRect(0, 0, 256, 256), (float)Math.Max(Math.Sin(-delta) * 128.0f, 0)), TestBrush); TestBrush.Color = SKColors.Black; canvas.DrawText("Hello, World!", 128, 300, TestBrush); canvas.Flush(); window.SwapBuffers(); } }
环境说明:使用最新版Silk.NET 2.21和SkiaSharp 2.28.8,代码改编自一个OpenTK的示例(该示例运行正常)。
问题原因及解决办法
闪烁的核心原因是SkiaSharp与Silk.NET的GL上下文未同步,且缺少帧缓冲清除、垂直同步等关键步骤,导致前后帧残留或帧交换时机错位。
解决步骤:
- 绑定Silk.NET的GL上下文给SkiaSharp
必须让Skia使用Silk.NET创建的GL实例,避免上下文不一致。 - 开启垂直同步
让帧交换与显示器刷新同步,消除大部分闪烁。 - 渲染前清除GL缓冲
确保每一帧起始状态干净,避免残留上一帧内容。 - 强制Skia提交所有渲染命令
确保Skia的绘制命令完全提交到GL后再交换缓冲。
修复后的完整代码
using Silk.NET.Windowing; using Silk.NET.OpenGL; using SkiaSharp; class Program { private static IWindow window; private static GL gl; private static GRGlInterface grgInterface; private static GRContext grContext; private static SKSurface surface; private static SKCanvas canvas; private static GRBackendRenderTarget renderTarget; private static SKPaint TestBrush; static void Main(string[] args) { var options = WindowOptions.Default; options.Size = new Silk.NET.Maths.Vector2D<int>(800, 600); options.Title = "Silk.NET with SkiaSharp Triangle"; options.IsVsync = true; // 开启垂直同步 window = Window.Create(options); window.Load += OnLoad; window.Render += OnRender; window.Run(); } private static void OnLoad() { // 获取Silk.NET的GL实例并设置初始清除颜色 gl = window.CreateOpenGL(); gl.ClearColor(SKColors.CornflowerBlue.Red / 255f, SKColors.CornflowerBlue.Green / 255f, SKColors.CornflowerBlue.Blue / 255f, 1f); // 传入Silk.NET的GL句柄创建Skia的GL接口 grgInterface = GRGlInterface.Create(gl.Handle); grContext = GRContext.CreateGl(grgInterface); renderTarget = new GRBackendRenderTarget(window.Size.X, window.Size.Y, 0, 8, new GRGlFramebufferInfo(0, (uint)SizedInternalFormat.Rgba8)); surface = SKSurface.Create(grContext, renderTarget, GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888); canvas = surface.Canvas; TestBrush = new SKPaint { Color = SKColors.White, IsAntialias = true, Style = SKPaintStyle.Fill, TextAlign = SKTextAlign.Center, TextSize = 24 }; } private static void OnRender(double delta) { // 先清除GL颜色缓冲 gl.Clear(ClearBufferMask.ColorBufferBit); canvas.Clear(SKColors.CornflowerBlue); TestBrush.Color = SKColors.White; canvas.DrawRoundRect(new SKRoundRect(new SKRect(0, 0, 256, 256), (float)Math.Max(Math.Sin(-delta) * 128.0f, 0)), TestBrush); TestBrush.Color = SKColors.Black; canvas.DrawText("Hello, World!", 128, 300, TestBrush); // 强制Skia提交所有渲染命令到GL canvas.Flush(); grContext.Flush(); window.SwapBuffers(); } }
内容的提问来源于stack exchange,提问作者AlexeyBobrovich
相关产品推荐
相关产品推荐

