我需要为未连接实际显示的虚拟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%。有什么更好的办法吗?我可以想到两个可能的改进:
  • 摆脱memcpy,仅将mmap的内存传递给MIT-SHM,但是MIT-SHM API似乎不支持此功能。
  • 获取某种“内容已更改”通知,以消除愚蠢的 sleep (但是我还没有找到合适的方法)。

  • 有任何想法吗?

    更新:
    如果删除的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/

    10-10 09:09