【发布时间】:2020-09-08 09:57:41
【问题描述】:
我目前正在将一些使用 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 在它认为合适的时候刷新渲染目标?
【问题讨论】:
标签: c# c++ .net direct2d wm-paint