如何在 C++ 中最有效地将像素数组渲染为 window?
How to render a pixel array most efficiently to a window in c++?
到目前为止,我一直在使用 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.[=15 渲染得更快=]
这也是我测量时间的方式:
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);
首先,应该注意的是,测量这么短的时间并不总是可靠的,因此应该对这些值持保留态度。即使 java 和 C++ 使用相同的系统计时器,也可能存在不相关的差异。
关于代码,SDL_UpdateTexture
会向内部缓冲区发出一个副本,因此有点慢。您应该改用 SDL_LockTexture
和 SDL_UnlockTexture
。这将允许直接访问内部缓冲区。
此外,您不需要清除屏幕,因为您的纹理跨越整个屏幕,因此会覆盖所有内容。
如果你需要填满屏幕,只是一行,你可以使用汇编指令rep stos
,它比循环快得多。使用 Visual C++,您可以使用 __stosd
为 uint32 发出 rep stos
。这与 memset
类似,但适用于 uint32(您还拥有带 __stosw
的 uint16 版本和带 __stosq
的 uint64,仅限 x64)。有等效的 __movsd
来制作副本,但实施得当 memcpy
可以更快。
到目前为止,我一直在使用 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.[=15 渲染得更快=]
这也是我测量时间的方式: 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);
首先,应该注意的是,测量这么短的时间并不总是可靠的,因此应该对这些值持保留态度。即使 java 和 C++ 使用相同的系统计时器,也可能存在不相关的差异。
关于代码,SDL_UpdateTexture
会向内部缓冲区发出一个副本,因此有点慢。您应该改用 SDL_LockTexture
和 SDL_UnlockTexture
。这将允许直接访问内部缓冲区。
此外,您不需要清除屏幕,因为您的纹理跨越整个屏幕,因此会覆盖所有内容。
如果你需要填满屏幕,只是一行,你可以使用汇编指令rep stos
,它比循环快得多。使用 Visual C++,您可以使用 __stosd
为 uint32 发出 rep stos
。这与 memset
类似,但适用于 uint32(您还拥有带 __stosw
的 uint16 版本和带 __stosq
的 uint64,仅限 x64)。有等效的 __movsd
来制作副本,但实施得当 memcpy
可以更快。