From 3e892e4a972446d17afde178a7b17482ecaced33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 14 Dec 2015 17:20:58 +0100 Subject: iOS: Switch backingstore to use raster paint engine, not GL Now that more of the raster operations are NEON-optimized this should be acceptable. The switch enables antialiased drawing, and makes iOS in line with other platforms in having QBackingStore backed by a QImage. The use of QImage also allows us to remove code from the backingstore implementation that was only needed to support the composeAndFlush code path. The common parts of a raster backingstore implementation have been factored out into QRasterBackingStore in platformsupport, which can be shared with more platforms in the future. [ChangeLog][iOS] QBackingStore now uses the raster paint engine instead of the OpenGL paint engine, enabling improved antialiased drawing. In case of performance regressions, the old code path can be enabled by setting the window's surface type to QSurface::OpenGLSurface. Task-number: QTBUG-35271 Change-Id: Ia300b9a5edf8dc0b4bfb99d84ed3c23a8523c267 Reviewed-by: Laszlo Agocs --- src/platformsupport/graphics/graphics.pri | 2 + .../graphics/qrasterbackingstore.cpp | 104 +++++++++++++++++++ .../graphics/qrasterbackingstore_p.h | 71 +++++++++++++ src/platformsupport/platformsupport.pro | 1 + src/plugins/platforms/ios/qiosbackingstore.h | 21 ++-- src/plugins/platforms/ios/qiosbackingstore.mm | 111 +++++++-------------- 6 files changed, 225 insertions(+), 85 deletions(-) create mode 100644 src/platformsupport/graphics/graphics.pri create mode 100644 src/platformsupport/graphics/qrasterbackingstore.cpp create mode 100644 src/platformsupport/graphics/qrasterbackingstore_p.h (limited to 'src') diff --git a/src/platformsupport/graphics/graphics.pri b/src/platformsupport/graphics/graphics.pri new file mode 100644 index 0000000000..43062682aa --- /dev/null +++ b/src/platformsupport/graphics/graphics.pri @@ -0,0 +1,2 @@ +HEADERS += $$PWD/qrasterbackingstore_p.h +SOURCES += $$PWD/qrasterbackingstore.cpp diff --git a/src/platformsupport/graphics/qrasterbackingstore.cpp b/src/platformsupport/graphics/qrasterbackingstore.cpp new file mode 100644 index 0000000000..a64a4cfa40 --- /dev/null +++ b/src/platformsupport/graphics/qrasterbackingstore.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** 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 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 +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** 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$ +** +****************************************************************************/ + +#include "qrasterbackingstore_p.h" + +#include + +QT_BEGIN_NAMESPACE + +QRasterBackingStore::QRasterBackingStore(QWindow *window) + : QPlatformBackingStore(window) +{ +} + +QRasterBackingStore::~QRasterBackingStore() +{ +} + +void QRasterBackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + Q_UNUSED(staticContents); + + int windowDevicePixelRatio = window()->devicePixelRatio(); + QSize effectiveBufferSize = size * windowDevicePixelRatio; + + if (m_image.size() == effectiveBufferSize) + return; + + QImage::Format format = window()->format().hasAlpha() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + m_image = QImage(effectiveBufferSize, format); + m_image.setDevicePixelRatio(windowDevicePixelRatio); + if (format == QImage::Format_ARGB32_Premultiplied) + m_image.fill(Qt::transparent); +} + +QPaintDevice *QRasterBackingStore::paintDevice() +{ + return &m_image; +} + +QImage QRasterBackingStore::toImage() const +{ + return m_image; +} + +bool QRasterBackingStore::scroll(const QRegion ®ion, int dx, int dy) +{ + if (window()->surfaceType() != QSurface::RasterSurface) + return false; + + extern void qt_scrollRectInImage(QImage &, const QRect &, const QPoint &); + + const qreal devicePixelRatio = m_image.devicePixelRatio(); + const QPoint delta(dx * devicePixelRatio, dy * devicePixelRatio); + + foreach (const QRect &rect, region.rects()) + qt_scrollRectInImage(m_image, QRect(rect.topLeft() * devicePixelRatio, rect.size() * devicePixelRatio), delta); + + return true; +} + +void QRasterBackingStore::beginPaint(const QRegion ®ion) +{ + if (!m_image.hasAlphaChannel()) + return; + + QPainter painter(&m_image); + painter.setCompositionMode(QPainter::CompositionMode_Source); + const QColor blank = Qt::transparent; + foreach (const QRect &rect, region.rects()) + painter.fillRect(rect, blank); +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/graphics/qrasterbackingstore_p.h b/src/platformsupport/graphics/qrasterbackingstore_p.h new file mode 100644 index 0000000000..314a6e6e79 --- /dev/null +++ b/src/platformsupport/graphics/qrasterbackingstore_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** 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 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 +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** 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$ +** +****************************************************************************/ + +#ifndef QRASTERBACKINGSTORE_P_H +#define QRASTERBACKINGSTORE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + + +QT_BEGIN_NAMESPACE + +class QRasterBackingStore : public QPlatformBackingStore +{ +public: + QRasterBackingStore(QWindow *window); + ~QRasterBackingStore(); + + QPaintDevice *paintDevice() Q_DECL_OVERRIDE; + QImage toImage() const Q_DECL_OVERRIDE; + void resize (const QSize &size, const QRegion &) Q_DECL_OVERRIDE; + bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE; + void beginPaint(const QRegion ®ion) Q_DECL_OVERRIDE; + +protected: + QImage m_image; +}; + +QT_END_NAMESPACE + +#endif // QRASTERBACKINGSTORE_P_H diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 1ea6d0eb69..81c7faa389 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -25,5 +25,6 @@ contains(QT_CONFIG, dbus) { include(dbusmenu/dbusmenu.pri) include(dbustray/dbustray.pri) } +ios: include(graphics/graphics.pri) load(qt_module) diff --git a/src/plugins/platforms/ios/qiosbackingstore.h b/src/plugins/platforms/ios/qiosbackingstore.h index 5d2ae429f1..387a286447 100644 --- a/src/plugins/platforms/ios/qiosbackingstore.h +++ b/src/plugins/platforms/ios/qiosbackingstore.h @@ -36,34 +36,31 @@ #include +#include + QT_BEGIN_NAMESPACE class QOpenGLPaintDevice; -class QOpenGLFramebufferObject; -class QOffscreenSurface; -class QIOSBackingStore : public QPlatformBackingStore +class QIOSBackingStore : public QRasterBackingStore { public: QIOSBackingStore(QWindow *window); ~QIOSBackingStore(); - QPaintDevice *paintDevice(); + QPaintDevice *paintDevice() Q_DECL_OVERRIDE; - void beginPaint(const QRegion &); - void endPaint(); + void beginPaint(const QRegion &) Q_DECL_OVERRIDE; + void endPaint() Q_DECL_OVERRIDE; - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); - void resize(const QSize &size, const QRegion &staticContents); - GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const; + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; + void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE; void makeCurrent(); private: QOpenGLContext *m_context; - QOpenGLPaintDevice *m_device; - QOpenGLFramebufferObject *m_fbo; - QOffscreenSurface *m_surface; + QOpenGLPaintDevice *m_glDevice; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosbackingstore.mm b/src/plugins/platforms/ios/qiosbackingstore.mm index 875d06dc80..f408c13af3 100644 --- a/src/plugins/platforms/ios/qiosbackingstore.mm +++ b/src/plugins/platforms/ios/qiosbackingstore.mm @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -58,13 +59,12 @@ void QIOSPaintDevice::ensureActiveTarget() } QIOSBackingStore::QIOSBackingStore(QWindow *window) - : QPlatformBackingStore(window) + : QRasterBackingStore(window) , m_context(new QOpenGLContext) - , m_device(0) - , m_fbo(0) - , m_surface(0) + , m_glDevice(nullptr) { QSurfaceFormat fmt = window->requestedFormat(); + // Due to sharing QIOSContext redirects our makeCurrent on window() attempts to // the global share context. Hence it is essential to have a compatible format. fmt.setDepthBufferSize(QSurfaceFormat::defaultFormat().depthBufferSize()); @@ -73,8 +73,10 @@ QIOSBackingStore::QIOSBackingStore(QWindow *window) if (fmt.depthBufferSize() == 0) qWarning("No depth in default format, expect rendering errors"); + // We use the surface both for raster operations and for GL drawing (when + // we blit the raster image), so the type needs to cover both use cases. if (window->surfaceType() == QSurface::RasterSurface) - window->setSurfaceType(QSurface::OpenGLSurface); + window->setSurfaceType(QSurface::RasterGLSurface); m_context->setFormat(fmt); m_context->setScreen(window->screen()); @@ -85,75 +87,44 @@ QIOSBackingStore::QIOSBackingStore(QWindow *window) QIOSBackingStore::~QIOSBackingStore() { - delete m_fbo; - delete m_surface; delete m_context; - delete m_device; + delete m_glDevice; } void QIOSBackingStore::makeCurrent() { - QSurface *surface = m_surface ? m_surface : static_cast(window()); - if (!m_context->makeCurrent(surface)) + if (!m_context->makeCurrent(window())) qWarning("QIOSBackingStore: makeCurrent() failed"); - if (m_fbo) - m_fbo->bind(); } -void QIOSBackingStore::beginPaint(const QRegion &) +void QIOSBackingStore::beginPaint(const QRegion ®ion) { - if (qt_window_private(window())->compositing) { - if (!m_fbo) { - delete m_device; - m_device = 0; - } - if (!m_surface) { - m_surface = new QOffscreenSurface; - m_surface->setFormat(m_context->format()); - m_surface->create(); - } - if (!m_context->makeCurrent(m_surface)) - qWarning("QIOSBackingStore: Failed to make offscreen surface current"); - const QSize size = window()->size() * window()->devicePixelRatio(); - if (m_fbo && m_fbo->size() != size) { - delete m_fbo; - m_fbo = 0; - } - if (!m_fbo) - m_fbo = new QOpenGLFramebufferObject(size, QOpenGLFramebufferObject::CombinedDepthStencil); - } else if (m_fbo) { - delete m_fbo; - m_fbo = 0; - delete m_surface; - m_surface = 0; - delete m_device; - m_device = 0; - } - makeCurrent(); - if (!m_device) - m_device = new QIOSPaintDevice(this); + if (!m_glDevice) + m_glDevice = new QIOSPaintDevice(this); + + if (window()->surfaceType() == QSurface::RasterGLSurface) + QRasterBackingStore::beginPaint(region); } void QIOSBackingStore::endPaint() { - if (m_fbo) { - m_fbo->release(); - glFlush(); - } } QPaintDevice *QIOSBackingStore::paintDevice() { - Q_ASSERT(m_device); + Q_ASSERT(m_glDevice); // Keep paint device size and device pixel ratio in sync with window qreal devicePixelRatio = window()->devicePixelRatio(); - m_device->setSize(window()->size() * devicePixelRatio); - m_device->setDevicePixelRatio(devicePixelRatio); + m_glDevice->setSize(window()->size() * devicePixelRatio); + m_glDevice->setDevicePixelRatio(devicePixelRatio); - return m_device; + if (window()->surfaceType() == QSurface::RasterGLSurface) + return QRasterBackingStore::paintDevice(); + else + return m_glDevice; } void QIOSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) @@ -171,6 +142,11 @@ void QIOSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin return; } + if (window->surfaceType() == QSurface::RasterGLSurface) { + QPainter painter(m_glDevice); + painter.drawImage(QPoint(), m_image); + } + m_context->makeCurrent(window); m_context->swapBuffers(window); } @@ -179,31 +155,20 @@ void QIOSBackingStore::resize(const QSize &size, const QRegion &staticContents) { Q_UNUSED(staticContents); - // Resizing the backing store would in our case mean resizing the QWindow, - // as we cheat and use an QOpenGLPaintDevice that we target at the window. - // That's probably not what the user intended, so we ignore resizes of the - // backing store and always keep the paint device's size in sync with the - // window size in beginPaint(). + if (window()->surfaceType() == QSurface::OpenGLSurface) { + // Resizing the backing store would in this case mean resizing the QWindow, + // as we use an QOpenGLPaintDevice that we target at the window. That's + // probably not what the user intended, so we ignore resizes of the backing + // store and always keep the paint device's size in sync with the window + // size in beginPaint(). - if (size != window()->size() && !window()->inherits("QWidgetWindow")) - qWarning() << "QIOSBackingStore needs to have the same size as its window"; -} - -GLuint QIOSBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const -{ - Q_ASSERT(qt_window_private(window())->compositing); - Q_UNUSED(dirtyRegion); - - if (flags) - *flags = TextureFlip; + if (size != window()->size() && !window()->inherits("QWidgetWindow")) + qWarning() << "QIOSBackingStore needs to have the same size as its window"; - if (!m_fbo) - return 0; - - if (textureSize) - *textureSize = m_fbo->size(); + return; + } - return m_fbo->texture(); + QRasterBackingStore::resize(size, staticContents); } QT_END_NAMESPACE -- cgit v1.2.3