首页 > 解决方案 > 运行程序后 Windows 控制台帧率下降

问题描述

正如标题所示,我在 C++ 中的 Windows 控制台应用程序存在问题。到目前为止,我已经创建了一个类,Console,来表示我重复用于构建 Windows 控制台的所有函数。我实现了一个画线算法,当用洋红色字符填充屏幕并用白色画一条线时,速度高达 500 fps。但是,接下来我实现了一个三角形绘制算法(仅连续调用三个线条绘制),并惊讶地发现帧速率下降到 20 左右。我再次删除了这段代码,但糟糕的帧速率仍然存在。我真的不知道为什么会发生这种情况,因为我基本上没有改变任何东西。

作为参考,这里是控制台代码(没有标题):

Console::Console(int width, int height):
    m_handle(GetStdHandle(STD_OUTPUT_HANDLE)),
    m_width(width),
    m_height(height),
    m_screen({ 0, 0, 1, 1 }),
    m_title(L"Demo"),
    m_buffer(new CHAR_INFO[(size_t)m_width * (size_t)m_height])
{
    memset(m_buffer, 0, sizeof(CHAR_INFO) * m_width * m_height);
}

Console::~Console()
{
    if (m_buffer)
        delete[] m_buffer;
}

int Console::Construct(int char_w, int char_h)
{
    if (m_handle == INVALID_HANDLE_VALUE)
        return BAD_HANDLE;

    if (!SetConsoleWindowInfo(m_handle, true, &m_screen))
        return WINDOW_INFO_ERROR;

    COORD screen_coord = { (short)m_width, (short)m_height };

    if (!SetConsoleScreenBufferSize(m_handle, screen_coord))
        return SCREEN_BUFFER_SIZE_ERROR;


    CONSOLE_FONT_INFOEX cinfo;
    cinfo.cbSize = sizeof(cinfo);
    cinfo.dwFontSize.X = (short)char_w;
    cinfo.dwFontSize.Y = (short)char_h;
    cinfo.FontFamily = FF_DONTCARE;
    cinfo.FontWeight = FW_NORMAL;
    cinfo.nFont = 0;

    wcscpy_s(cinfo.FaceName, L"Consolas");

    if (!SetCurrentConsoleFontEx(m_handle, false, &cinfo))
        return CONSOLE_FONT_ERROR;

    CONSOLE_SCREEN_BUFFER_INFO cbuffinfo;

    if (!GetConsoleScreenBufferInfo(m_handle, &cbuffinfo))
        return GET_BUFFER_INFO_ERROR;

    if (cbuffinfo.dwMaximumWindowSize.X < m_width)
        return HORIZONTAL_SIZE_TOO_LARGE_ERROR;

    if (cbuffinfo.dwMaximumWindowSize.Y < m_height)
        return VERTICAL_SIZE_TOO_LARGE_ERROR;

    m_screen = { 0, 0, (short)m_width - 1, (short)m_height - 1 };

    if (!SetConsoleWindowInfo(m_handle, true, &m_screen))
        return WINDOW_INFO_ERROR;

    if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)HandleClose, true))
        return CLOSE_HANDLER_ERROR;

    return OK;
}

void Console::Start()
{
    active = true;

    std::thread t(&Console::DoLoop, this);

    t.join();
}

void Console::DoLoop()
{
    if (!OnCreate())
        active = false;

    std::chrono::high_resolution_clock::time_point t1, t2;

    t1 = std::chrono::high_resolution_clock::now();
    t2 = t1;

    while (active)
    {
        t2 = std::chrono::high_resolution_clock::now();
        std::chrono::duration<float> diff = t2 - t1;
        t1 = t2;

        float dt = diff.count();

        if (!OnUpdate(dt))
            active = false;

        wchar_t title_buff[256];
        swprintf_s(title_buff, L"Console Application - %s - FPS: %3.2f", m_title.c_str(), 1.0f / dt);
        SetConsoleTitle(title_buff);
        WriteConsoleOutput(m_handle, m_buffer, { (short)m_width, (short)m_height }, { 0, 0 }, &m_screen);
    }

    finished.notify_one();
}

