为什么SDL在Mac上比Linux上慢得多?

9
我正在开发一个使用SDL2进行渲染的单线程图形程序,代码托管在Github上。下面是一个简短的示例。
该程序能够运行在旧的Linux机器和较新的Mac电脑上。Linux计算机的处理器有1.60GHz,而Mac的处理器则有2.2GHz。Linux上的SDL版本为2.0.8,而Mac上的SDL版本为2.0.10。我都使用clang++编译,并使用了优化标志-O3-flto。我使用命令 ./intergrid -fullscreen -pixel-size 3来运行可执行文件(实际上是让程序绘制非常多的像素)。
出乎意料的是,在较慢的Linux计算机上,该程序表现得非常顺畅,而Mac上则需要几秒钟来渲染第一帧。当我使用-no-draw标志禁用图形时,Mac比Linux更快。
补充说明:Linux计算机的图形处理器为“Intel Haswell Mobile”,而Mac则是“Intel Iris Pro 1536 MB”。
这里有一个最小可重现的示例:
#include <SDL2/SDL.h>
#include <stdio.h>

int main(void)
{
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);

    SDL_Window *window = SDL_CreateWindow(
        "Example",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        0, 0,
        SDL_WINDOW_SHOWN);
    SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);

    SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);

    SDL_Rect viewport;
    SDL_RenderGetViewport(renderer, &viewport);

    // The screen is not rendered to unless this is done:
    SDL_Event event;
    while (SDL_PollEvent(&event))
        ;

    Uint32 ticks_before = SDL_GetTicks();
    for (int x = 0; x < viewport.w - 10; x += 10) {
        for (int y = 0; y < viewport.h - 10; y += 10) {
            // I just chose a random visual effect for this example.
            SDL_Rect square;
            square.x = x;
            square.y = y;
            square.w = 10;
            square.h = 10;
            SDL_SetRenderDrawColor(renderer, x % 256, y % 256, 255, 255);
            SDL_RenderFillRect(renderer, &square);
        }
    }
    Uint32 ticks_after = SDL_GetTicks();
    printf("Ticks taken to render: %u\n", ticks_after - ticks_before);

    SDL_RenderPresent(renderer);

    SDL_Delay(500);

    // I Won't worry about cleaning stuff up.
}

我使用 clang++ -O3 -flto <filename> -lSDL2 命令在 Mac 和 Linux 上编译了这个程序。当我在 Mac 上运行时,它打印出:

Ticks taken to render: 849

在Linux上运行的程序输出:

Ticks taken to render: 4

那是一个巨大的差异!

3
你有对你的代码进行过性能分析吗?不同的计算机上使用的图形芯片组和驱动程序是什么? - Dai
@Dai,实际上我对图形和性能分析并没有太多经验。我已经查看了两台计算机的“关于本机”信息中的“图形”部分,并将其添加到问题中。如果差异只是由于不同的GPU而无法修复,那么我可以关闭这个问题。 - JudeMH
1
@genpfault 我已经添加了一个更好的例子。 - JudeMH
2
@JudeMH,这是使用金属或OpenGL渲染器(SDL_GetRendererInfoname字段)吗?您可以在创建窗口/渲染器之前但在SDL_Init之后设置每个(SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"))进行检查吗?通常,您测量时间的方式存在问题-很多实际工作是并行进行的,只有在队列已满时才会阻塞,但849太高了。 - keltar
1
@Dids 我只是在设置提示,所以我认为程序仍然会运行,并希望在OpenGL被移除时使用Metal。希望到那时,Metal后端会更快。目前似乎 Metal 由于某些原因受到了CPU的限制。SDL_SetHint 的解决方案目前对我有用,但可能会有更好的方法。 - JudeMH
显示剩余5条评论
1个回答

10

@keltar发现了一个对我来说足够好的解决方案,但他们还没有将其发布为答案,所以我将发布。由于某些原因,SDL2的Metal后端非常缓慢,因此解决方案是使用OpenGL后端。我通过调用SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl")来实现这一点,如果我发现默认驱动程序是Metal(使用SDL_GetRendererInfo)。


1
@keltar 我最近尝试了一个元胞自动机模拟,其中我重复绘制了128x128网格/纹理中的所有像素(500次迭代)。使用默认的金属渲染,我大约只有15帧每秒的性能,但是使用上面提到的OpenGL提示,我可以达到大约210帧每秒的性能! - krueger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接