从奔腾级处理器开始,包括 Athlon、K6-2 和其他 CPU,都存在内存类型范围寄存器 (MTRR),它们控制处理器如何访问内存位置范围。 基本上,它将对显卡的许多较小的单独写入转换为单个写入(突发)。 这提高了写入显卡的效率,并可以将图形速度提高 250% 或更多。
参见/usr/src/linux/Documentation/mtrr.txt了解详情。 请注意,自从编写此文件以来,XFree86 已被打上补丁,可以自动检测您的显卡 RAM 基地址和大小并设置 MTRR。
如果出于某种原因您正在使用 X 3.3,请按照以下说明进行操作mtrr.txt(请参阅第 5.1 节)来设置您的 MTRR。 X 4.0 会自动为您执行此操作。
如果您正在 X 下玩游戏,请不要运行窗口管理器,并且绝对不要运行像 GNOME 或 KDE 这样的桌面管理器。 有关详细信息,请参阅第 4.2 节。
使用系统上的启动脚本(您必须以 root 用户身份执行此操作)杀死所有非必要的进程。 在 Debian 上,运行级别 2 的启动脚本位于 /etc/rc2.d/ 中。 您可以通过向其启动脚本发送 `stop' 命令来有序地停止服务
# cd /etc/rc2.d # ./ntpd stop |
另一个(激进的)选项是简单地使用以下命令将自己置于单用户模式:
# telinit 1 |
这将甚至摆脱 getty; 您的系统将仅运行对其操作绝对至关重要的任何内容。 您将运行大约 10 个进程。 缺点是您必须以 root 用户身份玩游戏。 但是您的进程表将空无一人,所有额外的 CPU 都将直接用于您的游戏。
您在游戏中会看到的常见问题是找不到库文件。 它们有点神秘,并且有奇怪的名称,因此我们将简要介绍一下 Linux 上的库。 库有两种类型:静态库和动态库。 当您编译程序时,默认情况下,gcc 使用动态库,但是您可以使用-static开关使 gcc 改为使用静态库。 除非您计划从源代码编译游戏,否则您主要会对动态库感兴趣。
动态库,也称为“共享库”,在应用程序运行时为其提供目标代码。 也就是说,代码在运行时(而不是编译时)链接到可执行文件中。 它们类似于 Windows 使用的.dll。“动态”链接代码的程序称为 /etc/ld.so,动态库本身通常以.so结尾,并带有版本号,例如
/usr/lib/libSDL.so /lib/libm.so.3 |
当使用 gcc 时,您可以通过删除字符串来引用这些库lib, .so和所有版本号。 因此,要使用这两个库,您需要向 gcc 传递-lSDL -lm选项。 然后,gcc 将“在可执行文件中放置一个备忘录”,指示在/usr/lib/libSDL.so和/lib/libm.so.3文件中查找,每当使用 SDL 或数学函数时。
与在应用程序运行时提供代码的动态库相比,静态库包含在编译程序时链接(插入)到程序中的代码。 在运行时不会插入任何代码; 代码是完全独立的。 静态库通常以.a结尾,后跟版本号,例如
/usr/lib/libSDL.a /usr/lib/libm.a |
这些.a文件实际上是许多.o(目标)文件归档在一起的档案,类似于 tar 文件。 您可以使用 nm 查看静态库包含哪些函数
% nm /usr/lib/libm.a ... e_atan2.o: 00000000 T __ieee754_atan2 e_atanh.o: 00000000 T __ieee754_atanh 00000000 r half 00000010 r limit 00000018 r ln2_2 ... |
当使用 gcc 时,您可以通过删除字符串“lib”、“.a”和所有版本号来引用这些库。 因此,要使用这两个库,您需要向 gcc 传递-lSDL -lm选项。 然后,gcc 将在编译过程中看到数学函数时,从/usr/lib/SDL.a和/usr/lib/libm.a“焊接到”代码中。
如果您编译自己的游戏,您在库方面最大的问题要么是 gcc 找不到静态库,要么是您的系统上可能不存在该库。 当玩二进制游戏时,您在库方面的困境要么是 ld.so 找不到库,要么是您的系统上不存在该库。 因此,谈论 gcc 和 ld.so 最初是如何查找库的,是有意义的。
gcc 在“标准系统目录”以及您使用-L选项指定的任何目录中查找库。 您可以使用 gcc -print-search-dirs 找到这些标准系统目录是什么
ld.so 查找名为/etc/ld.so.cache的文件中包含的二进制哈希,以获取包含可用动态库的目录列表。 由于它包含二进制数据,因此您无法直接修改此文件。 但是,该文件是从文本文件/etc/ld.so.conf生成的,您可以编辑该文件。 此文件包含您希望 ld.so 搜索动态库的目录列表。 如果您想开始将动态库放在/home/joecool/privatelibs中,您需要将此目录添加到/etc/ld.so.conf。 您的更改实际上不会进入/etc/ld.so.cache,直到您运行 ldconfig; 一旦运行,ld.so 将开始在您的私有目录中查找库。
此外,即使您只是向系统中添加了额外的库,也必须更新ld.so.cache以反映新库的存在。
大多数商业 Linux 游戏将动态链接到各种 LGPL 库,例如 OpenAL 或 SDL。 在这些示例中,将使用 Bioware 的《无冬之夜》<http://nwn.bioware.com>。
要找出游戏使用了哪些库,我们可以使用 “ldd” 命令。 Cd 到/usr/games/nwn,或您安装它的任何位置,并查看文件。 您应该看到一个名为nwmain的文件; 这是实际的游戏二进制文件。 输入 “ldd nwmain”,您将看到
$ ldd nwmain linux-gate.so.1 => (0xffffe000) libm.so.6 => /lib/libm.so.6 (0x40027000) libpthread.so.0 => /lib/libpthread.so.0 (0x40049000) libGL.so.1 => /usr/lib/libGL.so.1 (0x4009b000) libGLU.so.1 => /usr/X11R6/lib/libGLU.so.1 (0x40103000) libmss.so.6 => not found libSDL-1.2.so.0 => /usr/lib/libSDL-1.2.so.0 (0x40178000) libc.so.6 => /lib/libc.so.6 (0x401ff000) /lib/ld-linux.so.2 (0x40000000) libGLcore.so.1 => /usr/lib/libGLcore.so.1 (0x40319000) libnvidia-tls.so.1 => /usr/lib/libnvidia-tls.so.1 (0x409f1000) libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x409f3000) libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x40a01000) libdl.so.2 => /lib/libdl.so.2 (0x40acd000) libstdc++.so.5 => /usr/lib/libstdc++.so.5 (0x40ad1000) libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x40b88000) libasound.so.2 => /usr/lib/./libasound.so.2 (0x40b90000) |
ldd 显示动态可执行文件依赖的所有库,并显示它们的位置。 它还“拉入”依赖项的依赖项。 例如,虽然 NWN 本身不依赖于libnvidia-tls.so,但我系统上 Nvidia 提供的 libGL 依赖于它。
缺少库?
在上面的示例中,我们可以看到nwmain想要libmss.so.6,但链接器找不到它。 通常,缺少库是等待发生的崩溃。 但还有一件事需要考虑:大多数游戏实际上是由“包装器”(shell 脚本)启动的,该脚本在启动游戏之前执行一些神奇的操作。 在 NWN 的情况下,包装器称为nwn。 现在让我们看一下它
$ less nwn #!/bin/sh # This script runs Neverwinter Nights from the current directory export SDL_MOUSE_RELATIVE=0 export SDL_VIDEO_X11_DGAMOUSE=0 # If you do not wish to use the SDL library included in the package, remove # ./lib from LD_LIBRARY_PATH export LD_LIBRARY_PATH=./lib:./miles:$LD_LIBRARY_PATH ./nwmain $@ |
此脚本设置了一些环境变量,然后使用我们添加的任何命令行选项启动游戏二进制文件。 这里相关的部分是名为 “LD_LIBRARY_PATH” 的环境变量。 这是一种添加到链接器搜索路径的方法。 尝试将该行复制到您的 shell 中,看看重新运行 ldd 时会发生什么。
$ export LD_LIBRARY_PATH=./lib:./miles:$LD_LIBRARY_PATH $ ldd nwmain linux-gate.so.1 => (0xffffe000) libm.so.6 => /lib/libm.so.6 (0x40027000) libpthread.so.0 => /lib/libpthread.so.0 (0x40049000) libGL.so.1 => /usr/lib/libGL.so.1 (0x4009b000) libGLU.so.1 => /usr/X11R6/lib/libGLU.so.1 (0x40103000) libmss.so.6 => ./miles/libmss.so.6 (0x40178000) libSDL-1.2.so.0 => ./lib/libSDL-1.2.so.0 (0x401ec000) libc.so.6 => /lib/libc.so.6 (0x4025e000) /lib/ld-linux.so.2 (0x40000000) libGLcore.so.1 => /usr/lib/libGLcore.so.1 (0x40378000) libnvidia-tls.so.1 => /usr/lib/libnvidia-tls.so.1 (0x40a50000) libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x40a52000) libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x40a60000) libdl.so.2 => /lib/libdl.so.2 (0x40b2c000) libstdc++.so.5 => /usr/lib/libstdc++.so.5 (0x40b30000) libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x40be7000) |
如您所见,这给了我们略有不同的结果。 NWN 库目录已添加到搜索路径的前面,因此现在链接器可以在 “libmss.so.6中找到./miles” 目录中找到,并且首先找到本地副本 libSDL,不再使用系统副本。
这些脚本还有另一个好处:它们很容易编辑,允许您提供自己的库副本。 任何游戏提供的库副本(例如 OpenAL 或 SDL)都可能针对最低公分母进行编译,可能是 i486 或 i686。 如果您有 Pentium4 或 AthlonXP,您可以专门为您的处理器编译自己的版本。 编译器将尝试优化生成的二进制文件,从而提高一些性能。 有关此方面的更多信息,请访问 GCC 网站 。
使 NWN 使用您的系统副本很容易。 它在包装器脚本中说明了! 从LD_LIBRARY_PATH行中删除 “./lib:”,您就可以开始了。
另一个不错的小技巧是针对使用 OpenAL 进行声音输出的游戏(例如,基于 Unreal 的游戏:UT、Postal、Rune 等)。 由于 Open Sound System (OSS) 已被弃用,转而支持 ALSA,因此我所见过的所有 Linux 发行版现在都默认提供 ALSA 支持,而 OSS 支持实际上是通过 ALSA 的兼容性模块提供的。 随游戏分发的openal.so副本通常不*支持 ALSA,因此使游戏使用您自己编译的副本将允许您原生使用 ALSA。