void Console::Fill(int x, int y, short glyph, short color)
{
    if (x < 0 || y < 0 || x >= m_width || y >= m_height) return;

    CHAR_INFO& ci = m_buffer[y * m_width + x];
    ci.Char.UnicodeChar = glyph;
    ci.Attributes = color;
}

void Console::Fill(int x1, int y1, int x2, int y2, short glyph, short color)
{
    if (x1 < 0) x1 = 0;
    if (y1 < 0) y1 = 0;

    if (x1 >= m_width) return;
    if (y1 >= m_height) return;

    if (x2 >= m_width) x2 = m_width - 1;
    if (y2 >= m_height) y2 = m_height - 1;

    if (x2 < 0) return;
    if (y2 < 0) return;

    for (int x = x1; x <= x2; x++)
    {
        for (int y = y1; y <= y2; y++)
        {
            CHAR_INFO& ci = m_buffer[y * m_width + x];
            ci.Char.UnicodeChar = glyph;
            ci.Attributes = color;
        }
    }
}

void Console::Clear(short glyph, short color)
{
    for (int x = 0; x < m_width; x++)
    {
        for (int y = 0; y < m_height; y++)
        {
            CHAR_INFO& ci = m_buffer[y * m_width + x];
            ci.Char.UnicodeChar = glyph;
            ci.Attributes = color;
        }
    }
}

void Console::Line(int x1, int y1, int x2, int y2, short glyph, short color)
{
    int dx = x2 - x1;
    int dy = y2 - y1;

    int adx = dx > 0 ? dx : -dx;
    int ady = dy > 0 ? dy : -dy;

    int dy2 = dy + dy;
    int dx2 = dx + dx;

    int adx2 = dx2 > 0 ? dx2 : -dx2;
    int ady2 = dy2 > 0 ? dy2 : -dy2;

    if (adx > ady)
    {
        if (x1 > x2)
        {
            int x = x1;
            x1 = x2;
            x2 = x;
            dx = -dx;
            dx2 = -dx2;

            int y = y1;
            y1 = y2;
            y2 = y;
            dy = -dy;
            dy2 = -dy2;
        }

        int sy = dy > 0 ? 1 : dy < 0 ? -1 : 0;

        int err = ady;

        for (int x = x1, y = y1; x <= x2; x++)
        {
            Fill(x, y, glyph, color);

            err += ady2;

            if (err > adx2)
            {
                err -= adx2;
                y += sy;
            }
        }
    }
    else
    {
        if (y1 > y2)
        {
            int x = x1;
            x1 = x2;
            x2 = x;
            dx = -dx;
            dx2 = -dx2;

            int y = y1;
            y1 = y2;
            y2 = y;
            dy = -dy;
            dy2 = -dy2;
        }

        int sx = dx > 0 ? 1 : dx < 0 ? -1 : 0;

        int err = adx;

        for (int x = x1, y = y1; y <= y2; y++)
        {
            Fill(x, y, glyph, color);

            err += adx2;

            if (err > ady2)
            {
                err -= ady2;
                x += sx;
            }
        }
    }
}

void Console::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, short glyph, short color)
{
    Line(x1, y1, x2, y2, glyph, color);
    Line(x2, y2, x3, y3, glyph, color);
    Line(x3, y3, x1, y1, glyph, color);
}

BOOL Console::HandleClose(DWORD evt)
{
    if (evt == CTRL_CLOSE_EVENT)
    {
        active = false;

        std::unique_lock<std::mutex> ul(lock);
        finished.wait(ul);
    }

    return true;
}

这是非常短的主要代码:

class Game : public Console
{
public:
    Game(int width, int height):
        Console(width, height)
    {

    }

    bool OnCreate() override
    {
        return true;
    }

    bool OnUpdate(float dt) override
    {
        Clear(GLYPH_SOLID, FG_BLACK);

        //Triangle(20, 20, 300, 40, 150, 200);

        return true;
    }
};

int main()
{
    Game game(400, 300);
    int err = game.Construct(2, 2);

    if (err == Console::OK)
        game.Start();
}

错误常量只是在头文件中定义的整数代码。如果需要任何其他代码,请告诉我。提前致谢!

编辑:

分析会话的屏幕截图

标签: c++windowsframe-ratewindows-console

解决方案


推荐阅读