【问题标题】:How to render a pixel array most efficiently to a window in c++?如何在 C++ 中最有效地将像素数组渲染到窗口?
【发布时间】:2016-04-09 00:35:37
【问题描述】:

到目前为止,我一直在使用 SDL 2.0,将我的像素数组复制到纹理中,然后在屏幕上渲染。 我的渲染方法如下所示:

for (int i = 0; i < WIDTH*HEIGHT; i++){
        pixels[i] = 0xFFFF0000;
        //pixel Format: AARRGGBB
    }
    SDL_UpdateTexture(sdlTexture, NULL, pixels, 800 * sizeof(Uint32));

    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, sdlTexture, NULL, NULL);
    SDL_RenderPresent(renderer);

然后我测量了以纳秒为单位渲染一次所需的时间(通过 chrono),并将其与 java 中渲染像素的类似方式进行了比较: (像素数组存储“displayImage”的像素)

BufferStrategy bs = getBufferStrategy();
    if (bs == null){
        createBufferStrategy(3);
        return;
    }
    screen.clear()
    for (int i = 0; i < WIDTH*HEIGHT; i++){
        pixels[i] = 0xFF0000;
        //pixel Format: RRGGBB
    }
    Graphics2D g =  (Graphics2D) bs.getDrawGraphics();
    g.drawImage(displayImage,0,0,getWidth(),getHeight(),null);



    g.dispose();
    bs.show();

然后我惊讶地发现,在 Java 中渲染它大约需要 600.000 纳秒,而在 C++ 中渲染它大约需要 2.000.000 纳秒。

所以我的问题是,是否有更有效的方法来绘制像素数组,就像我在屏幕上一样,因为(我假设)C++ 应该比 Java 更快地渲染它。

这也是我测量时间的方式: C++:

auto start = std::chrono::steady_clock::now();

//render function

auto end = std::chrono::steady_clock::now();
auto result = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
std::cout << result << std::endl;

Java:

long start = System.nanoTime();

//render function

long end = System.nanoTime();
long result = end - start;
System.out.println(result);

【问题讨论】:

  • 你画了多少纹理?启用 vsync 后,2.000.000 纳秒仍然不到一帧。
  • 我只是在初始化一个我正在绘制的纹理。我发布的基本上是我的整个渲染功能,因为我现在只是用它来测试性能。
  • 首先,在 C++ 中,您可以清除屏幕,但在 java 中您不会。
  • 现在改了试了下,确实不影响速度。
  • 感觉你正在测量某种 C++ 的“调试”版本。

标签: java c++ arrays sdl pixels


【解决方案1】:

首先,应该注意的是,测量这么短的时间并不总是可靠的,因此应该对这些值持保留态度。即使 java 和 C++ 使用相同的系统计时器,也可能存在不相关的差异。

关于代码,SDL_UpdateTexture 将向内部缓冲区发出一个副本,因此有点慢。您应该改用SDL_LockTextureSDL_UnlockTexture。这将允许直接访问内部缓冲区。

此外,您不需要清除屏幕,因为您的纹理跨越整个屏幕,因此会覆盖所有内容。

如果你需要填满屏幕,只有一行,你可以使用汇编指令rep stos,它比循环快得多。使用 Visual C++,您可以使用 __stosd 为 uint32 发出 rep stos。这与memset 类似,但适用于uint32(您也有带有__stosw 的uint16 版本,以及带有__stosq 的uint64,仅限x64)。有等价的__movsd 来制作副本,但良好实现的memcpy 可以更快。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-31
    相关资源
    最近更新 更多