我需要为未连接实际显示的虚拟GPU设备显示基于RAM的帧缓冲区。我所拥有的是RGB32格式的DRM_IOCTL_MODE_MAP_DUMB之后的映射内存块。目前,我正在使用通过XShmCreatePixmap()创建的MIT-SHM共享像素图,如下所示:
shminfo.shmid = shmget(IPC_PRIVATE, bytes, IPC_CREAT|0777);
shminfo.readOnly = False;
shminfo.shmaddr = shmat(shminfo.shmid, 0, 0);
shmctl(shminfo.shmid, IPC_RMID, 0);
XShmAttach(dpy, &shminfo);
XShmCreatePixmap(dpy, window, shminfo.shmaddr, &shminfo, width, height, 24);
然后简单地
while (1) {
struct timespec ts = {0, 999999999L / 30};
nanosleep(&ts, NULL);
memcpy(shminfo.shmaddr, mem, bytes);
XCopyArea(dpy, pixmap, window, gc, 0, 0, width, height, 0, 0);
XFlush(dpy);
}
因此它每秒循环30次,在XCopyArea之后执行memcpy。问题是它占用大量CPU:在一台功能强大的计算机上占50%。有什么更好的办法吗?我可以想到两个可能的改进:
有任何想法吗?
更新:
如果删除的CPU使用率可以忽略不计,则瓶颈是“memcpy”。问题似乎是没有办法共享以前mmap的内存(如果我正确理解了API),因此我不得不每次都复制整个缓冲区。
我还尝试了glDrawPixels()和SDL表面,它们似乎都比MIT-SHM还要慢。
更新:事实证明MIT-SHM不太适合此类任务。它的主要目的是创建缓冲区并将其写入(渲染),而没有X IPC的开销。除了将现有缓冲区“转发”到X外,我不需要编写任何其他内容。在这种情况下,共享像素图,共享图像和常规X图像(XCreateImage)之间没有性能差异。
结论:到目前为止,我还没有找到可以渲染现有缓冲区而无需每次都复制数据的API。
最佳答案
对于X11,请使用XShmCreateImage
,写入XImage.data
并使用XShmPutImage
使其可见,确保将False
传递给send_event
参数。您可能还想禁用当前GC的暴露事件;设置PointerMotionHintMask
也可以提供帮助。
SDL1可以完成上述大部分操作,但是如果用户格式和显示格式不匹配,则会使用阴影表面,并且可能会执行意外的颜色转换。 SDL2尝试使用硬件加速,并且可能执行意外的缩放和/或过滤。确保您得到所需的东西,以避免隐藏操作。
对于这种每秒30帧的传输来说,%50 cpu的用法听起来很像,为了以防万一,我将重写 sleep 函数,如下所示。
do
errno = 0;
while ( nanosleep(&ts, &ts) && errno == EINTR );
关于c - 如何有效地绘制帧缓冲区内容?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23873175/