From 6a4ef30a8f585a3dc20b337eb336ab028c97ddb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 8 Feb 2011 14:34:52 +0100 Subject: Optimized XCB window surface using partial updates and shared images. --- src/plugins/platforms/xcb/qxcbconnection.cpp | 1 - src/plugins/platforms/xcb/qxcbwindow.cpp | 12 +- src/plugins/platforms/xcb/qxcbwindowsurface.cpp | 149 ++++++++++++++++++++---- src/plugins/platforms/xcb/qxcbwindowsurface.h | 8 +- src/plugins/platforms/xcb/xcb.pro | 2 +- 5 files changed, 138 insertions(+), 34 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 023f673..70c6a63 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -111,7 +111,6 @@ void QXcbConnection::eventDispatcher() HANDLE_PLATFORM_WINDOW_EVENT(xcb_client_message_event_t, window, handleClientMessageEvent); default: break; - } } } diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index c7bcd38..6dfccba 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -96,8 +96,6 @@ QXcbWindow::QXcbWindow(QWidget *tlw) 32, sizeof(properties) / sizeof(xcb_atom_t), properties); - - printf("m_window: %d\n", m_window); } QXcbWindow::~QXcbWindow() @@ -164,12 +162,12 @@ void QXcbWindow::requestActivateWindow() void QXcbWindow::handleExposeEvent(xcb_expose_event_t *event) { - if (event->count != 0) - return; - QWindowSurface *surface = widget()->windowSurface(); - if (surface) - surface->flush(widget(), widget()->geometry(), QPoint()); + if (surface) { + QRect rect(event->x, event->y, event->width, event->height); + + surface->flush(widget(), rect, QPoint()); + } } void QXcbWindow::handleClientMessageEvent(xcb_client_message_event_t *event) diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp index e3b2c6c..513de08 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp +++ b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp @@ -45,13 +45,119 @@ #include "qxcbscreen.h" #include "qxcbwindow.h" +#include +#include + +#include +#include + #include +class QXcbShmImage : public QXcbObject +{ +public: + QXcbShmImage(QXcbScreen *connection, const QSize &size); + ~QXcbShmImage() { destroy(); } + + QImage *image() { return &m_qimage; } + + void put(xcb_window_t window, const QPoint &dst, const QRect &source); + void preparePaint(const QRegion ®ion); + +private: + void destroy(); + + xcb_shm_segment_info_t m_shm_info; + + xcb_image_t *m_xcb_image; + + QImage m_qimage; + + xcb_gcontext_t m_gc; + xcb_window_t m_gc_window; + + QRegion m_dirty; +}; + +QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size) + : QXcbObject(screen->connection()) + , m_gc(0) + , m_gc_window(0) +{ + m_xcb_image = xcb_image_create_native(xcb_connection(), + size.width(), + size.height(), + XCB_IMAGE_FORMAT_Z_PIXMAP, + screen->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_shm_attach(xcb_connection(), m_shm_info.shmseg, m_shm_info.shmid, false); + + m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, screen->format()); +} + +void QXcbShmImage::destroy() +{ + xcb_shm_detach(xcb_connection(), m_shm_info.shmseg); + xcb_image_destroy(m_xcb_image); + shmdt(m_shm_info.shmaddr); + shmctl(m_shm_info.shmid, IPC_RMID, 0); + + xcb_free_gc(xcb_connection(), m_gc); +} + +void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &source) +{ + if (m_gc_window != window) { + xcb_free_gc(xcb_connection(), m_gc); + + m_gc = xcb_generate_id(xcb_connection()); + xcb_create_gc(xcb_connection(), m_gc, window, 0, 0); + + m_gc_window = window; + } + + xcb_image_shm_put(xcb_connection(), + window, + m_gc, + m_xcb_image, + m_shm_info, + source.x(), + source.y(), + target.x(), + target.y(), + source.width(), + source.height(), + false); + + m_dirty = m_dirty | source; + + xcb_flush(xcb_connection()); +} + +void QXcbShmImage::preparePaint(const QRegion ®ion) +{ + // to prevent X from reading from the image region while we're writing to it + if (m_dirty.intersects(region)) { + // from xcb_aux_sync + free(xcb_get_input_focus_reply(xcb_connection(), xcb_get_input_focus(xcb_connection()), 0)); + m_dirty = QRegion(); + } +} + QXcbWindowSurface::QXcbWindowSurface(QWidget *widget, bool setDefaultSurface) : QWindowSurface(widget, setDefaultSurface) + , m_image(0) { setStaticContentsSupport(false); - setPartialUpdateSupport(false); + setPartialUpdateSupport(true); QXcbScreen *screen = static_cast(QPlatformScreen::platformScreenForWidget(widget)); setConnection(screen->connection()); @@ -63,7 +169,12 @@ QXcbWindowSurface::~QXcbWindowSurface() QPaintDevice *QXcbWindowSurface::paintDevice() { - return &m_image; + return m_image->image(); +} + +void QXcbWindowSurface::beginPaint(const QRegion ®ion) +{ + m_image->preparePaint(region); } void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) @@ -73,42 +184,36 @@ void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoi QXcbWindow *window = static_cast(widget->window()->platformWindow()); - m_gc = xcb_generate_id(xcb_connection()); - xcb_create_gc(xcb_connection(), m_gc, window->window(), 0, 0); - - xcb_put_image(xcb_connection(), - XCB_IMAGE_FORMAT_Z_PIXMAP, - window->window(), - m_gc, - m_image.width(), - m_image.height(), - 0, - 0, - 0, - 24, - m_image.numBytes(), - m_image.bits()); + extern QWidgetData* qt_widget_data(QWidget *); + QPoint widgetOffset = qt_qwidget_data(widget)->wrect.topLeft(); - xcb_free_gc(xcb_connection(), m_gc); - xcb_flush(xcb_connection()); + QVector rects = region.rects(); + for (int i = 0; i < rects.size(); ++i) + m_image->put(window->window(), rects.at(i).topLeft() - widgetOffset, rects.at(i).translated(offset)); } void QXcbWindowSurface::resize(const QSize &size) { QWindowSurface::resize(size); - m_image = QImage(size, QImage::Format_RGB32); + + QXcbScreen *screen = static_cast(QPlatformScreen::platformScreenForWidget(window())); + + delete m_image; + m_image = new QXcbShmImage(screen, size); } extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); bool QXcbWindowSurface::scroll(const QRegion &area, int dx, int dy) { - if (m_image.isNull()) + if (m_image->image()->isNull()) return false; + m_image->preparePaint(area); + const QVector rects = area.rects(); for (int i = 0; i < rects.size(); ++i) - qt_scrollRectInImage(m_image, rects.at(i), QPoint(dx, dy)); + qt_scrollRectInImage(*m_image->image(), rects.at(i), QPoint(dx, dy)); return true; } diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.h b/src/plugins/platforms/xcb/qxcbwindowsurface.h index 66b9c29..ee63190 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.h +++ b/src/plugins/platforms/xcb/qxcbwindowsurface.h @@ -48,6 +48,8 @@ #include "qxcbobject.h" +class QXcbShmImage; + class QXcbWindowSurface : public QXcbObject, public QWindowSurface { public: @@ -59,10 +61,10 @@ public: void resize(const QSize &size); bool scroll(const QRegion &area, int dx, int dy); -private: - QImage m_image; + void beginPaint(const QRegion &); - xcb_gcontext_t m_gc; +private: + QXcbShmImage *m_image; }; #endif diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro index f63495c..a4f9246 100644 --- a/src/plugins/platforms/xcb/xcb.pro +++ b/src/plugins/platforms/xcb/xcb.pro @@ -19,7 +19,7 @@ HEADERS = \ qxcbwindow.h \ qxcbwindowsurface.h -LIBS += -lxcb +LIBS += -lxcb -lxcb-image include (../fontdatabases/genericunix/genericunix.pri) -- cgit v0.12