如何在 SDL 中缩放到分辨率

How to scale to resolution in SDL?

本文关键字:缩放 分辨率 SDL      更新时间:2023-10-16

我正在使用 SDL 和 C++ 编写一款 2D 平台游戏。但是,我遇到了一个涉及缩放到分辨率的巨大问题。我希望游戏在全高清下看起来不错,因此已经创建了游戏的所有图像,以便游戏的自然分辨率为 1920x1080。但是,如果有人使用较小的分辨率,我希望游戏缩小到正确的分辨率,或者如果有人使用较大的分辨率,则放大到正确的分辨率。

问题是我无法找到一种有效的方法来做到这一点。我首先使用 SDL_gfx 库预先缩放所有图像,但这不起作用,因为它会产生许多逐个错误,其中一个像素丢失。而且由于我的动画包含在一个图像中,当动画播放时,动画会在每一帧中略微向上或向下移动。

然后,经过一番环顾,我尝试使用 opengl 来处理缩放。目前,我的程序将所有图像绘制为 1920x1080 的SDL_Surface。然后,它将此表面转换为 opengl 纹理,将此纹理缩放到屏幕分辨率,然后绘制纹理。这在视觉上工作正常,但问题是它根本没有效率。目前我的最大 fps 为 18 :(

所以我的问题是,有谁知道将 SDL 显示器扩展到屏幕分辨率的有效方法?

它效率低下,因为OpenGL不是为这种工作而设计的。 当前设计的主要性能问题:

  • 第一个问题:您正在使用 SDL 进行软件栅格化。 抱歉,但无论您使用此配置做什么,这都将是一个瓶颈。 在 1920x1080 的分辨率下,您需要为 2,073,600 像素着色。 假设每个 4 通道像素着色需要 10 个时钟周期,那么在 2GHz 处理器上,您最多运行 96.4 fps。 这听起来还不错,除了你可能无法那么快地着色像素,而且你还没有做过人工智能、用户输入、游戏机制、声音、物理和其他一切,而且你可能至少画过一次像素。 SDL_gfx可能很快,但对于大分辨率,CPU 从根本上来说是超负荷的。
  • 第二个问题:每一帧,你都在通过图形总线将数据复制到 GPU。 这是您在图形方面可以做的最慢的事情。 图像数据可能是其中最糟糕的,因为通常有太多。 基本上,每一帧你告诉GPU将200万个像素从RAM复制到VRAM。 根据维基百科,您可以期望,对于 2,073,600 像素,每个像素 4 字节,不超过 258.9 fps,在您记住您需要做的所有其他事情之前,这听起来还不错。

我的建议:将你的应用程序完全切换到OpenGL。 这样就无需渲染到纹理并复制到屏幕 - 只需直接渲染到屏幕即可! 此外,缩放由视图矩阵(glOrtho/gluOrtho2D for 2D)自动处理,因此您根本不需要关心缩放问题 - 您的视口只会以相同的比例显示所有内容。 这是您问题的理想解决方案。

现在,它有一个主要缺点,即您必须使用 OpenGL 绘制命令重新编码所有内容(这是工作,但不是太难,尤其是从长远来看)。 除此之外,您可以尝试以下想法来提高速度:

  • 人民银行。 像素缓冲区对象可用于通过异步加载/复制纹理来解决问题二。
  • 多线程渲染。 大多数 CPU 至少有两个内核,在较新的芯片上,可以为单个内核保存两个寄存器状态(超线程)。 你实际上是在复制GPU解决渲染问题的方式(有很多线程)。 我不确定SDL_gfx线程的安全性如何,但我敢打赌可以解决一些问题,特别是如果您只同时处理图像的不同部分。
  • 请务必注意绘图表面在 SDL 中的位置。 它可能应该是SDL_SWSURFACE的(因为你是在CPU上绘制的)。
  • 删除 VSync。 这可以提高性能,即使您没有以 60Hz 运行
  • 确保你正在绘制原始纹理 - 不要将其放大或缩小到新的纹理。 以不同的大小绘制它,然后让光栅器完成工作!
  • 偶尔更新:一次只更新一半的图像。 这可能会接近您的"帧速率"的两倍,并且(通常)不明显。
  • 同样,仅更新图像的更改部分。

希望这有帮助。