减少页面错误
使用原生 GDI 将减少页面错误。
引言
我的应用程序出现大量的页面错误。根据我在线上找到的信息,这不太可能导致任何问题,但这引起了我的兴趣去调查:是什么导致了大量的页面错误,以及是否有办法减少它。
背景
几年前,我试图让我的12岁的儿子对编程感兴趣(抱歉,甚至保留了原始名称MyFirstGame)。因此,我们设计了一个简单的游戏。
请注意:这篇文章不是关于这个游戏 - 我只是用这个游戏来调查页面错误的数量。在玩游戏时,使用标准的.NET图形对象,你会得到大约25000个页面错误/秒。
Using the Code
代码有一个简单的棋盘(5行,4列)。正方形随机放置在每一行,玩家应该点击黑色正方形使其消失。如果你没有点击它,并且它到达底部,你就输了,如果你点击了白色正方形,你就输了。棋盘在Form1对象内的“Draw”方法中使用标准.NET绘制。
当你点击“使用GDI”时,会使用gdi32.dll - 在Draw2方法中。你会看到页面错误急剧减少。
(为了更容易观察,我每秒在屏幕上显示页面错误,无需打开任务管理器。)
此外,使用GDI绘制的平均速度大约快10倍。
Draw方法如下所示
private void Draw(Graphics g)
{
    if (checkBoxUseGDI.Checked)
    {
        Draw2(g);
        return;
    }
    graphics.Clear(Color.White);
    int left = 0;
    int top = board.Top;
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            Rectangle rect = new Rectangle(left, top, 100, 150);
            if (board.Cells[i, j] > -1)
            {
                graphics.FillRectangle(Brushes.Black, rect);
            }
            graphics.DrawRectangle(Pens.Black, rect);
            left += 100;
        }
        top += 150;
        left = 0;
    }
    g.DrawImage(bitmap, 0, 0);
}
Draw2方法如下所示
private void Draw2(Graphics g)
{
    IntPtr hdc2 = g.GetHdc();
    IntPtr hdc = GDI.CreateCompatibleDC(hdc2);
    IntPtr hBitmap = GDI.CreateCompatibleBitmap(hdc, 401, 601);
    GDI.SelectObject(hdc, hBitmap);
    IntPtr brushWhite = GDI.CreateSolidBrush(0xFFFFFF);
    GDI.FillRgn(hdc, GDI.CreateRectRgn(0, 0, 401, 601), brushWhite);
    GDI.DeleteObject(brushWhite);
    IntPtr brushBlack = GDI.CreateSolidBrush(0x0);
    int left = 0;
    int top = board.Top;
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            GDI.Rectangle(hdc, left, top, left + 101, top + 151);
            if (board.Cells[i, j] > -1)
            {
                GDI.FillRgn(hdc, GDI.CreateRectRgn(left, top, left + 101, top + 151), brushBlack);
            }
            left += 100;
        }
        top += 150;
        left = 0;
    }
    GDI.DeleteObject(brushBlack);
    GDI.BitBlt(hdc2, 0, 0, 401, 601, hdc, 0, 0, GDI.TernaryRasterOperations.SRCCOPY);
    g.ReleaseHdc(hdc2);
    GDI.DeleteDC(hdc);
    GDI.DeleteObject(hBitmap);
}
关注点
我发现这个网站很有帮助:http://pinvoke.net/default.aspx
历史
- 2018年12月26日:初始版本




