diff options
author | Liang Qi <liang.qi@qt.io> | 2018-02-16 08:54:58 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2018-02-16 08:54:58 +0100 |
commit | 942ab490724fcc9544e786e5783718e1a07aa50b (patch) | |
tree | feb7d3ff716edb37b2ca60e33c05adf8777bd964 /src/plugins/platforms/xcb | |
parent | 0fb8271a467202990c90321066e40faed640a7a8 (diff) | |
parent | 24adaa9a742e6f95ff897d0eb9a2bce0527dd042 (diff) |
Merge remote-tracking branch 'origin/5.11' into dev
Conflicts:
src/corelib/tools/tools.pri
Change-Id: I705630f9cecbf0ce51a22fc6116b8c49611259e9
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r-- | src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp | 4 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbbackingstore.cpp | 166 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 37 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.h | 6 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 6 |
5 files changed, 172 insertions, 47 deletions
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 56a737e882..21024385b0 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -134,7 +134,11 @@ static void updateFormatFromContext(QSurfaceFormat &format) } format.setProfile(QSurfaceFormat::NoProfile); + const bool isStereo = format.testOption(QSurfaceFormat::StereoBuffers); format.setOptions(QSurfaceFormat::FormatOptions()); + // Restore flags that come from the VisualInfo/FBConfig. + if (isStereo) + format.setOption(QSurfaceFormat::StereoBuffers); if (format.renderableType() == QSurfaceFormat::OpenGL) { if (format.version() < qMakePair(3, 0)) { diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 1cf45c96d1..eae0ee7613 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -48,9 +48,11 @@ #include <sys/ipc.h> #include <sys/shm.h> +#include <sys/mman.h> #include <stdio.h> #include <errno.h> +#include <unistd.h> #include <qdebug.h> #include <qpainter.h> @@ -61,6 +63,11 @@ #include <qendian.h> #include <algorithm> + +#if (XCB_SHM_MAJOR_VERSION == 1 && XCB_SHM_MINOR_VERSION >= 2) || XCB_SHM_MAJOR_VERSION > 1 +#define XCB_USE_SHM_FD +#endif + QT_BEGIN_NAMESPACE class QXcbShmImage : public QXcbObject @@ -85,6 +92,9 @@ public: void preparePaint(const QRegion ®ion); private: + void createShmSegment(size_t segmentSize); + void destroyShmSegment(size_t segmentSize); + void destroy(); void ensureGC(xcb_drawable_t dst); @@ -154,6 +164,11 @@ private: QImage *m_image; }; +static inline size_t imageDataSize(const xcb_image_t *image) +{ + return static_cast<size_t>(image->stride) * image->height; +} + QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format) : QXcbObject(screen->connection()) , m_graphics_buffer(nullptr) @@ -173,39 +188,13 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI XCB_IMAGE_ORDER_MSB_FIRST, 0, ~0, 0); - const int segmentSize = m_xcb_image->stride * m_xcb_image->height; + const size_t segmentSize = imageDataSize(m_xcb_image); if (!segmentSize) return; - int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); - if (id == -1) { - qWarning("QXcbShmImage: shmget() failed (%d: %s) for size %d (%dx%d)", - errno, strerror(errno), segmentSize, size.width(), size.height()); - } else { - m_shm_info.shmaddr = m_xcb_image->data = (quint8 *)shmat(id, 0, 0); - } - m_shm_info.shmid = id; - 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 || id == -1) { - free(error); - - if (id != -1) { - shmdt(m_shm_info.shmaddr); - shmctl(m_shm_info.shmid, IPC_RMID, 0); - } - m_shm_info.shmaddr = 0; + createShmSegment(segmentSize); - 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_xcb_image->data = m_shm_info.shmaddr ? m_shm_info.shmaddr : (uint8_t *)malloc(segmentSize); m_hasAlpha = QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha; if (!m_hasAlpha) @@ -270,6 +259,111 @@ void QXcbShmImage::flushScrolledRegion(bool clientSideScroll) } } +void QXcbShmImage::createShmSegment(size_t segmentSize) +{ + m_shm_info.shmaddr = nullptr; + + if (!connection()->hasShm()) + return; + +#ifdef XCB_USE_SHM_FD + if (connection()->hasShmFd()) { + if (Q_UNLIKELY(segmentSize > std::numeric_limits<uint32_t>::max())) { + qWarning("QXcbShmImage: xcb_shm_create_segment() can't be called for size %zu, maximum allowed size is %u", + segmentSize, std::numeric_limits<uint32_t>::max()); + return; + } + const auto seg = xcb_generate_id(xcb_connection()); + auto reply = Q_XCB_REPLY(xcb_shm_create_segment, + xcb_connection(), seg, segmentSize, false); + if (!reply) { + qWarning("QXcbShmImage: xcb_shm_create_segment() failed for size %zu", segmentSize); + return; + } + + int *fds = xcb_shm_create_segment_reply_fds(xcb_connection(), reply.get()); + if (reply->nfd != 1) { + for (int i = 0; i < reply->nfd; i++) + close(fds[i]); + + qWarning("QXcbShmImage: failed to get file descriptor for shm segment of size %zu", segmentSize); + return; + } + + void *addr = mmap(nullptr, segmentSize, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0], 0); + if (addr == MAP_FAILED) { + qWarning("QXcbShmImage: failed to mmap segment from X server (%d: %s) for size %zu", + errno, strerror(errno), segmentSize); + close(fds[0]); + xcb_shm_detach(xcb_connection(), seg); + return; + } + + close(fds[0]); + m_shm_info.shmseg = seg; + m_shm_info.shmaddr = static_cast<quint8 *>(addr); + } else +#endif + { + const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); + if (id == -1) { + qWarning("QXcbShmImage: shmget() failed (%d: %s) for size %zu", + errno, strerror(errno), segmentSize); + return; + } + + void *addr = shmat(id, 0, 0); + if (addr == (void *)-1) { + qWarning("QXcbShmImage: shmat() failed (%d: %s) for id %d", + errno, strerror(errno), id); + return; + } + + if (shmctl(id, IPC_RMID, 0) == -1) + qWarning("QXcbBackingStore: Error while marking the shared memory segment to be destroyed"); + + const auto seg = xcb_generate_id(xcb_connection()); + auto cookie = xcb_shm_attach_checked(xcb_connection(), seg, id, false); + auto *error = xcb_request_check(xcb_connection(), cookie); + if (error) { + connection()->printXcbError("QXcbShmImage: xcb_shm_attach() failed with error", error); + free(error); + if (shmdt(addr) == -1) { + qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p", + errno, strerror(errno), addr); + } + return; + } + + m_shm_info.shmseg = seg; + m_shm_info.shmid = id; // unused + m_shm_info.shmaddr = static_cast<quint8 *>(addr); + } +} + +void QXcbShmImage::destroyShmSegment(size_t segmentSize) +{ + auto cookie = xcb_shm_detach_checked(xcb_connection(), m_shm_info.shmseg); + xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); + if (error) + connection()->printXcbError("QXcbShmImage: xcb_shm_detach() failed with error", error); + +#ifdef XCB_USE_SHM_FD + if (connection()->hasShmFd()) { + if (munmap(m_shm_info.shmaddr, segmentSize) == -1) { + qWarning("QXcbShmImage: munmap() failed (%d: %s) for %p with size %zu", + errno, strerror(errno), m_shm_info.shmaddr, segmentSize); + } + } else +#endif + { + if (shmdt(m_shm_info.shmaddr) == -1) { + qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p", + errno, strerror(errno), m_shm_info.shmaddr); + } + } +} + extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); bool QXcbShmImage::scroll(const QRegion &area, int dx, int dy) @@ -318,17 +412,11 @@ bool QXcbShmImage::scroll(const QRegion &area, int dx, int dy) void QXcbShmImage::destroy() { - const int segmentSize = m_xcb_image ? (m_xcb_image->stride * m_xcb_image->height) : 0; - if (segmentSize && m_shm_info.shmaddr) - xcb_shm_detach(xcb_connection(), m_shm_info.shmseg); - - if (segmentSize) { - if (m_shm_info.shmaddr) { - shmdt(m_shm_info.shmaddr); - shmctl(m_shm_info.shmid, IPC_RMID, 0); - } else { + if (m_xcb_image->data) { + if (m_shm_info.shmaddr) + destroyShmSegment(imageDataSize(m_xcb_image)); + else free(m_xcb_image->data); - } } xcb_image_destroy(m_xcb_image); diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index d6013541fc..ee25d6a12f 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -582,6 +582,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra initializeAllAtoms(); + initializeShm(); if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR")) initializeXRandr(); if (!has_randr_extension) @@ -961,14 +962,20 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error) if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), error, &result)) return; + printXcbError("QXcbConnection: XCB error", error); +} + +void QXcbConnection::printXcbError(const char *message, xcb_generic_error_t *error) +{ uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1); uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1); - qWarning("QXcbConnection: XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d", - int(error->error_code), xcb_errors[clamped_error_code], - int(error->sequence), int(error->resource_id), - int(error->major_code), xcb_protocol_request_codes[clamped_major_code], - int(error->minor_code)); + qWarning("%s: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d", + message, + int(error->error_code), xcb_errors[clamped_error_code], + int(error->sequence), int(error->resource_id), + int(error->major_code), xcb_protocol_request_codes[clamped_major_code], + int(error->minor_code)); } static Qt::MouseButtons translateMouseButtons(int s) @@ -2084,6 +2091,26 @@ void QXcbConnection::sync() free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0)); } +void QXcbConnection::initializeShm() +{ + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_shm_id); + if (!reply || !reply->present) { + qWarning("QXcbConnection: MIT-SHM extension is not present on the X server."); + return; + } + + has_shm = true; + + auto shm_query = Q_XCB_REPLY(xcb_shm_query_version, m_connection); + if (!shm_query) { + qWarning("QXcbConnection: Failed to request MIT-SHM version"); + return; + } + + has_shm_fd = (shm_query->major_version == 1 && shm_query->minor_version >= 2) || + shm_query->major_version > 1; +} + void QXcbConnection::initializeXFixes() { const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xfixes_id); diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 2e06292f78..0a7f878ed8 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -438,6 +438,7 @@ public: void sync(); void handleXcbError(xcb_generic_error_t *error); + void printXcbError(const char *message, xcb_generic_error_t *error); void handleXcbEvent(xcb_generic_event_t *event); void printXcbEvent(const QLoggingCategory &log, const char *message, xcb_generic_event_t *event) const; @@ -475,6 +476,8 @@ public: bool hasXKB() const { return has_xkb; } bool hasXRender() const { return has_render_extension; } bool hasXInput2() const { return m_xi2Enabled; } + bool hasShm() const { return has_shm; } + bool hasShmFd() const { return has_shm_fd; } bool threadedEventHandling() const { return m_reader->isRunning(); } @@ -542,6 +545,7 @@ private slots: private: void initializeAllAtoms(); void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0); + void initializeShm(); void initializeXFixes(); void initializeXRender(); void initializeXRandr(); @@ -696,6 +700,8 @@ private: bool has_input_shape; bool has_xkb = false; bool has_render_extension = false; + bool has_shm = false; + bool has_shm_fd = false; Qt::MouseButtons m_buttonState = 0; Qt::MouseButton m_button = Qt::NoButton; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 5b05a230e4..e9a6e536a7 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2071,7 +2071,7 @@ bool QXcbWindow::isEmbedded() const QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const { if (!m_embedded) - return pos; + return QPlatformWindow::mapToGlobal(pos); QPoint ret; auto reply = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(), @@ -2088,7 +2088,7 @@ QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const { if (!m_embedded) - return pos; + return QPlatformWindow::mapFromGlobal(pos); QPoint ret; auto reply = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(), @@ -2857,7 +2857,7 @@ QString QXcbWindow::windowTitle(const QXcbConnection *conn, xcb_window_t window) utf8Atom, 0, 1024); if (reply && reply->format == 8 && reply->type == utf8Atom) { const char *name = reinterpret_cast<const char *>(xcb_get_property_value(reply.get())); - return QString::fromUtf8(name); + return QString::fromUtf8(name, xcb_get_property_value_length(reply.get())); } return QString(); } |