summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb/qxcbbackingstore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbbackingstore.cpp')
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp119
1 files changed, 101 insertions, 18 deletions
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 42a868d997..c0f5477f82 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -49,6 +49,7 @@
#include <qdebug.h>
#include <qpainter.h>
#include <qscreen.h>
+#include <qpa/qplatformgraphicsbuffer.h>
#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -60,6 +61,8 @@ public:
~QXcbShmImage() { destroy(); }
QImage *image() { return &m_qimage; }
+ QPlatformGraphicsBuffer *graphicsBuffer() { return m_graphics_buffer; }
+
QSize size() const { return m_qimage.size(); }
void put(xcb_window_t window, const QPoint &dst, const QRect &source);
@@ -73,6 +76,7 @@ private:
xcb_image_t *m_xcb_image;
QImage m_qimage;
+ QPlatformGraphicsBuffer *m_graphics_buffer;
xcb_gcontext_t m_gc;
xcb_window_t m_gc_window;
@@ -80,8 +84,39 @@ private:
QRegion m_dirty;
};
+class QXcbShmGraphicsBuffer : public QPlatformGraphicsBuffer
+{
+public:
+ QXcbShmGraphicsBuffer(QImage *image)
+ : QPlatformGraphicsBuffer(image->size(), QImage::toPixelFormat(image->format()))
+ , m_access_lock(QPlatformGraphicsBuffer::None)
+ , m_image(image)
+ { }
+
+ bool doLock(AccessTypes access, const QRect &rect) Q_DECL_OVERRIDE
+ {
+ Q_UNUSED(rect);
+ if (access & ~(QPlatformGraphicsBuffer::SWReadAccess | QPlatformGraphicsBuffer::SWWriteAccess))
+ return false;
+
+ m_access_lock |= access;
+ return true;
+ }
+ void doUnlock() Q_DECL_OVERRIDE { m_access_lock = None; }
+
+ const uchar *data() const Q_DECL_OVERRIDE { return m_image->bits(); }
+ uchar *data() Q_DECL_OVERRIDE { return m_image->bits(); }
+ int bytesPerLine() const Q_DECL_OVERRIDE { return m_image->bytesPerLine(); }
+
+ Origin origin() const Q_DECL_OVERRIDE { return QPlatformGraphicsBuffer::OriginTopLeft; }
+private:
+ AccessTypes m_access_lock;
+ QImage *m_image;
+};
+
QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format)
: QXcbObject(screen->connection())
+ , m_graphics_buffer(Q_NULLPTR)
, m_gc(0)
, m_gc_window(0)
{
@@ -137,6 +172,7 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI
}
m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format);
+ m_graphics_buffer = new QXcbShmGraphicsBuffer(&m_qimage);
}
void QXcbShmImage::destroy()
@@ -158,6 +194,8 @@ void QXcbShmImage::destroy()
if (m_gc)
Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc));
+ delete m_graphics_buffer;
+ m_graphics_buffer = Q_NULLPTR;
}
void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &source)
@@ -265,21 +303,30 @@ QXcbBackingStore::~QXcbBackingStore()
QPaintDevice *QXcbBackingStore::paintDevice()
{
- return m_image ? m_image->image() : 0;
+ if (!m_image)
+ return 0;
+ return m_rgbImage.isNull() ? m_image->image() : &m_rgbImage;
}
void QXcbBackingStore::beginPaint(const QRegion &region)
{
if (!m_image)
return;
- const int dpr = int(m_image->image()->devicePixelRatio());
- QRegion xRegion = dpr == 1 ? region : QTransform::fromScale(dpr,dpr).map(region);
- m_image->preparePaint(xRegion);
+
+ int dpr = int(m_image->image()->devicePixelRatio());
+ const int windowDpr = int(window()->devicePixelRatio());
+ if (windowDpr != dpr) {
+ resize(window()->size(), QRegion());
+ dpr = int(m_image->image()->devicePixelRatio());
+ }
+
+ m_paintRegion = dpr == 1 ? region : QTransform::fromScale(dpr,dpr).map(region);
+ m_image->preparePaint(m_paintRegion);
if (m_image->image()->hasAlphaChannel()) {
- QPainter p(m_image->image());
+ QPainter p(paintDevice());
p.setCompositionMode(QPainter::CompositionMode_Source);
- const QVector<QRect> rects = xRegion.rects();
+ const QVector<QRect> rects = m_paintRegion.rects();
const QColor blank = Qt::transparent;
for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
p.fillRect(*it, blank);
@@ -287,17 +334,50 @@ void QXcbBackingStore::beginPaint(const QRegion &region)
}
}
+void QXcbBackingStore::endPaint()
+{
+ QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window()->handle());
+ if (!platformWindow || !platformWindow->imageNeedsRgbSwap())
+ return;
+
+ // Slow path: the paint device was m_rgbImage. Now copy with swapping red
+ // and blue into m_image.
+ const QVector<QRect> rects = m_paintRegion.rects();
+ if (rects.isEmpty())
+ return;
+ QPainter p(m_image->image());
+ for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
+ const QRect rect = *it;
+ p.drawImage(rect.topLeft(), m_rgbImage.copy(rect).rgbSwapped());
+ }
+}
+
+#ifndef QT_NO_OPENGL
QImage QXcbBackingStore::toImage() const
{
return m_image && m_image->image() ? *m_image->image() : QImage();
}
+#endif
+
+QPlatformGraphicsBuffer *QXcbBackingStore::graphicsBuffer() const
+{
+ return m_image ? m_image->graphicsBuffer() : Q_NULLPTR;
+}
void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
if (!m_image || m_image->size().isEmpty())
return;
- QSize imageSize = m_image->size();
+ const int dpr = int(window->devicePixelRatio());
+
+#ifndef QT_NO_DEBUG
+ const int imageDpr = int(m_image->image()->devicePixelRatio());
+ if (dpr != imageDpr)
+ qWarning() << "QXcbBackingStore::flush() wrong devicePixelRatio for backingstore image" << dpr << imageDpr;
+#endif
+
+ QSize imageSize = m_image->size() / dpr; //because we multiply with the DPR later
QRegion clipped = region;
clipped &= QRect(0, 0, window->width(), window->height());
@@ -316,8 +396,6 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoin
return;
}
- const int dpr = int(window->devicePixelRatio());
-
QVector<QRect> rects = clipped.rects();
for (int i = 0; i < rects.size(); ++i) {
QRect rect = QRect(rects.at(i).topLeft() * dpr, rects.at(i).size() * dpr);
@@ -354,8 +432,7 @@ void QXcbBackingStore::resize(const QSize &size, const QRegion &)
{
const int dpr = int(window()->devicePixelRatio());
const QSize xSize = size * dpr;
-
- if (m_image && xSize == m_image->size())
+ if (m_image && xSize == m_image->size() && dpr == m_image->image()->devicePixelRatio())
return;
Q_XCB_NOOP(connection());
@@ -370,6 +447,12 @@ void QXcbBackingStore::resize(const QSize &size, const QRegion &)
delete m_image;
m_image = new QXcbShmImage(screen, xSize, win->depth(), win->imageFormat());
m_image->image()->setDevicePixelRatio(dpr);
+ // Slow path for bgr888 VNC: Create an additional image, paint into that and
+ // swap R and B while copying to m_image after each paint.
+ if (win->imageNeedsRgbSwap()) {
+ m_rgbImage = QImage(xSize, win->imageFormat());
+ m_rgbImage.setDevicePixelRatio(dpr);
+ }
Q_XCB_NOOP(connection());
}