双显示器的 C++ SDL2 vsync 问题

问题描述 投票:0回答:0

我很难解决导致我的街机老虎机 SDL2 游戏在我的双显示器 linux 主板上运行不佳的错误。

void Rendering::Update()
{
    Time::Tick("RENDERING: ");

    bool anythingVGA = false; /**< Flag that says if the VGA has anything to render. */
    bool anythingHDMI = false; /**< Flag that says if the HDMI has anything to render. */

    /* I reserve my final vector the necessary memory.*/
    Rendering::vPObjects.reserve(RESERVED_VECTOR_MEMORY);

    /* I process objects and push their texture, destination and layer into my final VPObjects vector.
    * This is necessary to process layered rendering of multiple classes members. */
    Rendering::ProcessImages(anythingVGA, anythingHDMI);
    Rendering::ProcessSymbols(anythingVGA, anythingHDMI);
    Rendering::ProcessEFX(anythingVGA);
    Rendering::ProcessAwards(anythingVGA);
    Rendering::ProcessTexts(anythingVGA);

    /* I sort my final vector based on its members layer, from the lowest to the highest.*/
    std::sort(Rendering::vPObjects.begin(), Rendering::vPObjects.end(), Compare(Compare::CRITERIA_LAYER));

    if(anythingVGA)
    {
        /* Clearing must be done just once per refresh. */
        MONITOR_VGA.Clear();
    }

    if(anythingHDMI)
    {
        /* Clearing must be done just once per refresh. */
        MONITOR_HDMI.Clear();
    }

    for(const auto& k: Rendering::vPObjects)
    {
        /* I put each object into the SDL Buffer, ready to be rendered. */
        if(k.renderer == RENDERER_VGA)
            MONITOR_VGA.RenderCopy(k.texture, k.destination);
        else if(k.renderer == RENDERER_HDMI && HDMI_FLAG)
            MONITOR_HDMI.RenderCopy(k.texture, k.destination);
    }

    /* I call the RenderPresent function only
     * if the renderer has something to operate on.*/
    if(anythingVGA)
    {
        SDL_RenderPresent(MONITOR_VGA.renderer);
    }

    /* I call the RenderPresent function only
     * if the renderer has something to operate on.*/
    if(anythingHDMI)
    {
        SDL_RenderPresent(MONITOR_HDMI.renderer);
    }

    /* I clear my vector, so that it will be ready for the next frame later.*/
    Rendering::vPObjects.clear();

    /* I clear the fonts objects vector and free its textures. */
    Text::Clear();

    Time::Tock();
    Time::PrintTickTockLapse();
}

我有多个具有不同数据的对象,所以我正在处理包含每个类的所有成员的向量,并将它们放在一个名为“VPObjects”的最终向量上,我已经根据对象的层对它进行了排序,这样我就可以轻松在不同的图层上渲染。

VPObjects 是 ProcessedObjects 的向量,即:

struct ProcessedObject
{
    SDL_Texture* texture;
    SDL_Renderer* renderer;
    SDL_Rect destination;
    uint8_t layer;
};

本质上,我在每个“Rendering::Process...()”函数中所做的是检查对象是否被标记为“可见”,它是否具有来自 nullptr 的纹理 != 以及它是否具有有效的渲染器。如果满足所有这些条件,我将其作为“ProcessedObject”推入我的 vPObjects 向量中。

如果我使用带有单个屏幕的街机老虎机,代码运行非常流畅,但如果我也打开第二个屏幕,它会在“SDL_RenderPresent()”调用中开始出现延迟。

我觉得VSYNC有问题。两台显示器均为 1680x1050 60HZ。正如预期的那样,如果我使用 SDL_RENDERER_PRESENTVSYNC 在单个监视器上运行我的代码,每个游戏循环的执行时间为 16 毫秒,因此我得到稳定的 60fps。但是,如果我在机器上有 2 个显示器时运行代码,游戏循环执行时间就会混乱。一次需要 16 毫秒,然后是 0 毫秒,然后是 4 毫秒,然后是 87 毫秒。对每个函数进行基准测试,我发现只有当代码需要执行“SDL_RenderPresent()”时才会出现延迟。

如果我从我的代码中删除“MONITOR_HDMI”部分,它不会修复任何东西,只有一些东西会在双屏打开时弄乱我的代码,即使它不处理任何对象。要解决问题,我需要关闭机器,然后再次打开它,但要断开第二台显示器的连接。

这就是我创建渲染器和 Windows 的方式:

void Screen::Create()
{
    static uint8_t screens_number = 0;

    if(!this->exists)
    {
        this->window = SDL_CreateWindow(this->name, Screen::WIDTH * screens_number, 0, this->w,   this->h, SDL_WINDOW_OPENGL);
        SDL_SetWindowBrightness(this->window, WINDOWS_BRIGHTNESS);

        this->renderer = SDL_CreateRenderer(this->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
        this->SetDrawColor(&DRAW_COLOR);
        SDL_SetRenderDrawBlendMode(this->renderer, SDL_BLENDMODE_BLEND);

        ++screens_number;

        this->exists = true;
        return;
    }
}

我尝试了窗口和渲染器的每个 SDL 标志。如果我关闭 SDL_RENDERER_PRESENTVSYNC,我会按预期调用 0 毫秒的 SDL_RenderPresent() 并调用 90+ 毫秒,这完全破坏了我的性能。我试过弄乱 xrandr 设置,但我没有解决任何问题。

这不是机器本身的问题,因为我们在上面测试了另一个SDL游戏,运行良好。

c++ linux performance sdl-2 vsync
© www.soinside.com 2019 - 2024. All rights reserved.