aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/qsgdefaultrendercontext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph/qsgdefaultrendercontext.cpp')
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext.cpp360
1 files changed, 157 insertions, 203 deletions
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
index 73b79c6300..1b0753e9ae 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
@@ -1,121 +1,98 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or 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.GPL2 and 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-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsgdefaultrendercontext_p.h"
+#include "qsgcurveglyphatlas_p.h"
#include <QtGui/QGuiApplication>
-#include <QtGui/QOpenGLFramebufferObject>
#include <QtQuick/private/qsgbatchrenderer_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
-#include <QtQuick/private/qsgatlastexture_p.h>
+#include <QtQuick/private/qsgrhiatlastexture_p.h>
+#include <QtQuick/private/qsgrhidistancefieldglyphcache_p.h>
+#include <QtQuick/private/qsgmaterialshader_p.h>
+
#include <QtQuick/private/qsgcompressedtexture_p.h>
-#include <QtQuick/private/qsgdefaultdistancefieldglyphcache_p.h>
-QT_BEGIN_NAMESPACE
+#include <QtQuick/qsgrendererinterface.h>
+#include <QtQuick/qquickgraphicsconfiguration.h>
-#define QSG_RENDERCONTEXT_PROPERTY "_q_sgrendercontext"
+QT_BEGIN_NAMESPACE
QSGDefaultRenderContext::QSGDefaultRenderContext(QSGContext *context)
: QSGRenderContext(context)
- , m_gl(nullptr)
- , m_depthStencilManager(nullptr)
+ , m_rhi(nullptr)
, m_maxTextureSize(0)
- , m_brokenIBOs(false)
- , m_serializedRender(false)
- , m_attachToGLContext(true)
- , m_atlasManager(nullptr)
+ , m_rhiAtlasManager(nullptr)
+ , m_currentFrameCommandBuffer(nullptr)
+ , m_currentFrameRenderPass(nullptr)
+ , m_useDepthBufferFor2D(true)
+ , m_glyphCacheResourceUpdates(nullptr)
{
-
}
/*!
Initializes the scene graph render context with the GL context \a context. This also
emits the ready() signal so that the QML graph can start building scene graph nodes.
*/
-void QSGDefaultRenderContext::initialize(void *context)
+void QSGDefaultRenderContext::initialize(const QSGRenderContext::InitParams *params)
{
if (!m_sg)
return;
- QOpenGLContext *openglContext = static_cast<QOpenGLContext *>(context);
+ const InitParams *initParams = static_cast<const InitParams *>(params);
+ if (initParams->sType != INIT_PARAMS_MAGIC)
+ qFatal("QSGDefaultRenderContext: Invalid parameters passed to initialize()");
- QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
- funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
+ m_initParams = *initParams;
- // Sanity check the surface format, in case it was overridden by the application
- QSurfaceFormat requested = m_sg->defaultSurfaceFormat();
- QSurfaceFormat actual = openglContext->format();
- if (requested.depthBufferSize() > 0 && actual.depthBufferSize() <= 0)
- qWarning("QSGContext::initialize: depth buffer support missing, expect rendering errors");
- if (requested.stencilBufferSize() > 0 && actual.stencilBufferSize() <= 0)
- qWarning("QSGContext::initialize: stencil buffer support missing, expect rendering errors");
+ m_rhi = m_initParams.rhi;
+ m_maxTextureSize = m_rhi->resourceLimit(QRhi::TextureSizeMax);
+ if (!m_rhiAtlasManager)
+ m_rhiAtlasManager = new QSGRhiAtlasTexture::Manager(this, m_initParams.initialSurfacePixelSize, m_initParams.maybeSurface);
- if (!m_atlasManager)
- m_atlasManager = new QSGAtlasTexture::Manager();
+ m_glyphCacheResourceUpdates = nullptr;
- Q_ASSERT_X(!m_gl, "QSGRenderContext::initialize", "already initialized!");
- m_gl = openglContext;
- if (m_attachToGLContext) {
- Q_ASSERT(!openglContext->property(QSG_RENDERCONTEXT_PROPERTY).isValid());
- openglContext->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant::fromValue(this));
- }
m_sg->renderContextInitialized(this);
-#ifdef Q_OS_LINUX
- const char *vendor = (const char *) funcs->glGetString(GL_VENDOR);
- if (vendor && strstr(vendor, "nouveau"))
- m_brokenIBOs = true;
- const char *renderer = (const char *) funcs->glGetString(GL_RENDERER);
- if (renderer && strstr(renderer, "llvmpipe"))
- m_serializedRender = true;
- if (vendor && renderer && strstr(vendor, "Hisilicon Technologies") && strstr(renderer, "Immersion.16"))
- m_brokenIBOs = true;
-#endif
-
emit initialized();
}
+void QSGDefaultRenderContext::invalidateGlyphCaches()
+{
+ {
+ auto it = m_glyphCaches.begin();
+ while (it != m_glyphCaches.end()) {
+ if (!(*it)->isActive()) {
+ delete *it;
+ it = m_glyphCaches.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+
+ qDeleteAll(m_curveGlyphAtlases);
+ m_curveGlyphAtlases.clear();
+
+ {
+ auto it = m_fontEnginesToClean.begin();
+ while (it != m_fontEnginesToClean.end()) {
+ if (it.value() == 0) {
+ it.key()->clearGlyphCache(this);
+ if (!it.key()->ref.deref())
+ delete it.key();
+ it = m_fontEnginesToClean.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+}
void QSGDefaultRenderContext::invalidate()
{
- if (!m_gl)
+ if (!m_rhi)
return;
qDeleteAll(m_texturesToDelete);
@@ -138,84 +115,77 @@ void QSGDefaultRenderContext::invalidate()
deferred deleted last.
Another alternative would be to use a QPointer in
- QSGAtlasTexture::Texture, but this seemed simpler.
+ QSGOpenGLAtlasTexture::Texture, but this seemed simpler.
*/
- m_atlasManager->invalidate();
- m_atlasManager->deleteLater();
- m_atlasManager = nullptr;
+ if (m_rhiAtlasManager) {
+ m_rhiAtlasManager->invalidate();
+ m_rhiAtlasManager->deleteLater();
+ m_rhiAtlasManager = nullptr;
+ }
// The following piece of code will read/write to the font engine's caches,
// potentially from different threads. However, this is safe because this
// code is only called from QQuickWindow's shutdown which is called
// only when the GUI is blocked, and multiple threads will call it in
// sequence. (see qsgdefaultglyphnode_p.cpp's init())
- for (QSet<QFontEngine *>::const_iterator it = m_fontEnginesToClean.constBegin(),
- end = m_fontEnginesToClean.constEnd(); it != end; ++it) {
- (*it)->clearGlyphCache(m_gl);
- if (!(*it)->ref.deref())
- delete *it;
+ for (auto it = m_fontEnginesToClean.constBegin(); it != m_fontEnginesToClean.constEnd(); ++it) {
+ it.key()->clearGlyphCache(this);
+ if (!it.key()->ref.deref())
+ delete it.key();
}
m_fontEnginesToClean.clear();
- delete m_depthStencilManager;
- m_depthStencilManager = nullptr;
+ qDeleteAll(m_curveGlyphAtlases);
+ m_curveGlyphAtlases.clear();
qDeleteAll(m_glyphCaches);
m_glyphCaches.clear();
- if (m_gl->property(QSG_RENDERCONTEXT_PROPERTY) == QVariant::fromValue(this))
- m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant());
- m_gl = nullptr;
+ resetGlyphCacheResources();
+
+ m_rhi = nullptr;
if (m_sg)
m_sg->renderContextInvalidated(this);
+
emit invalidated();
}
-static QBasicMutex qsg_framerender_mutex;
-
-void QSGDefaultRenderContext::renderNextFrame(QSGRenderer *renderer, uint fboId)
+void QSGDefaultRenderContext::prepareSync(qreal devicePixelRatio,
+ QRhiCommandBuffer *cb,
+ const QQuickGraphicsConfiguration &config)
{
- if (m_serializedRender)
- qsg_framerender_mutex.lock();
+ m_currentDevicePixelRatio = devicePixelRatio;
+ m_useDepthBufferFor2D = config.isDepthBufferEnabledFor2D();
- renderer->renderScene(fboId);
+ // we store the command buffer already here, in case there is something in
+ // an updatePaintNode() implementation that leads to needing it (for
+ // example, an updateTexture() call on a QSGRhiLayer)
+ m_currentFrameCommandBuffer = cb;
+}
+
+void QSGDefaultRenderContext::beginNextFrame(QSGRenderer *renderer, const QSGRenderTarget &renderTarget,
+ RenderPassCallback mainPassRecordingStart,
+ RenderPassCallback mainPassRecordingEnd,
+ void *callbackUserData)
+{
+ renderer->setRenderTarget(renderTarget);
+ renderer->setRenderPassRecordingCallbacks(mainPassRecordingStart, mainPassRecordingEnd, callbackUserData);
- if (m_serializedRender)
- qsg_framerender_mutex.unlock();
+ m_currentFrameCommandBuffer = renderTarget.cb; // usually the same as what was passed to prepareSync() but cannot count on that having been called
+ m_currentFrameRenderPass = renderTarget.rpDesc;
}
-/*!
- Returns a shared pointer to a depth stencil buffer that can be used with \a fbo.
-*/
-QSharedPointer<QSGDepthStencilBuffer> QSGDefaultRenderContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo)
+void QSGDefaultRenderContext::renderNextFrame(QSGRenderer *renderer)
{
- if (!m_gl)
- return QSharedPointer<QSGDepthStencilBuffer>();
- QSGDepthStencilBufferManager *manager = depthStencilBufferManager();
- QSGDepthStencilBuffer::Format format;
- format.size = fbo->size();
- format.samples = fbo->format().samples();
- format.attachments = QSGDepthStencilBuffer::DepthAttachment | QSGDepthStencilBuffer::StencilAttachment;
- QSharedPointer<QSGDepthStencilBuffer> buffer = manager->bufferForFormat(format);
- if (buffer.isNull()) {
- buffer = QSharedPointer<QSGDepthStencilBuffer>(new QSGDefaultDepthStencilBuffer(m_gl, format));
- manager->insertBuffer(buffer);
- }
- return buffer;
+ renderer->renderScene();
}
-/*!
- Returns a pointer to the context's depth/stencil buffer manager. This is useful for custom
- implementations of \l depthStencilBufferForFbo().
-*/
-QSGDepthStencilBufferManager *QSGDefaultRenderContext::depthStencilBufferManager()
+void QSGDefaultRenderContext::endNextFrame(QSGRenderer *renderer)
{
- if (!m_gl)
- return nullptr;
- if (!m_depthStencilManager)
- m_depthStencilManager = new QSGDepthStencilBufferManager(m_gl);
- return m_depthStencilManager;
+ Q_UNUSED(renderer);
+ m_currentFrameCommandBuffer = nullptr;
+ m_currentFrameRenderPass = nullptr;
}
QSGTexture *QSGDefaultRenderContext::createTexture(const QImage &image, uint flags) const
@@ -226,13 +196,15 @@ QSGTexture *QSGDefaultRenderContext::createTexture(const QImage &image, uint fla
// The atlas implementation is only supported from the render thread and
// does not support mipmaps.
- if (!mipmap && atlas && openglContext() && QThread::currentThread() == openglContext()->thread()) {
- QSGTexture *t = m_atlasManager->create(image, alpha);
- if (t)
- return t;
+ if (m_rhi) {
+ if (!mipmap && atlas && QThread::currentThread() == m_rhi->thread()) {
+ QSGTexture *t = m_rhiAtlasManager->create(image, alpha);
+ if (t)
+ return t;
+ }
}
- QSGPlainTexture *texture = new QSGPlainTexture();
+ QSGPlainTexture *texture = new QSGPlainTexture;
texture->setImage(image);
if (texture->hasAlphaChannel() && !alpha)
texture->setHasAlphaChannel(false);
@@ -240,106 +212,88 @@ QSGTexture *QSGDefaultRenderContext::createTexture(const QImage &image, uint fla
return texture;
}
-QSGRenderer *QSGDefaultRenderContext::createRenderer()
+QSGRenderer *QSGDefaultRenderContext::createRenderer(QSGRendererInterface::RenderMode renderMode)
{
- return new QSGBatchRenderer::Renderer(this);
+ return new QSGBatchRenderer::Renderer(this, renderMode);
}
QSGTexture *QSGDefaultRenderContext::compressedTextureForFactory(const QSGCompressedTextureFactory *factory) const
{
- // The atlas implementation is only supported from the render thread
- if (openglContext() && QThread::currentThread() == openglContext()->thread())
- return m_atlasManager->create(factory);
+ // This is only used for atlasing compressed textures. Returning null implies no atlas.
+
+ if (m_rhi && QThread::currentThread() == m_rhi->thread())
+ return m_rhiAtlasManager->create(factory);
+
return nullptr;
}
-/*!
- Compile \a shader, optionally using \a vertexCode and \a fragmentCode as
- replacement for the source code supplied by \a shader.
-
- If \a vertexCode or \a fragmentCode is supplied, the caller is responsible
- for setting up attribute bindings.
+void QSGDefaultRenderContext::initializeRhiShader(QSGMaterialShader *shader, QShader::Variant shaderVariant)
+{
+ QSGMaterialShaderPrivate::get(shader)->prepare(shaderVariant);
+}
- \a material is supplied in case the implementation needs to take the
- material flags into account.
- */
-void QSGDefaultRenderContext::compileShader(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode, const char *fragmentCode)
+void QSGDefaultRenderContext::preprocess()
{
- Q_UNUSED(material);
- if (vertexCode || fragmentCode) {
- Q_ASSERT_X((material->flags() & QSGMaterial::CustomCompileStep) == 0,
- "QSGRenderContext::compile()",
- "materials with custom compile step cannot have modified vertex or fragment code");
- QOpenGLShaderProgram *p = shader->program();
- p->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexCode ? vertexCode : shader->vertexShader());
- p->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragmentCode ? fragmentCode : shader->fragmentShader());
- p->link();
- if (!p->isLinked())
- qWarning() << "shader compilation failed:" << endl << p->log();
- } else {
- shader->compile();
+ for (auto it = m_glyphCaches.begin(); it != m_glyphCaches.end(); ++it) {
+ it.value()->processPendingGlyphs();
+ it.value()->update();
}
}
-QString QSGDefaultRenderContext::fontKey(const QRawFont &font)
+QSGCurveGlyphAtlas *QSGDefaultRenderContext::curveGlyphAtlas(const QRawFont &font)
{
- QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine;
- if (!fe->faceId().filename.isEmpty()) {
- QByteArray keyName = fe->faceId().filename;
- if (font.style() != QFont::StyleNormal)
- keyName += QByteArray(" I");
- if (font.weight() != QFont::Normal)
- keyName += ' ' + QByteArray::number(font.weight());
- keyName += QByteArray(" DF");
- return QString::fromUtf8(keyName);
- } else {
- return QString::fromLatin1("%1_%2_%3_%4")
- .arg(font.familyName())
- .arg(font.styleName())
- .arg(font.weight())
- .arg(font.style());
+ FontKey key = FontKey(font, 0);
+ QSGCurveGlyphAtlas *atlas = m_curveGlyphAtlases.value(key, nullptr);
+ if (atlas == nullptr) {
+ atlas = new QSGCurveGlyphAtlas(font);
+ m_curveGlyphAtlases.insert(key, atlas);
}
+
+ return atlas;
}
-void QSGDefaultRenderContext::initializeShader(QSGMaterialShader *shader)
+QSGDistanceFieldGlyphCache *QSGDefaultRenderContext::distanceFieldGlyphCache(const QRawFont &font, int renderTypeQuality)
{
- shader->program()->bind();
- shader->initialize();
+ FontKey key(font, renderTypeQuality);
+ QSGDistanceFieldGlyphCache *cache = m_glyphCaches.value(key, 0);
+ if (!cache && font.isValid()) {
+ cache = new QSGRhiDistanceFieldGlyphCache(this, font, renderTypeQuality);
+ m_glyphCaches.insert(key, cache);
+ }
+
+ return cache;
}
-void QSGDefaultRenderContext::setAttachToGraphicsContext(bool attach)
+QRhiResourceUpdateBatch *QSGDefaultRenderContext::maybeGlyphCacheResourceUpdates()
{
- Q_ASSERT(!isValid());
- m_attachToGLContext = attach;
+ return m_glyphCacheResourceUpdates;
}
-QSGDefaultRenderContext *QSGDefaultRenderContext::from(QOpenGLContext *context)
+QRhiResourceUpdateBatch *QSGDefaultRenderContext::glyphCacheResourceUpdates()
{
- return qobject_cast<QSGDefaultRenderContext *>(context->property(QSG_RENDERCONTEXT_PROPERTY).value<QObject *>());
+ if (!m_glyphCacheResourceUpdates)
+ m_glyphCacheResourceUpdates = m_rhi->nextResourceUpdateBatch();
+
+ return m_glyphCacheResourceUpdates;
}
-bool QSGDefaultRenderContext::separateIndexBuffer() const
+void QSGDefaultRenderContext::deferredReleaseGlyphCacheTexture(QRhiTexture *texture)
{
- // WebGL: A given WebGLBuffer object may only be bound to one of
- // the ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER target in its
- // lifetime. An attempt to bind a buffer object to the other
- // target will generate an INVALID_OPERATION error, and the
- // current binding will remain untouched.
- static const bool isWebGL = (qGuiApp->platformName().compare(QLatin1String("webgl")) == 0
- || qGuiApp->platformName().compare(QLatin1String("wasm")) == 0);
- return isWebGL;
+ if (texture)
+ m_pendingGlyphCacheTextures.insert(texture);
}
-QSGDistanceFieldGlyphCache *QSGDefaultRenderContext::distanceFieldGlyphCache(const QRawFont &font)
+void QSGDefaultRenderContext::resetGlyphCacheResources()
{
- QString key = fontKey(font);
- QSGDistanceFieldGlyphCache *cache = m_glyphCaches.value(key, 0);
- if (!cache) {
- cache = new QSGDefaultDistanceFieldGlyphCache(openglContext(), font);
- m_glyphCaches.insert(key, cache);
+ if (m_glyphCacheResourceUpdates) {
+ m_glyphCacheResourceUpdates->release();
+ m_glyphCacheResourceUpdates = nullptr;
}
- return cache;
+ for (QRhiTexture *t : std::as_const(m_pendingGlyphCacheTextures))
+ t->deleteLater(); // the QRhiTexture object stays valid for the current frame
+
+ m_pendingGlyphCacheTextures.clear();
}
QT_END_NAMESPACE