在 window 上放置多种颜色的最有效方法是什么,尤其是在逐帧格式中?

What is the most efficient way to put multiple colours on a window, especially in frame-by-frame format?

我正在用 C 和 X11 制作游戏。我已经尝试了很长时间以找到一种方法,可以逐帧将不同颜色的像素放在 window 上。我见过完全开发的游戏每秒可获得数千帧。最有效的方法是什么?

我见过使用 XImages 的 2 色位图,在黑白渐变上分配 256 种颜色,并使用 XPutPixel 和 XImages(我无法弄清楚如何正确创建 XImage,以后可能会有像素放在上面)。

我制作了这个创建随机图像的 for 循环,但很明显,它是逐像素而不是逐帧渲染一整帧需要 18 秒。

XColor pixel;
for (int x = 0; x < currentWindowWidth; x++) {
    for (int y = 0; y < currentWindowHeight; y++) {
        pixel.red = rand() % 256 * 256; //Converting 16-bit colour to 8-bit colour
        pixel.green = rand() % 256 * 256;
        pixel.blue = rand() % 256 * 256;
        XAllocColor(display, XDefaultColormap(display, screenNumber), &pixel); //This probably takes the most time,
        XSetForeground(display, graphics, pixel.pixel); //as does this.
        XDrawPoint(display, window, graphics, x, y);
    }
}

每秒几千帧是不可能的。监视器频率约为 100 Hz,或每秒 100 个周期,这大致是最大帧速率。这还是很快的。人眼不会接收到更快的帧速率。

监视器响应时间约为5ms,因此屏幕上任何一个点每秒刷新不能超过200次。

8位是1个字节,所以8位图像每个像素使用一个字节,每个像素从0到256。像素没有红,蓝,绿分量。相反,每个像素都指向颜色 table 中的一个索引。颜色 table 包含 256 种颜色。有一个技巧可以让像素保持不变并更改颜色 table,这会使图像淡入淡出或做其他奇怪的事情。

在 24 位图像中,每个像素都有蓝色、红色、绿色分量。每种颜色为 1 个字节,因此每个像素为 3 个字节,即 24 位。

uint8_t red = rand() % 256; 
uint8_t grn = rand() % 256;
uint8_t blu = rand() % 256;

一张16位的图像使用一种奇怪的格式来存储红、蓝、绿。 16 不能被 3 整除,通常 2 种颜色分配 5 位,而第 3 种颜色分配 6 位。然后你必须将这些颜色适合一个 uint16_t 大小的像素。探索这个可能不值得。

您的例程之所以缓慢是因为您一次绘制一个像素。您应该改为绘制到缓冲区,并每帧渲染一次缓冲区。您可能会考虑使用其他框架作品,如 SDL。其他游戏可能会使用 OpenGL 之类的东西,它利用 GPU 优化矩阵运算等。

您必须使用 GPU。 GPU 具有针对图形优化的高度并行架构(因此得名)。要访问 GPU,您将使用 API,例如 OpenGL 或 Vulkan,或者使用游戏引擎。

经过三个多星期的断断续续的测试,我终于弄清楚了如何去做,而且相当简单。正如我在 OP 中所说,XAllocColor 和 XSetForground 需要相当多的时间(相对)才能工作。 XDrawPoint 也很慢,因为它不仅仅是在图像上的一个点放置一个像素。

首先我测试了 Xlib 的颜色格式是如何工作的(对于表示为 pixel.pixel 的无符号长整型,这正是我需要 XAllocColor 的原因),它似乎将 100% 红色设置为 16711680,100%绿色设置为65280,100%蓝色设置为255,这显然是一个图案。我发现最大值是所有颜色的 50%,4286019447,它是纯灰色。

接下来,我使用 XMatchVisualInfo([预期的视觉信息值])进行测试,确保我的系统支持我的 XVisualInfo。这确保了我将使用的深度和 TrueColor class 工作。

最后,我从根 window 的图像复制了一个 XImage 进行操作。我为 window 上的每个像素使用 XPutPixel,并将其设置为 0 到 4286019448 之间的随机值,从而创建随机图像。然后我使用 XPutImage 将图像粘贴到 window.

这是最终代码:

if (!XMatchVisualInfo(display, screenNumber, 24, TrueColor, &visualInfo)) {
    exit(0);
}
frameImage = XGetImage(display, rootWindow, 0, 0, screenWidth, screenHeight, AllPlanes, ZPixmap);
while (1) {
    for (unsigned short x = 0; x < currentWindowWidth; x += pixelSize) {
        for (unsigned short y = 0; y < currentWindowHeight; y += pixelSize) {
            XPutPixel(frameImage, x, y, rand() % 4286019447);
        }
    }
    XPutImage(display, window, graphics, frameImage, 0, 0, 0, 0, currentWindowWidth, currentWindowHeight);
}

这会在屏幕上放置一张随机图像,在全屏模式下以每秒 140 帧的速度稳定播放。我不一定知道这是否是最有效的方法,但它比我尝试过的任何其他方法都要好。让我知道是否有任何方法可以让它变得更好。