我目前正在将一些使用 C#(FW 版本 4.7.2)WinForms 实现的旧游戏转换为使用 C++ 的 Direct3D。
目前,我所有的实时图形游戏都实现了OnPaint
覆盖,绘制到从PaintEventArgs
参数中检索到的 Graphics 对象,并在绘制当前帧后立即失效。(我不知道这是否不推荐,但效果很好)。这些应用程序当然使用双缓冲。这会导致一个核心 100% 的利用率,这是可以的。
在将我的游戏移植到 C++ 和 Direct3D 时,我遇到的第一个障碍是窗口的刷新率,即使我通过在绘图后执行WndProc()
和调用来完成相同的事情。InvalidateRect()
我遵循了这个快速入门指南:https ://docs.microsoft.com/en-us/windows/win32/direct2d/direct2d-quickstart
问题是,
使用我的 Windows 窗体应用程序,在全尺寸背景图像上绘制时刷新率约为 60 fps,在空白背景上绘制时为 300-400 fps。以下示例仅绘制一个矩形,产生惊人的 2,500 fps:
public class Surface : Form
{
private int fps = 0;
private int lastFPS = 0;
private double lastSeconds = 0;
private Stopwatch chronometer = Stopwatch.StartNew();
Font font = new Font("Courier New", 10f);
public Surface()
{
BackColor = Color.Black;
DoubleBuffered = true;
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawRectangle(Pens.White, 100, 100, 100, 100);
e.Graphics.DrawString("FPS: " + lastFPS, font, Brushes.White, 5, 5);
fps++;
if (chronometer.Elapsed.Seconds > lastSeconds)
{
lastSeconds = chronometer.Elapsed.Seconds;
lastFPS = fps;
fps = 0;
}
Invalidate();
}
}
不用说,我在移植到 DirectX 时期待更好的帧速率,但问题是 WM_PAINT 事件没有足够频繁地触发,即使我不画任何东西,我也卡在 100 fps,并且 cpu 利用率是仅约 10%。
我只在快速入门指南的源代码中添加了以下行:
case WM_PAINT:
{
pDemoApp->OnRender();
ValidateRect(hwnd, NULL);
InvalidateRect(hwnd, NULL, TRUE); // THIS IS THE LINE I'VE ADDED
}
我究竟做错了什么?
我读到 Direct 2D 的渲染目标是自动双缓冲的,
所以问题是,为什么 WM_PAINT 事件每秒只触发 100 次?
注意:检查了 windows 窗体Control.Invalidate()
方法源,它的作用是调用 InvalidateRect (或 RedrawWindow() 如果子控件也将失效)
注意:我是否在这里错误地使用了直接 2d 绘图?我是否应该在一个单独的线程上持续绘制并让 DirectX 在它认为合适的时候刷新渲染目标?