1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29
30 #include "qwasmbackingstore.h"
31 #include "qwasmwindow.h"
32 #include "qwasmcompositor.h"
33
34 #include <QtGui/qopengltexture.h>
35 #include <QtGui/qmatrix4x4.h>
36 #include <QtGui/qpainter.h>
37 #include <private/qguiapplication_p.h>
38 #include <qpa/qplatformscreen.h>
39 #include <QtGui/qoffscreensurface.h>
40 #include <QtGui/qbackingstore.h>
41
42 QT_BEGIN_NAMESPACE
43
QWasmBackingStore(QWasmCompositor * compositor,QWindow * window)44 QWasmBackingStore::QWasmBackingStore(QWasmCompositor *compositor, QWindow *window)
45 : QPlatformBackingStore(window)
46 , m_compositor(compositor)
47 , m_texture(new QOpenGLTexture(QOpenGLTexture::Target2D))
48 {
49 QWasmWindow *wasmWindow = static_cast<QWasmWindow *>(window->handle());
50 if (wasmWindow)
51 wasmWindow->setBackingStore(this);
52 }
53
~QWasmBackingStore()54 QWasmBackingStore::~QWasmBackingStore()
55 {
56 auto window = this->window();
57 QWasmIntegration::get()->removeBackingStore(window);
58 destroy();
59 QWasmWindow *wasmWindow = static_cast<QWasmWindow *>(window->handle());
60 if (wasmWindow)
61 wasmWindow->setBackingStore(nullptr);
62 }
63
destroy()64 void QWasmBackingStore::destroy()
65 {
66 if (m_texture->isCreated()) {
67 auto context = m_compositor->context();
68 auto currentContext = QOpenGLContext::currentContext();
69 if (!currentContext || !QOpenGLContext::areSharing(context, currentContext)) {
70 QOffscreenSurface offScreenSurface(m_compositor->screen()->screen());
71 offScreenSurface.setFormat(context->format());
72 offScreenSurface.create();
73 context->makeCurrent(&offScreenSurface);
74 m_texture->destroy();
75 } else {
76 m_texture->destroy();
77 }
78 }
79 }
80
paintDevice()81 QPaintDevice *QWasmBackingStore::paintDevice()
82 {
83 return &m_image;
84 }
85
flush(QWindow * window,const QRegion & region,const QPoint & offset)86 void QWasmBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset)
87 {
88 Q_UNUSED(window);
89 Q_UNUSED(region);
90 Q_UNUSED(offset);
91
92 m_dirty |= region;
93 m_compositor->requestRedraw();
94 }
95
updateTexture()96 void QWasmBackingStore::updateTexture()
97 {
98 if (m_dirty.isNull())
99 return;
100
101 if (m_recreateTexture) {
102 m_recreateTexture = false;
103 destroy();
104 }
105
106 if (!m_texture->isCreated()) {
107 m_texture->setMinificationFilter(QOpenGLTexture::Nearest);
108 m_texture->setMagnificationFilter(QOpenGLTexture::Nearest);
109 m_texture->setWrapMode(QOpenGLTexture::ClampToEdge);
110 m_texture->setData(m_image, QOpenGLTexture::DontGenerateMipMaps);
111 m_texture->create();
112 }
113 m_texture->bind();
114
115 QRegion fixed;
116 QRect imageRect = m_image.rect();
117
118 for (const QRect &rect : m_dirty) {
119
120 // Convert device-independent dirty region to device region
121 qreal dpr = m_image.devicePixelRatio();
122 QRect deviceRect = QRect(rect.topLeft() * dpr, rect.size() * dpr);
123
124 // intersect with image rect to be sure
125 QRect r = imageRect & deviceRect;
126 // if the rect is wide enough it is cheaper to just extend it instead of doing an image copy
127 if (r.width() >= imageRect.width() / 2) {
128 r.setX(0);
129 r.setWidth(imageRect.width());
130 }
131
132 fixed |= r;
133 }
134
135 for (const QRect &rect : fixed) {
136 // if the sub-rect is full-width we can pass the image data directly to
137 // OpenGL instead of copying, since there is no gap between scanlines
138 if (rect.width() == imageRect.width()) {
139 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
140 m_image.constScanLine(rect.y()));
141 } else {
142 glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
143 m_image.copy(rect).constBits());
144 }
145 }
146 /* End of code taken from QEGLPlatformBackingStore */
147
148 m_dirty = QRegion();
149 }
150
beginPaint(const QRegion & region)151 void QWasmBackingStore::beginPaint(const QRegion ®ion)
152 {
153 m_dirty |= region;
154 // Keep backing store device pixel ratio in sync with window
155 if (m_image.devicePixelRatio() != window()->devicePixelRatio())
156 resize(backingStore()->size(), backingStore()->staticContents());
157
158 QPainter painter(&m_image);
159 painter.setCompositionMode(QPainter::CompositionMode_Source);
160 const QColor blank = Qt::transparent;
161 for (const QRect &rect : region)
162 painter.fillRect(rect, blank);
163 }
164
resize(const QSize & size,const QRegion & staticContents)165 void QWasmBackingStore::resize(const QSize &size, const QRegion &staticContents)
166 {
167 Q_UNUSED(staticContents)
168
169 m_image = QImage(size * window()->devicePixelRatio(), QImage::Format_RGB32);
170 m_image.setDevicePixelRatio(window()->devicePixelRatio());
171 m_recreateTexture = true;
172 }
173
toImage() const174 QImage QWasmBackingStore::toImage() const
175 {
176 // used by QPlatformBackingStore::composeAndFlush
177 return m_image;
178 }
179
getImageRef() const180 const QImage &QWasmBackingStore::getImageRef() const
181 {
182 return m_image;
183 }
184
getUpdatedTexture()185 const QOpenGLTexture *QWasmBackingStore::getUpdatedTexture()
186 {
187 updateTexture();
188 return m_texture.data();
189 }
190
191 QT_END_NAMESPACE
192