/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 or (at your option) any later version ** approved by the KDE Free Qt Foundation. The licenses are as published by ** the Free Software Foundation and appearing in the file LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qwasmbackingstore.h" #include "qwasmwindow.h" #include "qwasmcompositor.h" #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE QWasmBackingStore::QWasmBackingStore(QWasmCompositor *compositor, QWindow *window) : QPlatformBackingStore(window) , m_compositor(compositor) , m_texture(new QOpenGLTexture(QOpenGLTexture::Target2D)) { QWasmWindow *wasmWindow = static_cast(window->handle()); if (wasmWindow) wasmWindow->setBackingStore(this); } QWasmBackingStore::~QWasmBackingStore() { auto window = this->window(); QWasmIntegration::get()->removeBackingStore(window); destroy(); QWasmWindow *wasmWindow = static_cast(window->handle()); if (wasmWindow) wasmWindow->setBackingStore(nullptr); } void QWasmBackingStore::destroy() { if (m_texture->isCreated()) { auto context = m_compositor->context(); auto currentContext = QOpenGLContext::currentContext(); if (!currentContext || !QOpenGLContext::areSharing(context, currentContext)) { QOffscreenSurface offScreenSurface(m_compositor->screen()->screen()); offScreenSurface.setFormat(context->format()); offScreenSurface.create(); context->makeCurrent(&offScreenSurface); m_texture->destroy(); } else { m_texture->destroy(); } } } QPaintDevice *QWasmBackingStore::paintDevice() { return &m_image; } void QWasmBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { Q_UNUSED(window); Q_UNUSED(region); Q_UNUSED(offset); m_dirty |= region; m_compositor->requestRedraw(); } void QWasmBackingStore::updateTexture() { if (m_dirty.isNull()) return; if (m_recreateTexture) { m_recreateTexture = false; destroy(); } if (!m_texture->isCreated()) { m_texture->setMinificationFilter(QOpenGLTexture::Nearest); m_texture->setMagnificationFilter(QOpenGLTexture::Nearest); m_texture->setWrapMode(QOpenGLTexture::ClampToEdge); m_texture->setData(m_image, QOpenGLTexture::DontGenerateMipMaps); m_texture->create(); } m_texture->bind(); QRegion fixed; QRect imageRect = m_image.rect(); for (const QRect &rect : m_dirty) { // Convert device-independent dirty region to device region qreal dpr = m_image.devicePixelRatio(); QRect deviceRect = QRect(rect.topLeft() * dpr, rect.size() * dpr); // intersect with image rect to be sure QRect r = imageRect & deviceRect; // if the rect is wide enough it is cheaper to just extend it instead of doing an image copy if (r.width() >= imageRect.width() / 2) { r.setX(0); r.setWidth(imageRect.width()); } fixed |= r; } for (const QRect &rect : fixed) { // if the sub-rect is full-width we can pass the image data directly to // OpenGL instead of copying, since there is no gap between scanlines if (rect.width() == imageRect.width()) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, m_image.constScanLine(rect.y())); } else { glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, m_image.copy(rect).constBits()); } } /* End of code taken from QEGLPlatformBackingStore */ m_dirty = QRegion(); } void QWasmBackingStore::beginPaint(const QRegion ®ion) { m_dirty |= region; // Keep backing store device pixel ratio in sync with window if (m_image.devicePixelRatio() != window()->devicePixelRatio()) resize(backingStore()->size(), backingStore()->staticContents()); QPainter painter(&m_image); painter.setCompositionMode(QPainter::CompositionMode_Source); const QColor blank = Qt::transparent; for (const QRect &rect : region) painter.fillRect(rect, blank); } void QWasmBackingStore::resize(const QSize &size, const QRegion &staticContents) { Q_UNUSED(staticContents) m_image = QImage(size * window()->devicePixelRatio(), QImage::Format_RGB32); m_image.setDevicePixelRatio(window()->devicePixelRatio()); m_recreateTexture = true; } QImage QWasmBackingStore::toImage() const { // used by QPlatformBackingStore::composeAndFlush return m_image; } const QImage &QWasmBackingStore::getImageRef() const { return m_image; } const QOpenGLTexture *QWasmBackingStore::getUpdatedTexture() { updateTexture(); return m_texture.data(); } QT_END_NAMESPACE