QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format) : QXcbObject(screen->connection()) , m_gc(0) , m_gc_window(0) { Q_XCB_NOOP(connection()); m_xcb_image = xcb_image_create_native(xcb_connection(), size.width(), size.height(), XCB_IMAGE_FORMAT_Z_PIXMAP, depth, 0, ~0, 0); m_shm_info.shmid = shmget (IPC_PRIVATE, m_xcb_image->stride * m_xcb_image->height, IPC_CREAT|0777); m_shm_info.shmaddr = m_xcb_image->data = (quint8 *)shmat (m_shm_info.shmid, 0, 0); m_shm_info.shmseg = xcb_generate_id(xcb_connection()); xcb_generic_error_t *error = xcb_request_check(xcb_connection(), xcb_shm_attach_checked(xcb_connection(), m_shm_info.shmseg, m_shm_info.shmid, false)); if (error) { qWarning() << "QXcbWindowSurface: Unable to attach to shared memory segment"; free(error); } if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1) qWarning() << "QXcbWindowSurface: Error while marking the shared memory segment to be destroyed"; m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format); }
ExcCode screen_shm_init() { xcb_query_extension_cookie_t extension_cookie = xcb_query_extension(display, strlen(MIT_SHM_EXTENSION_NAME), MIT_SHM_EXTENSION_NAME); xcb_query_extension_reply_t *extension_reply = xcb_query_extension_reply(display, extension_cookie, NULL); if (extension_reply == NULL) PANIC(ERR_X_EXTENSION, MIT_SHM_EXTENSION_NAME); free(extension_reply); xcb_shm_query_version_cookie_t version_cookie = xcb_shm_query_version(display); xcb_shm_query_version_reply_t *version_reply = xcb_shm_query_version_reply(display, version_cookie, NULL); if (version_reply == NULL) PANIC(ERR_X_EXTENSION, MIT_SHM_EXTENSION_NAME); free(version_reply); size_t max_size = screen->width_in_pixels * screen->height_in_pixels * sizeof (unsigned); shmid = shmget(IPC_PRIVATE, max_size, IPC_CREAT | 0777); if (shmid < 0) PANIC(ERR_SHM_ALLOC); shmaddr = shmat(shmid, 0, 0); if (shmaddr == (uint8_t *) -1) PANIC(ERR_SHM_ATTACH); shmseg = xcb_generate_id(display); xcb_void_cookie_t attach_cookie = xcb_shm_attach_checked(display, shmseg, shmid, 0); if (xcb_request_check(display, attach_cookie) != NULL) PANIC(ERR_SHM_ATTACH); return 0; }
QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format) : QXcbObject(screen->connection()) , m_gc(0) , m_gc_window(0) { Q_XCB_NOOP(connection()); m_xcb_image = xcb_image_create_native(xcb_connection(), size.width(), size.height(), XCB_IMAGE_FORMAT_Z_PIXMAP, depth, 0, ~0, 0); const int segmentSize = m_xcb_image->stride * m_xcb_image->height; if (!segmentSize) return; int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); if (id == -1) qWarning("QXcbShmImage: shmget() failed (%d) for size %d (%dx%d)", errno, segmentSize, size.width(), size.height()); else m_shm_info.shmid = id; m_shm_info.shmaddr = m_xcb_image->data = (quint8 *)shmat (m_shm_info.shmid, 0, 0); m_shm_info.shmseg = xcb_generate_id(xcb_connection()); const xcb_query_extension_reply_t *shm_reply = xcb_get_extension_data(xcb_connection(), &xcb_shm_id); bool shm_present = shm_reply != NULL && shm_reply->present; xcb_generic_error_t *error = NULL; if (shm_present) error = xcb_request_check(xcb_connection(), xcb_shm_attach_checked(xcb_connection(), m_shm_info.shmseg, m_shm_info.shmid, false)); if (!shm_present || error) { free(error); shmdt(m_shm_info.shmaddr); shmctl(m_shm_info.shmid, IPC_RMID, 0); m_shm_info.shmaddr = 0; m_xcb_image->data = (uint8_t *)malloc(segmentSize); } else { if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1) qWarning() << "QXcbBackingStore: Error while marking the shared memory segment to be destroyed"; } m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format); }
/** * Initialize a picture buffer as shared memory, according to the video output * format. If a attach is true, the segment is attached to * the X server (MIT-SHM extension). */ int PictureResourceAlloc (vout_display_t *vd, picture_resource_t *res, size_t size, xcb_connection_t *conn, bool attach) { res->p_sys = malloc (sizeof(*res->p_sys)); if (!res->p_sys) return VLC_EGENERIC; #ifdef HAVE_SYS_SHM_H /* Allocate shared memory segment */ int id = shmget (IPC_PRIVATE, size, IPC_CREAT | S_IRWXU); if (id == -1) { msg_Err (vd, "shared memory allocation error: %m"); free (res->p_sys); return VLC_EGENERIC; } /* Attach the segment to VLC */ void *shm = shmat (id, NULL, 0 /* read/write */); if (-1 == (intptr_t)shm) { msg_Err (vd, "shared memory attachment error: %m"); shmctl (id, IPC_RMID, 0); free (res->p_sys); return VLC_EGENERIC; } xcb_shm_seg_t segment; if (attach) { /* Attach the segment to X */ xcb_void_cookie_t ck; segment = xcb_generate_id (conn); ck = xcb_shm_attach_checked (conn, segment, id, 1); switch (CheckError (vd, conn, "shared memory server-side error", ck)) { case 0: break; case XCB_ACCESS: { struct shmid_ds buf; /* Retry with promiscuous permissions */ shmctl (id, IPC_STAT, &buf); buf.shm_perm.mode |= S_IRGRP|S_IROTH; shmctl (id, IPC_SET, &buf); ck = xcb_shm_attach_checked (conn, segment, id, 1); if (CheckError (vd, conn, "same error on retry", ck) == 0) break; /* fall through */ } default: msg_Info (vd, "using buggy X11 server - SSH proxying?"); segment = 0; } } else segment = 0; shmctl (id, IPC_RMID, NULL); res->p_sys->segment = segment; res->p->p_pixels = shm; #else assert (!attach); res->p_sys->segment = 0; /* XXX: align on 32 bytes for VLC chroma filters */ res->p->p_pixels = malloc (size); if (unlikely(res->p->p_pixels == NULL)) { free (res->p_sys); return VLC_EGENERIC; } #endif return VLC_SUCCESS; }