SharpGL播放视频卡顿,是否未启用硬件加速?
问题描述
我用SharpGL播放由OpenCV转换为Bitmap的视频流时,发现两个关键调用耗时过高:
texture.Create(gl, bitmap)耗时约40毫秒gl.Flush()耗时约100毫秒
设备为Windows 10系统,搭载NVIDIA 3080显卡且驱动为最新版本,怀疑未启用硬件加速。由于SharpGL相关资料匮乏,纠结是否应该转用DirectX。
原始代码
XAML部分
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Red" Name="BorderControl" SizeChanged="BorderControlSizeChanged"> <sharpGL:OpenGLControl OpenGLDraw="OpenGLControl_OpenGLDraw" Name="OpenGLControl" Resized="openGLControl1_Resized" Width="500" Height="500" DrawFPS="True"> </sharpGL:OpenGLControl> </Border>
C#绘制逻辑
private void OpenGLControl_OpenGLDraw(object sender, OpenGLRoutedEventArgs args) { long time = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; long time0 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; MutexWaitOne(); time0 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - time0; long time1 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; OpenGL gl = args.OpenGL; gl.Enable(OpenGL.GL_TEXTURE_2D); gl.Disable(OpenGL.GL_DEPTH_TEST); time1 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - time1; long time2 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; int Width = (int)OpenGLControl.Width; int Height = (int)OpenGLControl.Height; gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT); gl.LoadIdentity(); time2 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - time2; long time3 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; texture.Destroy(gl); time3 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - time3; long time4 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; if (_cameraImagebuffer != null) { try { texture.Create(gl, _cameraImagebufferBitmap); }catch(Exception ex) { MutexRelease(); return; } } gl.TexParameter(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MIN_FILTER, OpenGL.GL_LINEAR); gl.TexParameter(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MAG_FILTER, OpenGL.GL_LINEAR); time4 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - time4; long time5 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; texture.Bind(gl); time5 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - time5; long time6 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; gl.Begin(OpenGL.GL_QUADS); gl.TexCoord(0.0f, 0.0f); gl.Vertex(0, 0, 0); gl.TexCoord(1.0f, 0.0f); gl.Vertex(Width, 0, 0); gl.TexCoord(1.0f, 1.0f); gl.Vertex(Width, Height, 0); gl.TexCoord(0.0f, 1.0f); gl.Vertex(0, Height, 0); gl.End(); time6 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - time6; long time7 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; gl.Flush(); time7 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - time7; MutexRelease(); time = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - time; Console.WriteLine(String.Format("OPENGL: Total : {0} step0:{1} step1:{2} step2:{3} step3:{4} step4:{5} step5:{6} step6:{7} step7:{8}", time, time0, time1, time2, time3, time4, time5, time6, time7)); }
性能优化方案(优先尝试)
你的代码存在几个核心性能瓶颈,先优化这些再判断是否需要迁移:
1. 避免每帧销毁重建纹理
当前每帧都执行texture.Destroy(gl)和texture.Create(gl, _cameraImagebufferBitmap),会导致GPU反复创建销毁资源,这是texture.Create耗时高的主要原因。正确做法是初始化时创建一次纹理,后续仅更新像素数据:
优化步骤:
- 在控件加载时初始化纹理:
private void OpenGLControl_Loaded(object sender, RoutedEventArgs e) { OpenGL gl = OpenGLControl.OpenGL; texture.Create(gl, _cameraImagebufferBitmap); // 纹理参数仅需设置一次 gl.TexParameter(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MIN_FILTER, OpenGL.GL_LINEAR); gl.TexParameter(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MAG_FILTER, OpenGL.GL_LINEAR); }
- 在绘制事件中替换销毁重建逻辑为像素更新:
// 移除texture.Destroy(gl); if (_cameraImagebuffer != null) { try { gl.Bind(OpenGL.GL_TEXTURE_2D, texture.TextureName); BitmapData data = _cameraImagebufferBitmap.LockBits( new Rectangle(0, 0, _cameraImagebufferBitmap.Width, _cameraImagebufferBitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); // 直接更新纹理像素,无需重建 gl.TexSubImage2D(OpenGL.GL_TEXTURE_2D, 0, 0, 0, data.Width, data.Height, OpenGL.GL_BGRA, OpenGL.GL_UNSIGNED_BYTE, data.Scan0); _cameraImagebufferBitmap.UnlockBits(data); } catch(Exception ex) { MutexRelease(); return; } }
2. 确认启用硬件加速
检查OpenGLControl的RenderContextType属性,确保使用硬件加速模式:
- XAML中设置:
<sharpGL:OpenGLControl RenderContextType="FBO" ... />
- 或代码中设置:
OpenGLControl.RenderContextType = RenderContextType.FBO;
FBO或NativeWindow模式会启用GPU硬件加速,避免软件渲染导致的高耗时。
3. 移除不必要的gl.Flush()
gl.Flush()会强制GPU立即执行所有待处理命令,实时渲染场景中通常无需显式调用——SharpGL控件本身会处理缓冲区交换。直接移除该调用,观察耗时是否下降。
4. 替换老旧的立即模式绘制
当前使用的glBegin/glEnd是老旧的立即模式,CPU-GPU交互开销大。建议改用VAO/VBO存储顶点数据,初始化时仅上传一次,绘制时直接绑定渲染,进一步降低CPU开销。
是否需要转用DirectX?
如果上述优化后性能仍不达标,或需要更深度的Windows平台视频渲染支持,转用DirectX是合理选择:
- Windows系统对DirectX原生优化更好,NVIDIA显卡对DirectX的驱动优化也更成熟,尤其适合视频流这类性能敏感场景。
- .NET生态下的DirectX绑定库(如SharpDX、DirectXTK)资料更丰富,社区支持更完善。
- 可直接处理OpenCV的Mat数据,无需转换为Bitmap,减少数据拷贝开销。
内容的提问来源于stack exchange,提问作者Jonathan Le Cornichone
相关产品推荐
相关产品推荐

