diff options
Diffstat (limited to 'src/quick/scenegraph')
90 files changed, 2082 insertions, 985 deletions
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp index 02cf8209d1..d715d900ba 100644 --- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp @@ -193,6 +193,12 @@ QRegion QSGAbstractSoftwareRenderer::optimizeRenderList() } } + if (m_obscuredRegion.contains(m_background->rect().toAlignedRect())) { + m_isOpaque = true; + } else { + m_isOpaque = false; + } + // Empty dirtyRegion (for second pass) m_dirtyRegion = QRegion(); m_obscuredRegion = QRegion(); @@ -227,11 +233,11 @@ void QSGAbstractSoftwareRenderer::setBackgroundColor(const QColor &color) renderableNode(m_background)->markMaterialDirty(); } -void QSGAbstractSoftwareRenderer::setBackgroundSize(const QSize &size) +void QSGAbstractSoftwareRenderer::setBackgroundRect(const QRect &rect) { - if (m_background->rect().size().toSize() == size) + if (m_background->rect().toRect() == rect) return; - m_background->setRect(0.0f, 0.0f, size.width(), size.height()); + m_background->setRect(rect); renderableNode(m_background)->markGeometryDirty(); // Invalidate the whole scene when the background is resized markDirty(); @@ -242,21 +248,21 @@ QColor QSGAbstractSoftwareRenderer::backgroundColor() return m_background->color(); } -QSize QSGAbstractSoftwareRenderer::backgroundSize() +QRect QSGAbstractSoftwareRenderer::backgroundRect() { - return m_background->rect().size().toSize(); + return m_background->rect().toRect(); } void QSGAbstractSoftwareRenderer::nodeAdded(QSGNode *node) { - qCDebug(lc2DRender) << "nodeAdded" << (void*)node; + qCDebug(lc2DRender, "nodeAdded %p", (void*)node); m_nodeUpdater->updateNodes(node); } void QSGAbstractSoftwareRenderer::nodeRemoved(QSGNode *node) { - qCDebug(lc2DRender) << "nodeRemoved" << (void*)node; + qCDebug(lc2DRender, "nodeRemoved %p", (void*)node); auto renderable = renderableNode(node); // remove mapping @@ -280,7 +286,7 @@ void QSGAbstractSoftwareRenderer::nodeRemoved(QSGNode *node) void QSGAbstractSoftwareRenderer::nodeGeometryUpdated(QSGNode *node) { - qCDebug(lc2DRender) << "nodeGeometryUpdated"; + qCDebug(lc2DRender, "nodeGeometryUpdated"); // Mark node as dirty auto renderable = renderableNode(node); @@ -293,7 +299,7 @@ void QSGAbstractSoftwareRenderer::nodeGeometryUpdated(QSGNode *node) void QSGAbstractSoftwareRenderer::nodeMaterialUpdated(QSGNode *node) { - qCDebug(lc2DRender) << "nodeMaterialUpdated"; + qCDebug(lc2DRender, "nodeMaterialUpdated"); // Mark node as dirty auto renderable = renderableNode(node); @@ -306,7 +312,7 @@ void QSGAbstractSoftwareRenderer::nodeMaterialUpdated(QSGNode *node) void QSGAbstractSoftwareRenderer::nodeMatrixUpdated(QSGNode *node) { - qCDebug(lc2DRender) << "nodeMaterialUpdated"; + qCDebug(lc2DRender, "nodeMaterialUpdated"); // Update children nodes m_nodeUpdater->updateNodes(node); @@ -314,7 +320,7 @@ void QSGAbstractSoftwareRenderer::nodeMatrixUpdated(QSGNode *node) void QSGAbstractSoftwareRenderer::nodeOpacityUpdated(QSGNode *node) { - qCDebug(lc2DRender) << "nodeOpacityUpdated"; + qCDebug(lc2DRender, "nodeOpacityUpdated"); // Update children nodes m_nodeUpdater->updateNodes(node); diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h index 04a17ea377..f6594d931a 100644 --- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h @@ -83,9 +83,11 @@ protected: QRegion optimizeRenderList(); void setBackgroundColor(const QColor &color); - void setBackgroundSize(const QSize &size); + void setBackgroundRect(const QRect &rect); QColor backgroundColor(); - QSize backgroundSize(); + QRect backgroundRect(); + // only known after calling optimizeRenderList() + bool isOpaque() const { return m_isOpaque; } private: void nodeAdded(QSGNode *node); @@ -102,6 +104,7 @@ private: QRegion m_dirtyRegion; QRegion m_obscuredRegion; + bool m_isOpaque = false; QSGSoftwareRenderableNodeUpdater *m_nodeUpdater; }; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp index 92c02b4966..a8b5944974 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp @@ -87,6 +87,6 @@ QSGRenderLoop *QSGSoftwareAdaptation::createWindowManager() return new QSGSoftwareRenderLoop(); } -QSGSoftwareContext *QSGSoftwareAdaptation::instance = 0; +QSGSoftwareContext *QSGSoftwareAdaptation::instance = nullptr; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation_p.h index ffe54b5d4b..8b2a545033 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation_p.h @@ -62,7 +62,7 @@ class QSGSoftwareContext; class QSGSoftwareAdaptation : public QSGContextPlugin { public: - QSGSoftwareAdaptation(QObject *parent = 0); + QSGSoftwareAdaptation(QObject *parent = nullptr); QStringList keys() const override; QSGContext *create(const QString &key) const override; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp index aa850a80db..5b5bf005d8 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp @@ -205,12 +205,12 @@ QSGRendererInterface::ShaderType QSGSoftwareContext::shaderType() const QSGRendererInterface::ShaderCompilationTypes QSGSoftwareContext::shaderCompilationType() const { - return 0; + return nullptr; } QSGRendererInterface::ShaderSourceTypes QSGSoftwareContext::shaderSourceType() const { - return 0; + return nullptr; } void *QSGSoftwareContext::getResource(QQuickWindow *window, Resource resource) const diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp index 10291b9cb5..3b0f3c48ff 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp @@ -318,7 +318,7 @@ void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargin QSGSoftwareInternalImageNode::QSGSoftwareInternalImageNode() : m_innerSourceRect(0, 0, 1, 1) , m_subSourceRect(0, 0, 1, 1) - , m_texture(0) + , m_texture(nullptr) , m_mirror(false) , m_smooth(true) , m_tileHorizontal(false) @@ -462,7 +462,7 @@ void QSGSoftwareInternalImageNode::paint(QPainter *painter) m_targetRect.right() - m_innerTargetRect.right(), m_targetRect.bottom() - m_innerTargetRect.bottom()); QSGSoftwareHelpers::QTileRules tilerules(getTileRule(m_subSourceRect.width()), getTileRule(m_subSourceRect.height())); QSGSoftwareHelpers::qDrawBorderPixmap(painter, m_targetRect.toRect(), margins, pm, QRect(0, 0, pm.width(), pm.height()), - margins, tilerules, QSGSoftwareHelpers::QDrawBorderPixmap::DrawingHints(0)); + margins, tilerules, QSGSoftwareHelpers::QDrawBorderPixmap::DrawingHints(nullptr)); return; } @@ -490,12 +490,13 @@ QRectF QSGSoftwareInternalImageNode::rect() const const QPixmap &QSGSoftwareInternalImageNode::pixmap() const { - if (QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture*>(m_texture)) { + if (QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture*>(m_texture)) return pt->pixmap(); - } else { - QSGSoftwareLayer *layer = qobject_cast<QSGSoftwareLayer*>(m_texture); + if (QSGSoftwareLayer *layer = qobject_cast<QSGSoftwareLayer*>(m_texture)) return layer->pixmap(); - } + Q_ASSERT(m_texture == nullptr); + static const QPixmap nullPixmap; + return nullPixmap; } QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h index f21667fdf7..5c95eb064a 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h @@ -124,8 +124,8 @@ public: QRectF rect() const; -private: const QPixmap &pixmap() const; +private: QRectF m_targetRect; QRectF m_innerTargetRect; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp index f6898b3879..bf3141bc32 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp @@ -227,8 +227,8 @@ void QSGSoftwareInternalRectangleNode::paint(QPainter *painter) { //We can only check for a device pixel ratio change when we know what //paint device is being used. - if (painter->device()->devicePixelRatio() != m_devicePixelRatio) { - m_devicePixelRatio = painter->device()->devicePixelRatio(); + if (!qFuzzyCompare(painter->device()->devicePixelRatioF(), m_devicePixelRatio)) { + m_devicePixelRatio = painter->device()->devicePixelRatioF(); generateCornerPixmap(); } @@ -245,7 +245,7 @@ void QSGSoftwareInternalRectangleNode::paint(QPainter *painter) } else { //Rounded Rects and Rects with Borders //Avoids broken behaviors of QPainter::drawRect/roundedRect - QPixmap pixmap = QPixmap(m_rect.width() * m_devicePixelRatio, m_rect.height() * m_devicePixelRatio); + QPixmap pixmap = QPixmap(qRound(m_rect.width() * m_devicePixelRatio), qRound(m_rect.height() * m_devicePixelRatio)); pixmap.fill(Qt::transparent); pixmap.setDevicePixelRatio(m_devicePixelRatio); QPainter pixmapPainter(&pixmap); @@ -356,7 +356,7 @@ void QSGSoftwareInternalRectangleNode::paintRectangle(QPainter *painter, const Q } else { //blit 4 corners to border - int scaledRadius = radius * m_devicePixelRatio; + int scaledRadius = qRound(radius * m_devicePixelRatio); QRectF topLeftCorner(QPointF(rect.x(), rect.y()), QPointF(rect.x() + radius, rect.y() + radius)); painter->drawPixmap(topLeftCorner, m_cornerPixmap, QRectF(0, 0, scaledRadius, scaledRadius)); @@ -416,7 +416,7 @@ void QSGSoftwareInternalRectangleNode::generateCornerPixmap() //Generate new corner Pixmap int radius = qFloor(qMin(qMin(m_rect.width(), m_rect.height()) * 0.5, m_radius)); - m_cornerPixmap = QPixmap(radius * 2 * m_devicePixelRatio, radius * 2 * m_devicePixelRatio); + m_cornerPixmap = QPixmap(qRound(radius * 2 * m_devicePixelRatio), qRound(radius * 2 * m_devicePixelRatio)); m_cornerPixmap.setDevicePixelRatio(m_devicePixelRatio); m_cornerPixmap.fill(Qt::transparent); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h index f363e279e1..1f87424d2a 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h @@ -95,7 +95,7 @@ private: bool m_cornerPixmapIsDirty; QPixmap m_cornerPixmap; - int m_devicePixelRatio; + qreal m_devicePixelRatio; }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp index bd5d8f72c0..b4301451d8 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp @@ -45,9 +45,9 @@ QT_BEGIN_NAMESPACE QSGSoftwareLayer::QSGSoftwareLayer(QSGRenderContext *renderContext) - : m_item(0) + : m_item(nullptr) , m_context(renderContext) - , m_renderer(0) + , m_renderer(nullptr) , m_device_pixel_ratio(1) , m_mirrorHorizontal(false) , m_mirrorVertical(true) @@ -203,7 +203,7 @@ void QSGSoftwareLayer::markDirtyTexture() void QSGSoftwareLayer::invalidated() { delete m_renderer; - m_renderer = 0; + m_renderer = nullptr; } void QSGSoftwareLayer::grab() @@ -229,9 +229,6 @@ void QSGSoftwareLayer::grab() if (m_pixmap.size() != m_size) { m_pixmap = QPixmap(m_size); m_pixmap.setDevicePixelRatio(m_device_pixel_ratio); - // This fill here is wasteful, but necessary because it is the only way - // to force a QImage based pixmap to have an alpha channel. - m_pixmap.fill(Qt::transparent); } // Render texture. diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepainternode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepainternode.cpp index 34b0cd5b72..60ae06dd94 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepainternode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepainternode.cpp @@ -47,7 +47,7 @@ QSGSoftwarePainterNode::QSGSoftwarePainterNode(QQuickPaintedItem *item) : QSGPainterNode() , m_preferredRenderTarget(QQuickPaintedItem::Image) , m_item(item) - , m_texture(0) + , m_texture(nullptr) , m_dirtyContents(false) , m_opaquePainting(false) , m_linear_filtering(false) diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp index ad6cf39425..303f98c801 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp @@ -79,16 +79,9 @@ void QSGSoftwarePixmapRenderer::render(QPaintDevice *target) QElapsedTimer renderTimer; // Setup background item - setBackgroundSize(QSize(target->width(), target->height())); + setBackgroundRect(m_projectionRect); setBackgroundColor(clearColor()); - QPainter painter(target); - painter.setRenderHint(QPainter::Antialiasing); - painter.setWindow(m_projectionRect); - auto rc = static_cast<QSGSoftwareRenderContext *>(context()); - QPainter *prevPainter = rc->m_activePainter; - rc->m_activePainter = &painter; - renderTimer.start(); buildRenderList(); qint64 buildRenderListTime = renderTimer.restart(); @@ -101,6 +94,19 @@ void QSGSoftwarePixmapRenderer::render(QPaintDevice *target) optimizeRenderList(); qint64 optimizeRenderListTime = renderTimer.restart(); + if (!isOpaque() && target->devType() == QInternal::Pixmap) { + // This fill here is wasteful, but necessary because it is the only way + // to force a QImage based pixmap to have an alpha channel. + static_cast<QPixmap *>(target)->fill(Qt::transparent); + } + + QPainter painter(target); + painter.setRenderHint(QPainter::Antialiasing); + painter.setWindow(m_projectionRect); + auto rc = static_cast<QSGSoftwareRenderContext *>(context()); + QPainter *prevPainter = rc->m_activePainter; + rc->m_activePainter = &painter; + QRegion paintedRegion = renderNodes(&painter); qint64 renderTime = renderTimer.elapsed(); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp index 77d21ec042..1463681fa3 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp @@ -188,7 +188,7 @@ void QSGSoftwareNinePatchNode::paint(QPainter *painter) painter->drawPixmap(m_bounds, m_pixmap, QRectF(0, 0, m_pixmap.width(), m_pixmap.height())); else QSGSoftwareHelpers::qDrawBorderPixmap(painter, m_bounds.toRect(), m_margins, m_pixmap, QRect(0, 0, m_pixmap.width(), m_pixmap.height()), - m_margins, Qt::StretchTile, QSGSoftwareHelpers::QDrawBorderPixmap::DrawingHints(0)); + m_margins, Qt::StretchTile, QSGSoftwareHelpers::QDrawBorderPixmap::DrawingHints(nullptr)); } QRectF QSGSoftwareNinePatchNode::bounds() const diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes_p.h index 9f1913205b..114137fb55 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes_p.h @@ -133,6 +133,8 @@ public: QRectF bounds() const; + bool isOpaque() const { return !m_pixmap.hasAlphaChannel(); } + private: QPixmap m_pixmap; QRectF m_bounds; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp index cecc6c21ca..7fb531cca3 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp @@ -134,73 +134,58 @@ void QSGSoftwareRenderableNode::update() { // Update the Node properties m_isDirty = true; + m_isOpaque = false; QRectF boundingRect; switch (m_nodeType) { case QSGSoftwareRenderableNode::SimpleRect: - if (m_handle.simpleRectNode->color().alpha() == 255 && !m_transform.isRotating()) + if (m_handle.simpleRectNode->color().alpha() == 255) m_isOpaque = true; - else - m_isOpaque = false; boundingRect = m_handle.simpleRectNode->rect(); break; case QSGSoftwareRenderableNode::SimpleTexture: - if (!m_handle.simpleTextureNode->texture()->hasAlphaChannel() && !m_transform.isRotating()) + if (!m_handle.simpleTextureNode->texture()->hasAlphaChannel()) m_isOpaque = true; - else - m_isOpaque = false; boundingRect = m_handle.simpleTextureNode->rect(); break; case QSGSoftwareRenderableNode::Image: - // There isn't a way to tell, so assume it's not - m_isOpaque = false; + m_isOpaque = !m_handle.imageNode->pixmap().hasAlphaChannel(); boundingRect = m_handle.imageNode->rect().toRect(); break; case QSGSoftwareRenderableNode::Painter: - if (m_handle.painterNode->opaquePainting() && !m_transform.isRotating()) + if (m_handle.painterNode->opaquePainting()) m_isOpaque = true; - else - m_isOpaque = false; boundingRect = QRectF(0, 0, m_handle.painterNode->size().width(), m_handle.painterNode->size().height()); break; case QSGSoftwareRenderableNode::Rectangle: - if (m_handle.rectangleNode->isOpaque() && !m_transform.isRotating()) + if (m_handle.rectangleNode->isOpaque()) m_isOpaque = true; - else - m_isOpaque = false; boundingRect = m_handle.rectangleNode->rect(); break; case QSGSoftwareRenderableNode::Glyph: // Always has alpha - m_isOpaque = false; - boundingRect = m_handle.glpyhNode->boundingRect(); break; case QSGSoftwareRenderableNode::NinePatch: - // Difficult to tell, assume non-opaque - m_isOpaque = false; + m_isOpaque = m_handle.ninePatchNode->isOpaque(); boundingRect = m_handle.ninePatchNode->bounds(); break; case QSGSoftwareRenderableNode::SimpleRectangle: - if (m_handle.simpleRectangleNode->color().alpha() == 255 && !m_transform.isRotating()) + if (m_handle.simpleRectangleNode->color().alpha() == 255) m_isOpaque = true; - else - m_isOpaque = false; boundingRect = m_handle.simpleRectangleNode->rect(); break; case QSGSoftwareRenderableNode::SimpleImage: - if (!m_handle.simpleImageNode->texture()->hasAlphaChannel() && !m_transform.isRotating()) + if (!m_handle.simpleImageNode->texture()->hasAlphaChannel()) m_isOpaque = true; - else - m_isOpaque = false; boundingRect = m_handle.simpleImageNode->rect(); break; @@ -211,10 +196,8 @@ void QSGSoftwareRenderableNode::update() break; #endif case QSGSoftwareRenderableNode::RenderNode: - if (m_handle.renderNode->flags().testFlag(QSGRenderNode::OpaqueRendering) && !m_transform.isRotating()) + if (m_handle.renderNode->flags().testFlag(QSGRenderNode::OpaqueRendering)) m_isOpaque = true; - else - m_isOpaque = false; boundingRect = m_handle.renderNode->rect(); break; @@ -222,6 +205,9 @@ void QSGSoftwareRenderableNode::update() break; } + if (m_transform.isRotating()) + m_isOpaque = false; + const QRectF transformedRect = m_transform.mapRect(boundingRect); m_boundingRectMin = toRectMin(transformedRect); m_boundingRectMax = toRectMax(transformedRect); @@ -232,8 +218,9 @@ void QSGSoftwareRenderableNode::update() m_boundingRectMin = QRect(); m_boundingRectMax = QRect(); } else { - m_boundingRectMin = m_boundingRectMin.intersected(m_clipRegion.rects().constFirst()); - m_boundingRectMax = m_boundingRectMax.intersected(m_clipRegion.rects().constFirst()); + const auto rects = m_clipRegion.begin(); + m_boundingRectMin = m_boundingRectMin.intersected(rects[0]); + m_boundingRectMax = m_boundingRectMax.intersected(rects[0]); } } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp index 666f1d0616..fabecfcbb8 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp @@ -83,7 +83,7 @@ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGTransformNode *) bool QSGSoftwareRenderableNodeUpdater::visit(QSGClipNode *node) { // Make sure to translate the clip rect into world coordinates - if (m_clipState.count() == 0 || m_clipState.top().isNull()) { + if (m_clipState.count() == 0 || (m_clipState.count() == 1 && m_clipState.top().isNull())) { m_clipState.push(m_transformState.top().map(QRegion(node->clipRect().toRect()))); m_hasClip = true; } else { @@ -97,7 +97,7 @@ bool QSGSoftwareRenderableNodeUpdater::visit(QSGClipNode *node) void QSGSoftwareRenderableNodeUpdater::endVisit(QSGClipNode *) { m_clipState.pop(); - if (m_clipState.count() == 0 || m_clipState.top().isNull()) + if (m_clipState.count() == 0 || (m_clipState.count() == 1 && m_clipState.top().isNull())) m_hasClip = false; } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp index 85d04fe136..ffcee5f56e 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp @@ -112,7 +112,8 @@ void QSGSoftwareRenderer::render() QElapsedTimer renderTimer; setBackgroundColor(clearColor()); - setBackgroundSize(QSize(m_paintDevice->width() / m_paintDevice->devicePixelRatio(), + setBackgroundRect(QRect(0, 0, + m_paintDevice->width() / m_paintDevice->devicePixelRatio(), m_paintDevice->height() / m_paintDevice->devicePixelRatio())); // Build Renderlist @@ -155,6 +156,7 @@ void QSGSoftwareRenderer::render() m_flushRegion = renderNodes(&painter); qint64 renderTime = renderTimer.elapsed(); + painter.end(); if (m_backingStore != nullptr) m_backingStore->endPaint(); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp index 3f0d1383b9..423f5f7321 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp @@ -97,7 +97,6 @@ void QSGSoftwareRenderLoop::windowDestroyed(QQuickWindow *window) if (m_windows.size() == 0) { rc->invalidate(); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); } } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp index 832b69d0cc..f8973af2fb 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp @@ -294,7 +294,7 @@ bool QSGSoftwareRenderThread::event(QEvent *e) } rc->invalidate(); QCoreApplication::processEvents(); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); if (wme->destroying) delete wd->animationController; } @@ -456,7 +456,7 @@ void QSGSoftwareRenderThread::sync(bool inExpose) // Process deferred deletes now, directly after the sync as deleteLater // on the GUI must now also have resulted in SG changes and the delete // is a safe operation. - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); } if (!inExpose) { @@ -523,7 +523,7 @@ void QSGSoftwareRenderThread::syncAndRender() // rate of the current screen the window is on. int blockTime = vsyncDelta - (int) renderThrottleTimer.elapsed(); if (blockTime > 0) { - qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "RT - blocking for " << blockTime << "ms"; + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - blocking for %d ms", blockTime); msleep(blockTime); } renderThrottleTimer.restart(); diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp new file mode 100644 index 0000000000..e868a4380e --- /dev/null +++ b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + +#include "qsgcompressedatlastexture_p.h" + +#include <QtCore/QVarLengthArray> +#include <QtCore/QElapsedTimer> +#include <QtCore/QtMath> + +#include <QtGui/QOpenGLContext> +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> +#include <QtGui/QSurface> +#include <QtGui/QWindow> +#include <QtGui/QOpenGLFunctions> +#include <QtGui/QOpenGLTexture> +#include <QDebug> + +#include <private/qqmlglobal_p.h> +#include <private/qquickprofiler_p.h> +#include <private/qsgtexture_p.h> +#include <private/qsgcompressedtexture_p.h> +#include <private/qsgpkmhandler_p.h> + +QT_BEGIN_NAMESPACE + +static QElapsedTimer qsg_renderer_timer; + +namespace QSGCompressedAtlasTexture +{ + +Atlas::Atlas(const QSize &size, uint format) + : QSGAtlasTexture::AtlasBase(size) + , m_format(format) +{ +} + +Atlas::~Atlas() +{ +} + +Texture *Atlas::create(const QByteArray &data, int dataLength, int dataOffset, const QSize &size, const QSize &paddedSize) +{ + // No need to lock, as manager already locked it. + QRect rect = m_allocator.allocate(paddedSize); + if (rect.width() > 0 && rect.height() > 0) { + Texture *t = new Texture(this, rect, data, dataLength, dataOffset, size); + m_pending_uploads << t; + return t; + } + return nullptr; +} + +void Atlas::generateTexture() +{ + QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); + funcs->glCompressedTexImage2D(GL_TEXTURE_2D, 0, m_format, + m_size.width(), m_size.height(), 0, + (m_size.width() * m_size.height()) / 2, + nullptr); +} + +void Atlas::uploadPendingTexture(int i) +{ + Texture *texture = static_cast<Texture*>(m_pending_uploads.at(i)); + + const QRect &r = texture->atlasSubRect(); + + QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); + funcs->glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, + r.x(), r.y(), r.width(), r.height(), m_format, + texture->sizeInBytes(), + texture->data().constData() + texture->dataOffset()); + + qCDebug(QSG_LOG_TIME_TEXTURE).nospace() << "compressed atlastexture uploaded in: " << qsg_renderer_timer.elapsed() + << "ms (" << texture->textureSize().width() << "x" + << texture->textureSize().height() << ")"; + + // TODO: consider releasing the data (as is done in the regular atlas)? + // The advantage of keeping this data around is that it makes it much easier + // to remove the texture from the atlas +} + +Texture::Texture(Atlas *atlas, const QRect &textureRect, const QByteArray &data, int dataLength, int dataOffset, const QSize &size) + : QSGAtlasTexture::TextureBase(atlas, textureRect) + , m_nonatlas_texture(nullptr) + , m_data(data) + , m_size(size) + , m_dataLength(dataLength) + , m_dataOffset(dataOffset) +{ + float w = atlas->size().width(); + float h = atlas->size().height(); + QRect nopad = atlasSubRect(); + // offset by half-pixel to prevent bleeding when scaling + m_texture_coords_rect = QRectF((nopad.x() + .5) / w, + (nopad.y() + .5) / h, + (nopad.width() - 1.) / w, + (nopad.height() - 1.) / h); +} + +Texture::~Texture() +{ + delete m_nonatlas_texture; +} + +bool Texture::hasAlphaChannel() const +{ + return QSGCompressedTexture::formatIsOpaque(static_cast<Atlas*>(m_atlas)->format()); +} + +QSGTexture *Texture::removedFromAtlas() const +{ + if (m_nonatlas_texture) { + m_nonatlas_texture->setMipmapFiltering(mipmapFiltering()); + m_nonatlas_texture->setFiltering(filtering()); + return m_nonatlas_texture; + } + + if (!m_data.isEmpty()) { + QSGCompressedTexture::DataPtr texData(QSGCompressedTexture::DataPtr::create()); + texData->data = m_data; + texData->size = m_size; + texData->format = static_cast<Atlas*>(m_atlas)->format(); + texData->hasAlpha = hasAlphaChannel(); + texData->dataLength = m_dataLength; + texData->dataOffset = m_dataOffset; + m_nonatlas_texture = new QSGCompressedTexture(texData); + m_nonatlas_texture->setMipmapFiltering(mipmapFiltering()); + m_nonatlas_texture->setFiltering(filtering()); + } + + return m_nonatlas_texture; +} + +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture_p.h b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture_p.h new file mode 100644 index 0000000000..59e935b623 --- /dev/null +++ b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + +#ifndef QSGCOMPRESSEDATLASTEXTURE_P_H +#define QSGCOMPRESSEDATLASTEXTURE_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 <QtCore/QSize> + +#include <QtGui/qopengl.h> + +#include <QtQuick/QSGTexture> +#include <QtQuick/private/qsgareaallocator_p.h> +#include <QtQuick/private/qsgatlastexture_p.h> + +QT_BEGIN_NAMESPACE + +class QSGCompressedTextureFactory; + +namespace QSGCompressedAtlasTexture { + +class Texture; + +class Atlas : public QSGAtlasTexture::AtlasBase +{ +public: + Atlas(const QSize &size, uint format); + ~Atlas(); + + void generateTexture() override; + void uploadPendingTexture(int i) override; + + Texture *create(const QByteArray &data, int dataLength, int dataOffset, const QSize &size, const QSize &paddedSize); + + uint format() const { return m_format; } + +private: + uint m_format; +}; + +class Texture : public QSGAtlasTexture::TextureBase +{ + Q_OBJECT +public: + Texture(Atlas *atlas, const QRect &textureRect, const QByteArray &data, int dataLength, int dataOffset, const QSize &size); + ~Texture(); + + QSize textureSize() const override { return m_size; } + bool hasAlphaChannel() const override; + bool hasMipmaps() const override { return false; } + + QRectF normalizedTextureSubRect() const override { return m_texture_coords_rect; } + + QSGTexture *removedFromAtlas() const override; + + const QByteArray &data() const { return m_data; } + int sizeInBytes() const { return m_dataLength; } + int dataOffset() const { return m_dataOffset; } + +private: + QRectF m_texture_coords_rect; + mutable QSGTexture *m_nonatlas_texture; + QByteArray m_data; + QSize m_size; + int m_dataLength; + int m_dataOffset; +}; + +} + +QT_END_NAMESPACE + +#endif diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp new file mode 100644 index 0000000000..839c562989 --- /dev/null +++ b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + + +#include "qsgcompressedtexture_p.h" +#include <QOpenGLContext> +#include <QOpenGLTexture> +#include <QOpenGLFunctions> +#include <QDebug> +#include <QtQuick/private/qquickwindow_p.h> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(QSG_LOG_TEXTUREIO, "qt.scenegraph.textureio"); + +bool QSGCompressedTextureData::isValid() const +{ + if (data.isNull() || size.isEmpty() || !format) + return false; + if (dataLength < 0 || dataOffset < 0 || dataOffset >= data.length()) + return false; + if (dataLength > 0 && qint64(dataOffset) + qint64(dataLength) > qint64(data.length())) + return false; + + return true; +} + +int QSGCompressedTextureData::sizeInBytes() const +{ + if (!isValid()) + return 0; + return dataLength > 0 ? dataLength : data.length() - dataOffset; +} + +Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QSGCompressedTextureData *d) +{ + QDebugStateSaver saver(dbg); + + dbg.nospace() << "QSGCompressedTextureData("; + if (d) { + dbg << d->logName << ' '; + dbg << static_cast<QOpenGLTexture::TextureFormat>(d->format) + << "[0x" << hex << d->format << dec << "]"; + dbg.space() << (d->hasAlpha ? "with" : "no") << "alpha" << d->size + << "databuffer" << d->data.size() << "offset" << d->dataOffset << "length"; + dbg.nospace() << d->dataLength << ")"; + } else { + dbg << "null)"; + } + return dbg; +} + +QSGCompressedTexture::QSGCompressedTexture(const DataPtr& texData) + : m_textureData(texData) +{ + if (m_textureData) { + m_size = m_textureData->size; + m_hasAlpha = m_textureData->hasAlpha; + } +} + +QSGCompressedTexture::~QSGCompressedTexture() +{ +#if QT_CONFIG(opengl) + if (m_textureId) { + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLFunctions *funcs = ctx ? ctx->functions() : nullptr; + if (!funcs) + return; + + funcs->glDeleteTextures(1, &m_textureId); + } +#endif +} + +int QSGCompressedTexture::textureId() const +{ +#if QT_CONFIG(opengl) + if (!m_textureId) { + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLFunctions *funcs = ctx ? ctx->functions() : nullptr; + if (!funcs) + return 0; + + funcs->glGenTextures(1, &m_textureId); + } +#endif + return m_textureId; +} + +QSize QSGCompressedTexture::textureSize() const +{ + return m_size; +} + +bool QSGCompressedTexture::hasAlphaChannel() const +{ + return m_hasAlpha; +} + +bool QSGCompressedTexture::hasMipmaps() const +{ + return false; +} + +void QSGCompressedTexture::bind() +{ +#if QT_CONFIG(opengl) + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLFunctions *funcs = ctx ? ctx->functions() : nullptr; + if (!funcs) + return; + + if (!textureId()) + return; + + funcs->glBindTexture(GL_TEXTURE_2D, m_textureId); + + if (m_uploaded) + return; + + QByteArray logName(m_textureData ? m_textureData->logName : QByteArrayLiteral("(unset)")); + + if (!m_textureData || !m_textureData->isValid()) { + qCDebug(QSG_LOG_TEXTUREIO, "Invalid texture data for %s", logName.constData()); + funcs->glBindTexture(GL_TEXTURE_2D, 0); + return; + } + + if (Q_UNLIKELY(QSG_LOG_TEXTUREIO().isDebugEnabled())) { + qCDebug(QSG_LOG_TEXTUREIO) << "Uploading texture" << m_textureData.data(); + while (funcs->glGetError() != GL_NO_ERROR); + } + + funcs->glCompressedTexImage2D(GL_TEXTURE_2D, 0, m_textureData->format, + m_size.width(), m_size.height(), 0, m_textureData->sizeInBytes(), + m_textureData->data.constData() + m_textureData->dataOffset); + + if (Q_UNLIKELY(QSG_LOG_TEXTUREIO().isDebugEnabled())) { + GLuint error = funcs->glGetError(); + if (error != GL_NO_ERROR) { + qCDebug(QSG_LOG_TEXTUREIO, "glCompressedTexImage2D failed for %s, error 0x%x", logName.constData(), error); + } + } + + m_textureData.clear(); // Release this memory, not needed anymore + + updateBindOptions(true); + m_uploaded = true; +#endif // QT_CONFIG(opengl) +} + +bool QSGCompressedTexture::formatIsOpaque(quint32 glTextureFormat) +{ + switch (glTextureFormat) { + case QOpenGLTexture::RGB_DXT1: + case QOpenGLTexture::R_ATI1N_UNorm: + case QOpenGLTexture::R_ATI1N_SNorm: + case QOpenGLTexture::RG_ATI2N_UNorm: + case QOpenGLTexture::RG_ATI2N_SNorm: + case QOpenGLTexture::RGB_BP_UNSIGNED_FLOAT: + case QOpenGLTexture::RGB_BP_SIGNED_FLOAT: + case QOpenGLTexture::R11_EAC_UNorm: + case QOpenGLTexture::R11_EAC_SNorm: + case QOpenGLTexture::RG11_EAC_UNorm: + case QOpenGLTexture::RG11_EAC_SNorm: + case QOpenGLTexture::RGB8_ETC2: + case QOpenGLTexture::SRGB8_ETC2: + case QOpenGLTexture::RGB8_ETC1: + case QOpenGLTexture::SRGB_DXT1: + return true; + break; + default: + return false; + } +} + +QSGCompressedTextureFactory::QSGCompressedTextureFactory(const QSGCompressedTexture::DataPtr &texData) + : m_textureData(texData) +{ +} + +QSGTexture *QSGCompressedTextureFactory::createTexture(QQuickWindow *window) const +{ + if (!m_textureData || !m_textureData->isValid()) + return nullptr; + + // attempt to atlas the texture + QSGRenderContext *context = QQuickWindowPrivate::get(window)->context; + QSGTexture *t = context->compressedTextureForFactory(this); + if (t) + return t; + + return new QSGCompressedTexture(m_textureData); +} + +int QSGCompressedTextureFactory::textureByteCount() const +{ + return m_textureData ? m_textureData->sizeInBytes() : 0; +} + + +QSize QSGCompressedTextureFactory::textureSize() const +{ + if (m_textureData && m_textureData->isValid()) + return m_textureData->size; + return QSize(); +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture_p.h b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture_p.h new file mode 100644 index 0000000000..aa87316809 --- /dev/null +++ b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QSGCOMPRESSEDTEXTURE_P_H +#define QSGCOMPRESSEDTEXTURE_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 <QSGTexture> +#include <QtQuick/private/qsgcontext_p.h> +#include <QQuickTextureFactory> +#include <QOpenGLFunctions> + +QT_BEGIN_NAMESPACE + +struct Q_QUICK_PRIVATE_EXPORT QSGCompressedTextureData +{ + QByteArray logName; + QByteArray data; + QSize size; + uint format = 0; + int dataOffset = 0; + int dataLength = 0; + bool hasAlpha = false; + + bool isValid() const; + int sizeInBytes() const; +}; + +Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug, const QSGCompressedTextureData *); + + +class Q_QUICK_PRIVATE_EXPORT QSGCompressedTexture : public QSGTexture +{ + Q_OBJECT +public: + typedef QSharedPointer<QSGCompressedTextureData> DataPtr; + + QSGCompressedTexture(const DataPtr& texData); + virtual ~QSGCompressedTexture(); + + int textureId() const override; + QSize textureSize() const override; + bool hasAlphaChannel() const override; + bool hasMipmaps() const override; + + void bind() override; + + const QSGCompressedTextureData *textureData(); + + static bool formatIsOpaque(quint32 glTextureFormat); + +protected: + DataPtr m_textureData; + QSize m_size; + mutable uint m_textureId = 0; + bool m_hasAlpha = false; + bool m_uploaded = false; +}; + +namespace QSGAtlasTexture { + class Manager; +} + +class Q_QUICK_PRIVATE_EXPORT QSGCompressedTextureFactory : public QQuickTextureFactory +{ +public: + QSGCompressedTextureFactory(const QSGCompressedTexture::DataPtr& texData); + QSGTexture *createTexture(QQuickWindow *) const override; + int textureByteCount() const override; + QSize textureSize() const override; + +protected: + QSGCompressedTexture::DataPtr m_textureData; +private: + friend class QSGAtlasTexture::Manager; +}; + +QT_END_NAMESPACE + +#endif // QSGCOMPRESSEDTEXTURE_P_H diff --git a/src/quick/scenegraph/compressedtexture/qsgktxhandler.cpp b/src/quick/scenegraph/compressedtexture/qsgktxhandler.cpp new file mode 100644 index 0000000000..e3e4ca6824 --- /dev/null +++ b/src/quick/scenegraph/compressedtexture/qsgktxhandler.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#include "qsgktxhandler_p.h" +#include "qsgcompressedtexture_p.h" +#include <QOpenGLTexture> +#include <QtEndian> + +//#define KTX_DEBUG + +QT_BEGIN_NAMESPACE + +#define KTX_IDENTIFIER_LENGTH 12 +static const char ktxIdentifier[KTX_IDENTIFIER_LENGTH] = { '\xAB', 'K', 'T', 'X', ' ', '1', '1', '\xBB', '\r', '\n', '\x1A', '\n' }; +static const quint32 platformEndianIdentifier = 0x04030201; +static const quint32 inversePlatformEndianIdentifier = 0x01020304; + +struct KTXHeader { + quint8 identifier[KTX_IDENTIFIER_LENGTH]; //Must match ktxIdentifier + quint32 endianness; //Either platformEndianIdentifier or inversePlatformEndianIdentifier, other values not allowed. + quint32 glType; + quint32 glTypeSize; + quint32 glFormat; + quint32 glInternalFormat; + quint32 glBaseInternalFormat; + quint32 pixelWidth; + quint32 pixelHeight; + quint32 pixelDepth; + quint32 numberOfArrayElements; + quint32 numberOfFaces; + quint32 numberOfMipmapLevels; + quint32 bytesOfKeyValueData; +}; + +static const int headerSize = sizeof(KTXHeader); + +// Currently unused, declared for future reference +struct KTXKeyValuePairItem { + quint32 keyAndValueByteSize; + /* + quint8 keyAndValue[keyAndValueByteSize]; + quint8 valuePadding[3 - ((keyAndValueByteSize + 3) % 4)]; + */ +}; + +struct KTXMipmapLevel { + quint32 imageSize; + /* + for each array_element in numberOfArrayElements* + for each face in numberOfFaces + for each z_slice in pixelDepth* + for each row or row_of_blocks in pixelHeight* + for each pixel or block_of_pixels in pixelWidth + Byte data[format-specific-number-of-bytes]** + end + end + end + Byte cubePadding[0-3] + end + end + quint8 mipPadding[3 - ((imageSize + 3) % 4)] + */ +}; + +bool QSGKtxHandler::canRead(const QByteArray &suffix, const QByteArray &block) +{ + Q_UNUSED(suffix) + + return (qstrncmp(block.constData(), ktxIdentifier, KTX_IDENTIFIER_LENGTH) == 0); +} + +QQuickTextureFactory *QSGKtxHandler::read() +{ + if (!device()) + return nullptr; + + QByteArray buf = device()->readAll(); + if (buf.size() < headerSize || !canRead(QByteArray(), buf)) { + qCDebug(QSG_LOG_TEXTUREIO, "Invalid KTX file %s", logName().constData()); + return nullptr; + } + + const KTXHeader *header = reinterpret_cast<const KTXHeader *>(buf.constData()); + if (!checkHeader(*header)) { + qCDebug(QSG_LOG_TEXTUREIO, "Unsupported KTX file format in %s", logName().constData()); + return nullptr; + } + + QSGCompressedTexture::DataPtr texData(QSGCompressedTexture::DataPtr::create()); + + texData->size = QSize(decode(header->pixelWidth), decode(header->pixelHeight)); + texData->format = decode(header->glInternalFormat); + texData->hasAlpha = !QSGCompressedTexture::formatIsOpaque(texData->format); + + // For now, ignore any additional mipmap levels + int preambleSize = headerSize + decode(header->bytesOfKeyValueData); + if (buf.size() >= preambleSize + int(sizeof(KTXMipmapLevel))) { + texData->data = buf; + texData->dataOffset = preambleSize + sizeof(quint32); // for the imageSize + const KTXMipmapLevel *level = reinterpret_cast<const KTXMipmapLevel *>(buf.constData() + preambleSize); + texData->dataLength = decode(level->imageSize); + } + + if (!texData->isValid()) { + qCDebug(QSG_LOG_TEXTUREIO, "Invalid values in header of KTX file %s", logName().constData()); + return nullptr; + } + + texData->logName = logName(); +#ifdef KTX_DEBUG + qDebug() << "KTX file handler read" << texData.data(); +#endif + + return new QSGCompressedTextureFactory(texData); +} + +bool QSGKtxHandler::checkHeader(const KTXHeader &header) +{ + if (header.endianness != platformEndianIdentifier && header.endianness != inversePlatformEndianIdentifier) + return false; + inverseEndian = (header.endianness == inversePlatformEndianIdentifier); +#ifdef KTX_DEBUG + QMetaEnum tfme = QMetaEnum::fromType<QOpenGLTexture::TextureFormat>(); + QMetaEnum ptme = QMetaEnum::fromType<QOpenGLTexture::PixelType>(); + qDebug("Header of %s:", logName().constData()); + qDebug(" glType: 0x%x (%s)", decode(header.glType), ptme.valueToKey(decode(header.glType))); + qDebug(" glTypeSize: %u", decode(header.glTypeSize)); + qDebug(" glFormat: 0x%x (%s)", decode(header.glFormat), tfme.valueToKey(decode(header.glFormat))); + qDebug(" glInternalFormat: 0x%x (%s)", decode(header.glInternalFormat), tfme.valueToKey(decode(header.glInternalFormat))); + qDebug(" glBaseInternalFormat: 0x%x (%s)", decode(header.glBaseInternalFormat), tfme.valueToKey(decode(header.glBaseInternalFormat))); + qDebug(" pixelWidth: %u", decode(header.pixelWidth)); + qDebug(" pixelHeight: %u", decode(header.pixelHeight)); + qDebug(" pixelDepth: %u", decode(header.pixelDepth)); + qDebug(" numberOfArrayElements: %u", decode(header.numberOfArrayElements)); + qDebug(" numberOfFaces: %u", decode(header.numberOfFaces)); + qDebug(" numberOfMipmapLevels: %u", decode(header.numberOfMipmapLevels)); + qDebug(" bytesOfKeyValueData: %u", decode(header.bytesOfKeyValueData)); +#endif + return ((decode(header.glType) == 0) && + (decode(header.glFormat) == 0) && + (decode(header.pixelDepth) == 0) && + (decode(header.numberOfFaces) == 1)); +} + +quint32 QSGKtxHandler::decode(quint32 val) +{ + return inverseEndian ? qbswap<quint32>(val) : val; +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/compressedtexture/qsgktxhandler_p.h b/src/quick/scenegraph/compressedtexture/qsgktxhandler_p.h new file mode 100644 index 0000000000..22f4db65b2 --- /dev/null +++ b/src/quick/scenegraph/compressedtexture/qsgktxhandler_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QSGKTXHANDLER_H +#define QSGKTXHANDLER_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 "qsgtexturefilehandler_p.h" + +QT_BEGIN_NAMESPACE + +struct KTXHeader; + +class QSGKtxHandler : public QSGTextureFileHandler +{ +public: + using QSGTextureFileHandler::QSGTextureFileHandler; + + static bool canRead(const QByteArray &suffix, const QByteArray &block); + + QQuickTextureFactory *read() override; + +private: + bool checkHeader(const KTXHeader &header); + quint32 decode(quint32 val); + + bool inverseEndian = false; +}; + +QT_END_NAMESPACE + +#endif // QSGKTXHANDLER_H diff --git a/src/quick/scenegraph/compressedtexture/qsgpkmhandler.cpp b/src/quick/scenegraph/compressedtexture/qsgpkmhandler.cpp index bb8fce046d..618c0db045 100644 --- a/src/quick/scenegraph/compressedtexture/qsgpkmhandler.cpp +++ b/src/quick/scenegraph/compressedtexture/qsgpkmhandler.cpp @@ -38,172 +38,81 @@ ****************************************************************************/ #include "qsgpkmhandler_p.h" +#include "qsgcompressedtexture_p.h" #include <QFile> #include <QDebug> #include <qendian.h> #include <qopenglfunctions.h> #include <qqmlfile.h> +#include <QOpenGLTexture> //#define ETC_DEBUG -#ifndef GL_ETC1_RGB8_OES - #define GL_ETC1_RGB8_OES 0x8d64 -#endif - -#ifndef GL_COMPRESSED_RGB8_ETC2 - #define GL_COMPRESSED_RGB8_ETC2 0x9274 -#endif - -#ifndef GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 - #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 -#endif - -#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC - #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 -#endif - QT_BEGIN_NAMESPACE static const int headerSize = 16; static unsigned int typeMap[5] = { - GL_ETC1_RGB8_OES, - GL_COMPRESSED_RGB8_ETC2, - 0, // unused - GL_COMPRESSED_RGBA8_ETC2_EAC, - GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 + QOpenGLTexture::RGB8_ETC1, // GL_ETC1_RGB8_OES, + QOpenGLTexture::RGB8_ETC2, // GL_COMPRESSED_RGB8_ETC2, + 0, // unused (obsolete) + QOpenGLTexture::RGBA8_ETC2_EAC, // GL_COMPRESSED_RGBA8_ETC2_EAC, + QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2 // GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 }; -QEtcTexture::QEtcTexture() - : m_texture_id(0), m_uploaded(false) -{ - initializeOpenGLFunctions(); -} - -QEtcTexture::~QEtcTexture() -{ - if (m_texture_id) - glDeleteTextures(1, &m_texture_id); -} - -int QEtcTexture::textureId() const -{ - if (m_texture_id == 0) { - QEtcTexture *texture = const_cast<QEtcTexture*>(this); - texture->glGenTextures(1, &texture->m_texture_id); - } - return m_texture_id; -} - -bool QEtcTexture::hasAlphaChannel() const -{ - return m_type == GL_COMPRESSED_RGBA8_ETC2_EAC || - m_type == GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; -} - - -void QEtcTexture::bind() +bool QSGPkmHandler::canRead(const QByteArray &suffix, const QByteArray &block) { - if (m_uploaded && m_texture_id) { - glBindTexture(GL_TEXTURE_2D, m_texture_id); - return; - } - - if (m_texture_id == 0) - glGenTextures(1, &m_texture_id); - glBindTexture(GL_TEXTURE_2D, m_texture_id); - -#ifdef ETC_DEBUG - qDebug() << "glCompressedTexImage2D, width: " << m_size.width() << "height" << m_size.height() << - "paddedWidth: " << m_paddedSize.width() << "paddedHeight: " << m_paddedSize.height(); -#endif + Q_UNUSED(suffix) -#ifndef QT_NO_DEBUG - while (glGetError() != GL_NO_ERROR) { } -#endif - - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - Q_ASSERT(ctx != 0); - ctx->functions()->glCompressedTexImage2D(GL_TEXTURE_2D, 0, m_type, - m_size.width(), m_size.height(), 0, - (m_paddedSize.width() * m_paddedSize.height()) / 2, - m_data.data() + headerSize); - -#ifndef QT_NO_DEBUG - // Gracefully fail in case of an error... - GLuint error = glGetError(); - if (error != GL_NO_ERROR) { - qDebug () << "glCompressedTexImage2D for compressed texture failed, error: " << error; - glBindTexture(GL_TEXTURE_2D, 0); - glDeleteTextures(1, &m_texture_id); - m_texture_id = 0; - return; - } -#endif - - m_uploaded = true; - updateBindOptions(true); + return block.startsWith("PKM "); } -class QEtcTextureFactory : public QQuickTextureFactory -{ -public: - QByteArray m_data; - QSize m_size; - QSize m_paddedSize; - unsigned int m_type; - - QSize textureSize() const { return m_size; } - int textureByteCount() const { return m_data.size(); } - - QSGTexture *createTexture(QQuickWindow *) const { - QEtcTexture *texture = new QEtcTexture; - texture->m_data = m_data; - texture->m_size = m_size; - texture->m_paddedSize = m_paddedSize; - texture->m_type = m_type; - return texture; - } -}; - -QQuickTextureFactory *QSGPkmHandler::read(QIODevice *device) +QQuickTextureFactory *QSGPkmHandler::read() { - QScopedPointer<QEtcTextureFactory> ret(new QEtcTextureFactory); - ret->m_data = device->readAll(); - if (ret->m_data.isEmpty() || ret->m_data.size() < headerSize) + if (!device()) return nullptr; - const char *rawData = ret->m_data.constData(); + QSGCompressedTexture::DataPtr texData(QSGCompressedTexture::DataPtr::create()); - // magic number - if (qstrncmp(rawData, "PKM ", 4) != 0) + texData->data = device()->readAll(); + if (texData->data.size() < headerSize || !canRead(QByteArray(), texData->data)) { + qCDebug(QSG_LOG_TEXTUREIO, "Invalid PKM file %s", logName().constData()); return nullptr; + } + + const char *rawData = texData->data.constData(); - // currently ignore version (rawData + 4) + // ignore version (rawData + 4 & 5) // texture type quint16 type = qFromBigEndian<quint16>(rawData + 6); - static int typeCount = sizeof(typeMap)/sizeof(typeMap[0]); - if (type >= typeCount) + if (type > sizeof(typeMap)/sizeof(typeMap[0])) { + qCDebug(QSG_LOG_TEXTUREIO, "Unknown compression format in PKM file %s", logName().constData()); return nullptr; - ret->m_type = typeMap[type]; + } + texData->format = typeMap[type]; + texData->hasAlpha = !QSGCompressedTexture::formatIsOpaque(texData->format); // texture size - ret->m_paddedSize.setWidth(qFromBigEndian<quint16>(rawData + 8)); - ret->m_paddedSize.setHeight(qFromBigEndian<quint16>(rawData + 10)); - if ((ret->m_paddedSize.width() * ret->m_paddedSize.height()) / 2 > ret->m_data.size() - headerSize) - return nullptr; - ret->m_size.setWidth(qFromBigEndian<quint16>(rawData + 12)); - ret->m_size.setHeight(qFromBigEndian<quint16>(rawData + 14)); - if (ret->m_size.isEmpty()) + const int bpb = (texData->format == QOpenGLTexture::RGBA8_ETC2_EAC) ? 16 : 8; + QSize paddedSize(qFromBigEndian<quint16>(rawData + 8), qFromBigEndian<quint16>(rawData + 10)); + texData->dataLength = (paddedSize.width() / 4) * (paddedSize.height() / 4) * bpb; + QSize texSize(qFromBigEndian<quint16>(rawData + 12), qFromBigEndian<quint16>(rawData + 14)); + texData->size = texSize; + + texData->dataOffset = headerSize; + + if (!texData->isValid()) { + qCDebug(QSG_LOG_TEXTUREIO, "Invalid values in header of PKM file %s", logName().constData()); return nullptr; + } + texData->logName = logName(); #ifdef ETC_DEBUG - qDebug() << "requestTexture returning: " << ret->m_data.length() << "bytes; width: " << ret->m_size.width() << ", height: " << ret->m_size.height(); + qDebug() << "PKM file handler read" << texData.data(); #endif - - return ret.take(); + return new QSGCompressedTextureFactory(texData); } QT_END_NAMESPACE diff --git a/src/quick/scenegraph/compressedtexture/qsgpkmhandler_p.h b/src/quick/scenegraph/compressedtexture/qsgpkmhandler_p.h index eb6b2e46c0..6154c51b84 100644 --- a/src/quick/scenegraph/compressedtexture/qsgpkmhandler_p.h +++ b/src/quick/scenegraph/compressedtexture/qsgpkmhandler_p.h @@ -51,42 +51,18 @@ // We mean it. // -#include <QOpenGLFunctions> -#include <QQuickImageProvider> -#include <QtQuick/QSGTexture> -#include <QUrl> +#include "qsgtexturefilehandler_p.h" QT_BEGIN_NAMESPACE -class QSGPkmHandler +class QSGPkmHandler : public QSGTextureFileHandler { public: - QSGPkmHandler() {} + using QSGTextureFileHandler::QSGTextureFileHandler; - QQuickTextureFactory *read(QIODevice *device); -}; - -class QEtcTexture : public QSGTexture, protected QOpenGLFunctions -{ - Q_OBJECT -public: - QEtcTexture(); - ~QEtcTexture(); - - void bind(); - - QSize textureSize() const { return m_size; } - int textureId() const; - - bool hasAlphaChannel() const; - bool hasMipmaps() const { return false; } + static bool canRead(const QByteArray &suffix, const QByteArray &block); - QByteArray m_data; - QSize m_size; - QSize m_paddedSize; - GLuint m_texture_id; - GLenum m_type; - bool m_uploaded; + QQuickTextureFactory *read() override; }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/compressedtexture/qsgtexturefilehandler_p.h b/src/quick/scenegraph/compressedtexture/qsgtexturefilehandler_p.h new file mode 100644 index 0000000000..8b831aebb9 --- /dev/null +++ b/src/quick/scenegraph/compressedtexture/qsgtexturefilehandler_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QSGTEXTUREFILEHANDLER_P_H +#define QSGTEXTUREFILEHANDLER_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 <QLoggingCategory> + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TEXTUREIO) + +class QQuickTextureFactory; + +class QSGTextureFileHandler +{ +public: + QSGTextureFileHandler(QIODevice *device, const QByteArray &logName = QByteArray()) + : m_device(device) + { + m_logName = !logName.isEmpty() ? logName : QByteArrayLiteral("(unknown)"); + } + virtual ~QSGTextureFileHandler() {} + + virtual QQuickTextureFactory *read() = 0; + QIODevice *device() const { return m_device; } + QByteArray logName() const { return m_logName; } + +private: + QIODevice *m_device = nullptr; + QByteArray m_logName; +}; + +QT_END_NAMESPACE + +#endif // QSGTEXTUREFILEHANDLER_P_H diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp b/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp index 3d4ce24716..fddac7ed71 100644 --- a/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp @@ -97,7 +97,7 @@ QT_BEGIN_NAMESPACE \internal */ QSGAbstractRendererPrivate::QSGAbstractRendererPrivate() - : m_root_node(0) + : m_root_node(nullptr) , m_clear_color(Qt::transparent) , m_clear_mode(QSGAbstractRenderer::ClearColorBuffer | QSGAbstractRenderer::ClearDepthBuffer) { diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h index 304dc008d5..ab6fb4f317 100644 --- a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h +++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h @@ -62,7 +62,7 @@ public: }; Q_DECLARE_FLAGS(ClearMode, ClearModeBit) - virtual ~QSGAbstractRenderer(); + ~QSGAbstractRenderer() override; void setRootNode(QSGRootNode *node); QSGRootNode *rootNode() const; diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 0da35fba42..ba71551302 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -144,7 +144,7 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material) Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphContextFrame); QSGMaterialShader *s = material->createShader(); - QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLContext *ctx = context->openglContext(); QSurfaceFormat::OpenGLContextProfile profile = ctx->format().profile(); QOpenGLShaderProgram *p = s->program(); @@ -155,10 +155,10 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material) p->bindAttributeLocation(attr[i], i); } p->bindAttributeLocation("_qt_order", i); - context->compileShader(s, material, qsgShaderRewriter_insertZAttributes(s->vertexShader(), profile), 0); + context->compileShader(s, material, qsgShaderRewriter_insertZAttributes(s->vertexShader(), profile), nullptr); context->initializeShader(s); if (!p->isLinked()) - return 0; + return nullptr; shader = new Shader; shader->program = s; @@ -215,7 +215,7 @@ void ShaderManager::invalidated() qDeleteAll(rewrittenShaders); rewrittenShaders.clear(); delete blitProgram; - blitProgram = 0; + blitProgram = nullptr; } void qsg_dumpShadowRoots(BatchRootInfo *i, int indent) @@ -226,7 +226,7 @@ void qsg_dumpShadowRoots(BatchRootInfo *i, int indent) QByteArray ind(indent + extraIndent + 10, ' '); if (!i) { - qDebug() << ind.constData() << "- no info"; + qDebug("%s - no info", ind.constData()); } else { qDebug() << ind.constData() << "- parent:" << i->parentRoot << "orders" << i->firstOrder << "->" << i->lastOrder << ", avail:" << i->availableOrders; for (QSet<Node *>::const_iterator it = i->subRoots.constBegin(); @@ -280,7 +280,7 @@ Updater::Updater(Renderer *r) void Updater::updateStates(QSGNode *n) { - m_current_clip = 0; + m_current_clip = nullptr; m_added = 0; m_transformChange = 0; @@ -293,15 +293,15 @@ void Updater::updateStates(QSGNode *n) qsg_dumpShadowRoots(sn); if (Q_UNLIKELY(debug_build())) { - qDebug() << "Updater::updateStates()"; + qDebug("Updater::updateStates()"); if (sn->dirtyState & (QSGNode::DirtyNodeAdded << 16)) - qDebug() << " - nodes have been added"; + qDebug(" - nodes have been added"); if (sn->dirtyState & (QSGNode::DirtyMatrix << 16)) - qDebug() << " - transforms have changed"; + qDebug(" - transforms have changed"); if (sn->dirtyState & (QSGNode::DirtyOpacity << 16)) - qDebug() << " - opacity has changed"; + qDebug(" - opacity has changed"); if (uint(sn->dirtyState) & uint(QSGNode::DirtyForceUpdate << 16)) - qDebug() << " - forceupdate"; + qDebug(" - forceupdate"); } if (Q_UNLIKELY(renderer->m_visualizeMode == Renderer::VisualizeChanges)) @@ -347,7 +347,7 @@ void Updater::visitNode(Node *n) m_added = count; m_force_update = force; - n->dirtyState = 0; + n->dirtyState = nullptr; } void Updater::visitClipNode(Node *n) @@ -473,7 +473,7 @@ void Updater::visitGeometryNode(Node *n) if (e->root) { BatchRootInfo *info = renderer->batchRootInfo(e->root); - while (info != 0) { + while (info != nullptr) { info->availableOrders--; if (info->availableOrders < 0) { renderer->m_rebuild |= Renderer::BuildRenderLists; @@ -481,10 +481,10 @@ void Updater::visitGeometryNode(Node *n) renderer->m_rebuild |= Renderer::BuildRenderListsForTaggedRoots; renderer->m_taggedRoots << e->root; } - if (info->parentRoot != 0) + if (info->parentRoot != nullptr) info = renderer->batchRootInfo(info->parentRoot); else - info = 0; + info = nullptr; } } else { renderer->m_rebuild |= Renderer::FullRebuild; @@ -680,12 +680,12 @@ void Batch::invalidate() // the batch to do an early out.. cleanupRemovedElements(); Element *e = first; - first = 0; - root = 0; + first = nullptr; + root = nullptr; while (e) { - e->batch = 0; + e->batch = nullptr; Element *n = e->nextInBatch; - e->nextInBatch = 0; + e->nextInBatch = nullptr; e = n; } } @@ -756,7 +756,7 @@ Renderer::Renderer(QSGDefaultRenderContext *ctx) , m_alphaRenderList(64) , m_nextRenderOrder(0) , m_partialRebuild(false) - , m_partialRebuildRoot(0) + , m_partialRebuildRoot(nullptr) , m_useDepthBuffer(true) , m_opaqueBatches(16) , m_alphaBatches(16) @@ -768,17 +768,17 @@ Renderer::Renderer(QSGDefaultRenderContext *ctx) , m_zRange(0) , m_renderOrderRebuildLower(-1) , m_renderOrderRebuildUpper(-1) - , m_currentMaterial(0) - , m_currentShader(0) + , m_currentMaterial(nullptr) + , m_currentShader(nullptr) , m_currentStencilValue(0) , m_clipMatrixId(0) - , m_currentClip(0) + , m_currentClip(nullptr) , m_currentClipType(NoClip) , m_vertexUploadPool(256) #ifdef QSG_SEPARATE_INDEX_BUFFER , m_indexUploadPool(64) #endif - , m_vao(0) + , m_vao(nullptr) , m_visualizeMode(VisualizeNothing) { initializeOpenGLFunctions(); @@ -805,8 +805,11 @@ Renderer::Renderer(QSGDefaultRenderContext *ctx) m_batchVertexThreshold = qt_sg_envInt("QSG_RENDERER_BATCH_VERTEX_THRESHOLD", 1024); if (Q_UNLIKELY(debug_build() || debug_render())) { - qDebug() << "Batch thresholds: nodes:" << m_batchNodeThreshold << " vertices:" << m_batchVertexThreshold; - qDebug() << "Using buffer strategy:" << (m_bufferStrategy == GL_STATIC_DRAW ? "static" : (m_bufferStrategy == GL_DYNAMIC_DRAW ? "dynamic" : "stream")); + qDebug("Batch thresholds: nodes: %d vertices: %d", + m_batchNodeThreshold, m_batchVertexThreshold); + qDebug("Using buffer strategy: %s", + (m_bufferStrategy == GL_STATIC_DRAW + ? "static" : (m_bufferStrategy == GL_DYNAMIC_DRAW ? "dynamic" : "stream"))); } // If rendering with an OpenGL Core profile context, we need to create a VAO @@ -913,7 +916,7 @@ void Renderer::unmap(Buffer *buffer, bool isIndexBuf) glBufferData(target, buffer->size, buffer->data, m_bufferStrategy); if (!m_context->hasBrokenIndexBufferObjects() && m_visualizeMode == VisualizeNothing) { - buffer->data = 0; + buffer->data = nullptr; } } @@ -941,7 +944,7 @@ void Renderer::removeBatchRootFromParent(Node *childRoot) Q_ASSERT(parentInfo->subRoots.contains(childRoot)); parentInfo->subRoots.remove(childRoot); - childInfo->parentRoot = 0; + childInfo->parentRoot = nullptr; } void Renderer::registerBatchRoot(Node *subRoot, Node *parentRoot) @@ -1069,7 +1072,7 @@ void Renderer::nodeWasRemoved(Node *node) if (e) { e->removed = true; m_elementsToDelete.add(e); - e->node = 0; + e->node = nullptr; if (e->root) { BatchRootInfo *info = batchRootInfo(e->root); info->availableOrders++; @@ -1112,7 +1115,7 @@ void Renderer::nodeWasRemoved(Node *node) void Renderer::turnNodeIntoBatchRoot(Node *node) { - if (Q_UNLIKELY(debug_change())) qDebug() << " - new batch root"; + if (Q_UNLIKELY(debug_change())) qDebug(" - new batch root"); m_rebuild |= FullRebuild; node->isBatchRoot = true; node->becameBatchRoot = true; @@ -1182,7 +1185,7 @@ void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state) return; } if (node == rootNode()) - nodeWasAdded(node, 0); + nodeWasAdded(node, nullptr); else nodeWasAdded(node, m_nodes.value(node->parent())); } @@ -1435,7 +1438,7 @@ void Renderer::buildRenderListsForTaggedRoots() } } m_partialRebuild = false; - m_partialRebuildRoot = 0; + m_partialRebuildRoot = nullptr; m_taggedRoots.clear(); m_nextRenderOrder = qMax(m_nextRenderOrder, maxRenderOrder); @@ -2032,7 +2035,7 @@ Renderer::ClipType Renderer::updateStencilClip(const QSGClipNode *clip) int vboSize = 0; bool useVBO = false; - QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLContext *ctx = m_context->openglContext(); QSurfaceFormat::OpenGLContextProfile profile = ctx->format().profile(); if (!ctx->isOpenGLES() && profile == QSurfaceFormat::CoreProfile) { @@ -2141,7 +2144,7 @@ Renderer::ClipType Renderer::updateStencilClip(const QSGClipNode *clip) glBufferSubData(GL_ARRAY_BUFFER, 0, vertexByteSize, g->vertexData()); } - pointer = 0; + pointer = nullptr; } glVertexAttribPointer(0, a->tupleSize, a->type, GL_FALSE, g->sizeOfVertex(), pointer); @@ -2183,7 +2186,7 @@ void Renderer::updateClip(const QSGClipNode *clipList, const Batch *batch) m_currentClip = clipList; // updateClip sets another program, so force-reactivate our own if (m_currentShader) - setActiveShader(0, 0); + setActiveShader(nullptr, nullptr); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); if (batch->isOpaque) @@ -2204,8 +2207,8 @@ void Renderer::updateClip(const QSGClipNode *clipList, const Batch *batch) */ void Renderer::setActiveShader(QSGMaterialShader *program, ShaderManager::Shader *shader) { - const char * const *c = m_currentProgram ? m_currentProgram->attributeNames() : 0; - const char * const *n = program ? program->attributeNames() : 0; + const char * const *c = m_currentProgram ? m_currentProgram->attributeNames() : nullptr; + const char * const *n = program ? program->attributeNames() : nullptr; int cza = m_currentShader ? m_currentShader->pos_order : -1; int nza = shader ? shader->pos_order : -1; @@ -2216,18 +2219,18 @@ void Renderer::setActiveShader(QSGMaterialShader *program, ShaderManager::Shader bool was = c; if (cza == i) { was = true; - c = 0; + c = nullptr; } else if (c && !c[i]) { // end of the attribute array names - c = 0; + c = nullptr; was = false; } bool is = n; if (nza == i) { is = true; - n = 0; + n = nullptr; } else if (n && !n[i]) { - n = 0; + n = nullptr; is = false; } @@ -2243,7 +2246,7 @@ void Renderer::setActiveShader(QSGMaterialShader *program, ShaderManager::Shader m_currentProgram->deactivate(); m_currentProgram = program; m_currentShader = shader; - m_currentMaterial = 0; + m_currentMaterial = nullptr; if (m_currentProgram) { m_currentProgram->program()->bind(); m_currentProgram->activate(); @@ -2295,7 +2298,7 @@ void Renderer::renderMergedBatch(const Batch *batch) glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id); - char *indexBase = 0; + char *indexBase = nullptr; #ifdef QSG_SEPARATE_INDEX_BUFFER const Buffer *indexBuf = &batch->ibo; #else @@ -2319,7 +2322,7 @@ void Renderer::renderMergedBatch(const Batch *batch) setActiveShader(program, sms); m_current_opacity = gn->inheritedOpacity(); - if (sms->lastOpacity != m_current_opacity) { + if (!qFuzzyCompare(sms->lastOpacity, float(m_current_opacity))) { dirty |= QSGMaterialShader::RenderState::DirtyOpacity; sms->lastOpacity = m_current_opacity; } @@ -2328,7 +2331,7 @@ void Renderer::renderMergedBatch(const Batch *batch) #ifndef QT_NO_DEBUG if (qsg_test_and_clear_material_failure()) { - qDebug() << "QSGMaterial::updateState triggered an error (merged), batch will be skipped:"; + qDebug("QSGMaterial::updateState triggered an error (merged), batch will be skipped:"); Element *ee = e; while (ee) { qDebug() << " -" << ee->node; @@ -2391,7 +2394,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch) updateClip(gn->clipList(), batch); glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id); - char *indexBase = 0; + char *indexBase = nullptr; #ifdef QSG_SEPARATE_INDEX_BUFFER const Buffer *indexBuf = &batch->ibo; #else @@ -2449,7 +2452,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch) #ifndef QT_NO_DEBUG if (qsg_test_and_clear_material_failure()) { - qDebug() << "QSGMaterial::updateState() triggered an error (unmerged), batch will be skipped:"; + qDebug("QSGMaterial::updateState() triggered an error (unmerged), batch will be skipped:"); qDebug() << " - offending node is" << e->node; QSGNodeDumper::dump(rootNode()); qFatal("Aborting: scene graph is invalid..."); @@ -2494,18 +2497,21 @@ void Renderer::updateLineWidth(QSGGeometry *g) if (g->drawingMode() == GL_LINE_STRIP || g->drawingMode() == GL_LINE_LOOP || g->drawingMode() == GL_LINES) glLineWidth(g->lineWidth()); #if !defined(QT_OPENGL_ES_2) - else if (!QOpenGLContext::currentContext()->isOpenGLES() && g->drawingMode() == GL_POINTS) { - QOpenGLFunctions_1_0 *gl1funcs = 0; - QOpenGLFunctions_3_2_Core *gl3funcs = 0; - if (QOpenGLContext::currentContext()->format().profile() == QSurfaceFormat::CoreProfile) - gl3funcs = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>(); - else - gl1funcs = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_1_0>(); - Q_ASSERT(gl1funcs || gl3funcs); - if (gl1funcs) - gl1funcs->glPointSize(g->lineWidth()); - else - gl3funcs->glPointSize(g->lineWidth()); + else { + QOpenGLContext *ctx = m_context->openglContext(); + if (!ctx->isOpenGLES() && g->drawingMode() == GL_POINTS) { + QOpenGLFunctions_1_0 *gl1funcs = nullptr; + QOpenGLFunctions_3_2_Core *gl3funcs = nullptr; + if (ctx->format().profile() == QSurfaceFormat::CoreProfile) + gl3funcs = ctx->versionFunctions<QOpenGLFunctions_3_2_Core>(); + else + gl1funcs = ctx->versionFunctions<QOpenGLFunctions_1_0>(); + Q_ASSERT(gl1funcs || gl3funcs); + if (gl1funcs) + gl1funcs->glPointSize(g->lineWidth()); + else + gl3funcs->glPointSize(g->lineWidth()); + } } #endif } @@ -2540,10 +2546,10 @@ void Renderer::renderBatches() bindable()->clear(clearMode()); m_current_opacity = 1; - m_currentMaterial = 0; - m_currentShader = 0; - m_currentProgram = 0; - m_currentClip = 0; + m_currentMaterial = nullptr; + m_currentShader = nullptr; + m_currentProgram = nullptr; + m_currentClip = nullptr; bool renderOpaque = !debug_noopaque(); bool renderAlpha = !debug_noalpha(); @@ -2576,8 +2582,8 @@ void Renderer::renderBatches() } if (m_currentShader) - setActiveShader(0, 0); - updateStencilClip(0); + setActiveShader(nullptr, nullptr); + updateStencilClip(nullptr); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glDepthMask(true); @@ -2591,12 +2597,12 @@ void Renderer::deleteRemovedElements() for (int i=0; i<m_opaqueRenderList.size(); ++i) { Element **e = m_opaqueRenderList.data() + i; if (*e && (*e)->removed) - *e = 0; + *e = nullptr; } for (int i=0; i<m_alphaRenderList.size(); ++i) { Element **e = m_alphaRenderList.data() + i; if (*e && (*e)->removed) - *e = 0; + *e = nullptr; } for (int i=0; i<m_elementsToDelete.size(); ++i) { @@ -2611,6 +2617,8 @@ void Renderer::deleteRemovedElements() void Renderer::render() { + Q_ASSERT(m_context->openglContext() == QOpenGLContext::currentContext()); + if (Q_UNLIKELY(debug_dump())) { qDebug("\n"); QSGNodeDumper::dump(rootNode()); @@ -2655,12 +2663,12 @@ void Renderer::render() m_rebuild |= BuildBatches; if (Q_UNLIKELY(debug_build())) { - qDebug() << "Opaque render lists" << (complete ? "(complete)" : "(partial)") << ":"; + qDebug("Opaque render lists %s:", (complete ? "(complete)" : "(partial)")); for (int i=0; i<m_opaqueRenderList.size(); ++i) { Element *e = m_opaqueRenderList.at(i); qDebug() << " - element:" << e << " batch:" << e->batch << " node:" << e->node << " order:" << e->order; } - qDebug() << "Alpha render list:" << (complete ? "(complete)" : "(partial)") << ":"; + qDebug("Alpha render list %s:", complete ? "(complete)" : "(partial)"); for (int i=0; i<m_alphaRenderList.size(); ++i) { Element *e = m_alphaRenderList.at(i); qDebug() << " - element:" << e << " batch:" << e->batch << " node:" << e->node << " order:" << e->order; @@ -2685,7 +2693,7 @@ void Renderer::render() if (Q_UNLIKELY(debug_render())) timePrepareAlpha = timer.restart(); if (Q_UNLIKELY(debug_build())) { - qDebug() << "Opaque Batches:"; + qDebug("Opaque Batches:"); for (int i=0; i<m_opaqueBatches.size(); ++i) { Batch *b = m_opaqueBatches.at(i); qDebug() << " - Batch " << i << b << (b->needsUpload ? "upload" : "") << " root:" << b->root; @@ -2693,7 +2701,7 @@ void Renderer::render() qDebug() << " - element:" << e << " node:" << e->node << e->order; } } - qDebug() << "Alpha Batches:"; + qDebug("Alpha Batches:"); for (int i=0; i<m_alphaBatches.size(); ++i) { Batch *b = m_alphaBatches.at(i); qDebug() << " - Batch " << i << b << (b->needsUpload ? "upload" : "") << " root:" << b->root; @@ -2731,7 +2739,7 @@ void Renderer::render() int largestIBO = 0; #endif - if (Q_UNLIKELY(debug_upload())) qDebug() << "Uploading Opaque Batches:"; + if (Q_UNLIKELY(debug_upload())) qDebug("Uploading Opaque Batches:"); for (int i=0; i<m_opaqueBatches.size(); ++i) { Batch *b = m_opaqueBatches.at(i); largestVBO = qMax(b->vbo.size, largestVBO); @@ -2743,7 +2751,7 @@ void Renderer::render() if (Q_UNLIKELY(debug_render())) timeUploadOpaque = timer.restart(); - if (Q_UNLIKELY(debug_upload())) qDebug() << "Uploading Alpha Batches:"; + if (Q_UNLIKELY(debug_upload())) qDebug("Uploading Alpha Batches:"); for (int i=0; i<m_alphaBatches.size(); ++i) { Batch *b = m_alphaBatches.at(i); uploadBatch(b); @@ -2807,11 +2815,11 @@ void Renderer::renderRenderNode(Batch *batch) Q_ASSERT(batch->first->isRenderNode); RenderNodeElement *e = (RenderNodeElement *) batch->first; - setActiveShader(0, 0); + setActiveShader(nullptr, nullptr); QSGNode *clip = e->renderNode->parent(); QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(e->renderNode); - rd->m_clip_list = 0; + rd->m_clip_list = nullptr; while (clip != rootNode()) { if (clip->type() == QSGNode::ClipNodeType) { rd->m_clip_list = static_cast<QSGClipNode *>(clip); @@ -2875,8 +2883,8 @@ void Renderer::renderRenderNode(Batch *batch) e->renderNode->render(&state); - rd->m_matrix = 0; - rd->m_clip_list = 0; + rd->m_matrix = nullptr; + rd->m_clip_list = nullptr; if (changes & QSGRenderNode::ViewportState) { QRect r = viewportRect(); @@ -2891,7 +2899,7 @@ void Renderer::renderRenderNode(Batch *batch) if (changes & (QSGRenderNode::StencilState | QSGRenderNode::ScissorState)) { glDisable(GL_SCISSOR_TEST); - m_currentClip = 0; + m_currentClip = nullptr; m_currentClipType = NoClip; } @@ -3061,7 +3069,7 @@ void Renderer::visualizeChanges(Node *n) // This is because many changes don't propegate their dirty state to the // parent so the node updater will not unset these states. They are // not used for anything so, unsetting it should have no side effects. - n->dirtyState = 0; + n->dirtyState = nullptr; } SHADOWNODE_TRAVERSE(n) { @@ -3153,7 +3161,7 @@ void Renderer::visualizeOverdraw() visualizeOverdraw_helper(m_nodes.value(rootNode())); // Animate the view... - QSurface *surface = QOpenGLContext::currentContext()->surface(); + QSurface *surface = m_context->openglContext()->surface(); if (surface->surfaceClass() == QSurface::Window) if (QQuickWindow *window = qobject_cast<QQuickWindow *>(static_cast<QWindow *>(surface))) window->update(); diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 5c39242029..918f3ce82c 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -125,7 +125,6 @@ template <typename Type, int PageSize> class Allocator { public: Allocator() - : m_freePage(0) { pages.push_back(new AllocatorPage<Type, PageSize>()); } @@ -209,7 +208,7 @@ public: } QVector<AllocatorPage<Type, PageSize> *> pages; - int m_freePage; + int m_freePage = 0; }; @@ -306,12 +305,7 @@ struct Buffer { struct Element { Element() - : node(0) - , batch(0) - , nextInBatch(0) - , root(0) - , order(0) - , boundsComputed(false) + : boundsComputed(false) , boundsOutsideFloatRange(false) , translateOnlyToRoot(false) , removed(false) @@ -332,14 +326,14 @@ struct Element { } void computeBounds(); - QSGGeometryNode *node; - Batch *batch; - Element *nextInBatch; - Node *root; + QSGGeometryNode *node = nullptr; + Batch *batch = nullptr; + Element *nextInBatch = nullptr; + Node *root = nullptr; Rect bounds; // in device coordinates - int order; + int order = 0; uint boundsComputed : 1; uint boundsOutsideFloatRange : 1; @@ -362,12 +356,12 @@ struct RenderNodeElement : public Element { }; struct BatchRootInfo { - BatchRootInfo() : parentRoot(0), lastOrder(-1), firstOrder(-1), availableOrders(0) { } + BatchRootInfo() {} QSet<Node *> subRoots; - Node *parentRoot; - int lastOrder; - int firstOrder; - int availableOrders; + Node *parentRoot = nullptr; + int lastOrder = -1; + int firstOrder = -1; + int availableOrders = 0; }; struct ClipBatchRootInfo : public BatchRootInfo @@ -381,14 +375,13 @@ struct DrawSet : vertices(v) , zorders(z) , indices(i) - , indexCount(0) { } - DrawSet() : vertices(0), zorders(0), indices(0), indexCount(0) {} - int vertices; - int zorders; - int indices; - int indexCount; + DrawSet() {} + int vertices = 0; + int zorders = 0; + int indices = 0; + int indexCount = 0; }; enum BatchCompatibility @@ -410,8 +403,8 @@ struct Batch // pseudo-constructor... void init() { - first = 0; - root = 0; + first = nullptr; + root = nullptr; vertexCount = 0; indexCount = 0; isOpaque = false; @@ -440,7 +433,9 @@ struct Batch mutable uint uploadedThisFrame : 1; // solely for debugging purposes Buffer vbo; +#ifdef QSG_SEPARATE_INDEX_BUFFER Buffer ibo; +#endif QDataBuffer<DrawSet> drawSets; }; @@ -461,9 +456,9 @@ struct Node void append(Node *child) { Q_ASSERT(child); Q_ASSERT(!hasChild(child)); - Q_ASSERT(child->m_parent == 0); - Q_ASSERT(child->m_next == 0); - Q_ASSERT(child->m_prev == 0); + Q_ASSERT(child->m_parent == nullptr); + Q_ASSERT(child->m_next == nullptr); + Q_ASSERT(child->m_prev == nullptr); if (!m_child) { child->m_next = child; @@ -484,27 +479,27 @@ struct Node // only child.. if (child->m_next == child) { - m_child = 0; + m_child = nullptr; } else { if (m_child == child) m_child = child->m_next; child->m_next->m_prev = child->m_prev; child->m_prev->m_next = child->m_next; } - child->m_next = 0; - child->m_prev = 0; - child->setParent(0); + child->m_next = nullptr; + child->m_prev = nullptr; + child->setParent(nullptr); } Node *firstChild() const { return m_child; } Node *sibling() const { Q_ASSERT(m_parent); - return m_next == m_parent->m_child ? 0 : m_next; + return m_next == m_parent->m_child ? nullptr : m_next; } void setParent(Node *p) { - Q_ASSERT(m_parent == 0 || p == 0); + Q_ASSERT(m_parent == nullptr || p == nullptr); m_parent = p; } @@ -589,7 +584,7 @@ public: float lastOpacity; }; - ShaderManager(QSGDefaultRenderContext *ctx) : visualizeProgram(0), blitProgram(0), context(ctx) { } + ShaderManager(QSGDefaultRenderContext *ctx) : visualizeProgram(nullptr), blitProgram(nullptr), context(ctx) { } ~ShaderManager() { qDeleteAll(rewrittenShaders); qDeleteAll(stockShaders); @@ -743,7 +738,9 @@ private: ClipType m_currentClipType; QDataBuffer<char> m_vertexUploadPool; +#ifdef QSG_SEPARATE_INDEX_BUFFER QDataBuffer<char> m_indexUploadPool; +#endif // For minimal OpenGL core profile support QOpenGLVertexArrayObject *m_vao; @@ -763,7 +760,10 @@ Batch *Renderer::newBatch() m_batchPool.resize(size - 1); } else { b = new Batch(); - memset(&b->vbo, 0, sizeof(Buffer) * 2); // Clear VBO & IBO + memset(&b->vbo, 0, sizeof(Buffer)); +#ifdef QSG_SEPARATE_INDEX_BUFFER + memset(&b->ibo, 0, sizeof(Buffer)); +#endif } b->init(); return b; diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp index 69a8c21ed2..226709094d 100644 --- a/src/quick/scenegraph/coreapi/qsggeometry.cpp +++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp @@ -430,9 +430,9 @@ QSGGeometry::QSGGeometry(const QSGGeometry::AttributeSet &attributes, , m_index_count(0) , m_index_type(indexType) , m_attributes(attributes) - , m_data(0) + , m_data(nullptr) , m_index_data_offset(-1) - , m_server_data(0) + , m_server_data(nullptr) , m_owns_data(false) , m_index_usage_pattern(AlwaysUploadPattern) , m_vertex_usage_pattern(AlwaysUploadPattern) @@ -529,7 +529,7 @@ QSGGeometry::~QSGGeometry() void *QSGGeometry::indexData() { return m_index_data_offset < 0 - ? 0 + ? nullptr : ((char *) m_data + m_index_data_offset); } @@ -541,7 +541,7 @@ void *QSGGeometry::indexData() const void *QSGGeometry::indexData() const { return m_index_data_offset < 0 - ? 0 + ? nullptr : ((char *) m_data + m_index_data_offset); } @@ -768,6 +768,19 @@ void QSGGeometry::updateColoredRectGeometry(QSGGeometry *g, const QRectF &rect) v[3].y = rect.bottom(); } +/*! + \enum QSGGeometry::AttributeType + + This enum identifies several attribute types. + + \value UnknownAttribute Don't care + \value PositionAttribute Position + \value ColorAttribute Color + \value TexCoordAttribute Texture coordinate + \value TexCoord1Attribute Texture coordinate 1 + \value TexCoord2Attribute Texture coordinate 2 + + */ /*! \enum QSGGeometry::DataPattern diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp index 07dc87a643..8557de1b1f 100644 --- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp +++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp @@ -443,7 +443,12 @@ void QSGMaterialShader::compile() otherwise returns \c false. */ +/*! + \fn bool QSGMaterialShader::RenderState::isCachedMaterialDataDirty() const + Returns \c true if the dirtyStates() contains the dirty cached material state, + otherwise returns \c false. + */ /*! \fn QSGMaterialShader::RenderState::DirtyStates QSGMaterialShader::RenderState::dirtyStates() const @@ -636,7 +641,7 @@ static void qt_print_material_count() */ QSGMaterial::QSGMaterial() - : m_flags(0) + : m_flags(nullptr) { Q_UNUSED(m_reserved); #ifndef QT_NO_DEBUG diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp index 22d57001fc..9717862baa 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.cpp +++ b/src/quick/scenegraph/coreapi/qsgnode.cpp @@ -114,6 +114,10 @@ static void qt_print_node_count() \value DirtyOpacity The opacity of a QSGOpacityNode has changed. \value DirtySubtreeBlocked The subtree has been blocked. + \omitvalue DirtyForceUpdate + \omitvalue DirtyUsePreprocess + \omitvalue DirtyPropagationMask + \sa QSGNode::markDirty() */ @@ -135,6 +139,8 @@ static void qt_print_node_count() ownership over the opaque material and will delete it when the node is destroyed or a material is assigned. \value InternalReserved Reserved for internal use. + + \omitvalue IsVisitableNode */ /*! @@ -149,6 +155,8 @@ static void qt_print_node_count() \value OpacityNodeType The type of QSGOpacityNode \value RenderNodeType The type of QSGRenderNode + \omitvalue RootNodeType + \sa type() */ @@ -236,15 +244,8 @@ static void qt_print_node_count() * Constructs a new node */ QSGNode::QSGNode() - : m_parent(0) - , m_type(BasicNodeType) - , m_firstChild(0) - , m_lastChild(0) - , m_nextSibling(0) - , m_previousSibling(0) - , m_subtreeRenderableCount(0) - , m_nodeFlags(OwnedByParent) - , m_dirtyState(0) + : m_nodeFlags(OwnedByParent) + , m_dirtyState(nullptr) { init(); } @@ -255,15 +256,15 @@ QSGNode::QSGNode() * \internal */ QSGNode::QSGNode(NodeType type) - : m_parent(0) + : m_parent(nullptr) , m_type(type) - , m_firstChild(0) - , m_lastChild(0) - , m_nextSibling(0) - , m_previousSibling(0) + , m_firstChild(nullptr) + , m_lastChild(nullptr) + , m_nextSibling(nullptr) + , m_previousSibling(nullptr) , m_subtreeRenderableCount(type == GeometryNodeType || type == RenderNodeType ? 1 : 0) , m_nodeFlags(OwnedByParent) - , m_dirtyState(0) + , m_dirtyState(nullptr) { init(); } @@ -274,15 +275,15 @@ QSGNode::QSGNode(NodeType type) * \internal */ QSGNode::QSGNode(QSGNodePrivate &dd, NodeType type) - : m_parent(0) + : m_parent(nullptr) , m_type(type) - , m_firstChild(0) - , m_lastChild(0) - , m_nextSibling(0) - , m_previousSibling(0) + , m_firstChild(nullptr) + , m_lastChild(nullptr) + , m_nextSibling(nullptr) + , m_previousSibling(nullptr) , m_subtreeRenderableCount(type == GeometryNodeType || type == RenderNodeType ? 1 : 0) , m_nodeFlags(OwnedByParent) - , m_dirtyState(0) + , m_dirtyState(nullptr) , d_ptr(&dd) { init(); @@ -380,17 +381,17 @@ void QSGNode::destroy() { if (m_parent) { m_parent->removeChildNode(this); - Q_ASSERT(m_parent == 0); + Q_ASSERT(m_parent == nullptr); } while (m_firstChild) { QSGNode *child = m_firstChild; removeChildNode(child); - Q_ASSERT(child->m_parent == 0); + Q_ASSERT(child->m_parent == nullptr); if (child->flags() & OwnedByParent) delete child; } - Q_ASSERT(m_firstChild == 0 && m_lastChild == 0); + Q_ASSERT(m_firstChild == nullptr && m_lastChild == nullptr); } @@ -549,11 +550,11 @@ void QSGNode::removeChildNode(QSGNode *node) next->m_previousSibling = previous; else m_lastChild = previous; - node->m_previousSibling = 0; - node->m_nextSibling = 0; + node->m_previousSibling = nullptr; + node->m_nextSibling = nullptr; node->markDirty(DirtyNodeRemoved); - node->m_parent = 0; + node->m_parent = nullptr; } @@ -566,13 +567,13 @@ void QSGNode::removeAllChildNodes() while (m_firstChild) { QSGNode *node = m_firstChild; m_firstChild = node->m_nextSibling; - node->m_nextSibling = 0; + node->m_nextSibling = nullptr; if (m_firstChild) - m_firstChild->m_previousSibling = 0; + m_firstChild->m_previousSibling = nullptr; else - m_lastChild = 0; + m_lastChild = nullptr; node->markDirty(DirtyNodeRemoved); - node->m_parent = 0; + node->m_parent = nullptr; } } @@ -706,9 +707,9 @@ void qsgnode_set_description(QSGNode *node, const QString &description) */ QSGBasicGeometryNode::QSGBasicGeometryNode(NodeType type) : QSGNode(type) - , m_geometry(0) - , m_matrix(0) - , m_clip_list(0) + , m_geometry(nullptr) + , m_matrix(nullptr) + , m_clip_list(nullptr) { } @@ -718,9 +719,9 @@ QSGBasicGeometryNode::QSGBasicGeometryNode(NodeType type) */ QSGBasicGeometryNode::QSGBasicGeometryNode(QSGBasicGeometryNodePrivate &dd, NodeType type) : QSGNode(dd, type) - , m_geometry(0) - , m_matrix(0) - , m_clip_list(0) + , m_geometry(nullptr) + , m_matrix(nullptr) + , m_clip_list(nullptr) { } @@ -862,10 +863,6 @@ void QSGBasicGeometryNode::setGeometry(QSGGeometry *geometry) QSGGeometryNode::QSGGeometryNode() : QSGBasicGeometryNode(GeometryNodeType) - , m_render_order(0) - , m_material(0) - , m_opaque_material(0) - , m_opacity(1) { } @@ -876,8 +873,8 @@ QSGGeometryNode::QSGGeometryNode() QSGGeometryNode::QSGGeometryNode(QSGGeometryNodePrivate &dd) : QSGBasicGeometryNode(dd, GeometryNodeType) , m_render_order(0) - , m_material(0) - , m_opaque_material(0) + , m_material(nullptr) + , m_opaque_material(nullptr) , m_opacity(1) { } @@ -971,7 +968,7 @@ void QSGGeometryNode::setMaterial(QSGMaterial *material) delete m_material; m_material = material; #ifndef QT_NO_DEBUG - if (m_material != 0 && m_opaque_material == m_material) + if (m_material != nullptr && m_opaque_material == m_material) qWarning("QSGGeometryNode: using same material for both opaque and translucent"); #endif markDirty(DirtyMaterial); @@ -1002,7 +999,7 @@ void QSGGeometryNode::setOpaqueMaterial(QSGMaterial *material) delete m_opaque_material; m_opaque_material = material; #ifndef QT_NO_DEBUG - if (m_opaque_material != 0 && m_opaque_material == m_material) + if (m_opaque_material != nullptr && m_opaque_material == m_material) qWarning("QSGGeometryNode: using same material for both opaque and translucent"); #endif @@ -1266,7 +1263,7 @@ QSGRootNode::QSGRootNode() QSGRootNode::~QSGRootNode() { while (!m_renderers.isEmpty()) - m_renderers.constLast()->setRootNode(0); + m_renderers.constLast()->setRootNode(nullptr); destroy(); // Must call destroy() here because markDirty() casts this to QSGRootNode. } @@ -1318,8 +1315,6 @@ void QSGRootNode::notifyNodeChange(QSGNode *node, DirtyState state) */ QSGOpacityNode::QSGOpacityNode() : QSGNode(OpacityNodeType) - , m_opacity(1) - , m_combined_opacity(1) { } diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h index f2708b2b96..854e284c9e 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.h +++ b/src/quick/scenegraph/coreapi/qsgnode.h @@ -77,9 +77,7 @@ public: TransformNodeType, ClipNodeType, OpacityNodeType, -#ifndef qdoc RootNodeType, -#endif RenderNodeType }; @@ -96,9 +94,8 @@ public: OwnsOpaqueMaterial = 0x00040000, // Uppermost 8 bits are reserved for internal use. -#ifndef qdoc IsVisitableNode = 0x01000000 -#else +#ifdef Q_CLANG_QDOC InternalReserved = 0x01000000 #endif }; @@ -113,7 +110,6 @@ public: DirtyMaterial = 0x2000, DirtyOpacity = 0x4000, -#ifndef qdoc DirtyForceUpdate = 0x8000, DirtyUsePreprocess = UsePreprocess, @@ -122,7 +118,6 @@ public: | DirtyNodeAdded | DirtyOpacity | DirtyForceUpdate -#endif }; Q_DECLARE_FLAGS(DirtyState, DirtyStateBit) @@ -173,13 +168,13 @@ private: void init(); void destroy(); - QSGNode *m_parent; - NodeType m_type; - QSGNode *m_firstChild; - QSGNode *m_lastChild; - QSGNode *m_nextSibling; - QSGNode *m_previousSibling; - int m_subtreeRenderableCount; + QSGNode *m_parent = nullptr; + NodeType m_type = BasicNodeType; + QSGNode *m_firstChild = nullptr; + QSGNode *m_lastChild = nullptr; + QSGNode *m_nextSibling = nullptr; + QSGNode *m_previousSibling = nullptr; + int m_subtreeRenderableCount = 0; Flags m_nodeFlags; DirtyState m_dirtyState; // Obsolete, remove in Qt 6 @@ -195,7 +190,7 @@ void Q_QUICK_EXPORT qsgnode_set_description(QSGNode *node, const QString &descri class Q_QUICK_EXPORT QSGBasicGeometryNode : public QSGNode { public: - ~QSGBasicGeometryNode(); + ~QSGBasicGeometryNode() override; void setGeometry(QSGGeometry *geometry); const QSGGeometry *geometry() const { return m_geometry; } @@ -229,7 +224,7 @@ class Q_QUICK_EXPORT QSGGeometryNode : public QSGBasicGeometryNode { public: QSGGeometryNode(); - ~QSGGeometryNode(); + ~QSGGeometryNode() override; void setMaterial(QSGMaterial *material); QSGMaterial *material() const { return m_material; } @@ -251,18 +246,18 @@ protected: private: friend class QSGNodeUpdater; - int m_render_order; - QSGMaterial *m_material; - QSGMaterial *m_opaque_material; + int m_render_order = 0; + QSGMaterial *m_material = nullptr; + QSGMaterial *m_opaque_material = nullptr; - qreal m_opacity; + qreal m_opacity = 1; }; class Q_QUICK_EXPORT QSGClipNode : public QSGBasicGeometryNode { public: QSGClipNode(); - ~QSGClipNode(); + ~QSGClipNode() override; void setIsRectangular(bool rectHint); bool isRectangular() const { return m_is_rectangular; } @@ -282,7 +277,7 @@ class Q_QUICK_EXPORT QSGTransformNode : public QSGNode { public: QSGTransformNode(); - ~QSGTransformNode(); + ~QSGTransformNode() override; void setMatrix(const QMatrix4x4 &matrix); const QMatrix4x4 &matrix() const { return m_matrix; } @@ -300,7 +295,7 @@ class Q_QUICK_EXPORT QSGRootNode : public QSGNode { public: QSGRootNode(); - ~QSGRootNode(); + ~QSGRootNode() override; private: void notifyNodeChange(QSGNode *node, DirtyState state); @@ -317,7 +312,7 @@ class Q_QUICK_EXPORT QSGOpacityNode : public QSGNode { public: QSGOpacityNode(); - ~QSGOpacityNode(); + ~QSGOpacityNode() override; void setOpacity(qreal opacity); qreal opacity() const { return m_opacity; } @@ -328,8 +323,8 @@ public: bool isSubtreeBlocked() const override; private: - qreal m_opacity; - qreal m_combined_opacity; + qreal m_opacity = 1; + qreal m_combined_opacity = 1; }; class Q_QUICK_EXPORT QSGNodeVisitor { diff --git a/src/quick/scenegraph/coreapi/qsgnode_p.h b/src/quick/scenegraph/coreapi/qsgnode_p.h index 84d5477085..f81128f51a 100644 --- a/src/quick/scenegraph/coreapi/qsgnode_p.h +++ b/src/quick/scenegraph/coreapi/qsgnode_p.h @@ -78,18 +78,14 @@ public: class QSGBasicGeometryNodePrivate : public QSGNodePrivate { public: - QSGBasicGeometryNodePrivate() - : QSGNodePrivate() - {} + QSGBasicGeometryNodePrivate() {} }; class QSGGeometryNodePrivate: public QSGBasicGeometryNodePrivate { public: - QSGGeometryNodePrivate() - : QSGBasicGeometryNodePrivate() - {} + QSGGeometryNodePrivate() {} }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp index d6d533307e..8bc9ded594 100644 --- a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp +++ b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE QSGNodeUpdater::QSGNodeUpdater() : m_combined_matrix_stack(64) , m_opacity_stack(64) - , m_current_clip(0) + , m_current_clip(nullptr) , m_force_update(0) { m_opacity_stack.add(1); @@ -60,7 +60,7 @@ QSGNodeUpdater::~QSGNodeUpdater() void QSGNodeUpdater::updateStates(QSGNode *n) { - m_current_clip = 0; + m_current_clip = nullptr; m_force_update = 0; Q_ASSERT(m_opacity_stack.size() == 1); // The one we added in the constructr... @@ -82,7 +82,7 @@ void QSGNodeUpdater::updateStates(QSGNode *n) bool QSGNodeUpdater::isNodeBlocked(QSGNode *node, QSGNode *root) const { - while (node != root && node != 0) { + while (node != root && node != nullptr) { if (node->isSubtreeBlocked()) return true; node = node->parent(); diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp index 3ae79a933f..e1ba001d2d 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp @@ -132,8 +132,8 @@ QSGRenderer::QSGRenderer(QSGRenderContext *context) , m_current_determinant(1) , m_device_pixel_ratio(1) , m_context(context) - , m_node_updater(0) - , m_bindable(0) + , m_node_updater(nullptr) + , m_bindable(nullptr) , m_changed_emitted(false) , m_is_rendering(false) , m_is_preprocessing(false) @@ -143,7 +143,7 @@ QSGRenderer::QSGRenderer(QSGRenderContext *context) QSGRenderer::~QSGRenderer() { - setRootNode(0); + setRootNode(nullptr); delete m_node_updater; } @@ -249,7 +249,7 @@ void QSGRenderer::renderScene(const QSGBindable &bindable) m_is_rendering = false; m_changed_emitted = false; - m_bindable = 0; + m_bindable = nullptr; qCDebug(QSG_LOG_TIME_RENDERER, "time in renderer: total=%dms, preprocess=%d, updates=%d, binding=%d, rendering=%d", diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h index ae8d9f75d2..8362ff54dc 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h @@ -168,12 +168,12 @@ class Q_QUICK_PRIVATE_EXPORT QSGNodeDumper : public QSGNodeVisitor { public: static void dump(QSGNode *n); - QSGNodeDumper() : m_indent(0) {} + QSGNodeDumper() {} void visitNode(QSGNode *n) override; void visitChildren(QSGNode *n) override; private: - int m_indent; + int m_indent = 0; }; diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp index a8954848d6..df3fa16a32 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp @@ -74,8 +74,8 @@ QSGRenderNode::~QSGRenderNode() } QSGRenderNodePrivate::QSGRenderNodePrivate() - : m_matrix(0) - , m_clip_list(0) + : m_matrix(nullptr) + , m_clip_list(nullptr) , m_opacity(1) { } @@ -119,7 +119,7 @@ QSGRenderNodePrivate::QSGRenderNodePrivate() */ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const { - return 0; + return nullptr; } /*! @@ -213,6 +213,22 @@ void QSGRenderNode::releaseResources() } /*! + \enum QSGRenderNode::StateFlag + + This enum is a bit mask identifying several states. + + \value DepthState Depth + \value StencilState Stencil + \value ScissorState Scissor + \value ColorState Color + \value BlendState Blend + \value CullState Cull + \value ViewportState View poirt + \value RenderTargetState Render target + + */ + +/*! \enum QSGRenderNode::RenderingFlag Possible values for the bitmask returned from flags(). @@ -251,7 +267,7 @@ void QSGRenderNode::releaseResources() */ QSGRenderNode::RenderingFlags QSGRenderNode::flags() const { - return 0; + return nullptr; } /*! @@ -354,7 +370,7 @@ QSGRenderNode::RenderState::~RenderState() */ /*! - \fn const QRegion *QSGRenderNode::clipRegion() const + \fn const QRegion *QSGRenderNode::RenderState::clipRegion() const \return the current clip region or null for backends where clipping is implemented via stencil or scissoring. diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.h b/src/quick/scenegraph/coreapi/qsgrendernode.h index f6bc40d3ee..0fb83b080c 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.h +++ b/src/quick/scenegraph/coreapi/qsgrendernode.h @@ -80,7 +80,7 @@ public: }; QSGRenderNode(); - ~QSGRenderNode(); + ~QSGRenderNode() override; virtual StateFlags changedStates() const; virtual void render(const RenderState *state) = 0; diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h index ba146b884f..9c88b8272c 100644 --- a/src/quick/scenegraph/qsgadaptationlayer_p.h +++ b/src/quick/scenegraph/qsgadaptationlayer_p.h @@ -266,19 +266,19 @@ public: Texture // for APIs with separate texture and sampler objects }; struct InputParameter { - InputParameter() : semanticIndex(0) { } + InputParameter() {} // Semantics use the D3D keys (POSITION, TEXCOORD). // Attribute name based APIs can map based on pre-defined names. QByteArray semanticName; - int semanticIndex; + int semanticIndex = 0; }; struct Variable { - Variable() : type(Constant), offset(0), size(0), bindPoint(0) { } - VariableType type; + Variable() {} + VariableType type = Constant; QByteArray name; - uint offset; // for cbuffer members - uint size; // for cbuffer members - int bindPoint; // for textures and samplers; for register-based APIs + uint offset = 0; // for cbuffer members + uint size = 0; // for cbuffer members + int bindPoint = 0; // for textures and samplers; for register-based APIs }; QByteArray blob; // source or bytecode @@ -329,8 +329,8 @@ public: }; struct ShaderData { - ShaderData() : hasShaderCode(false) { } - bool hasShaderCode; + ShaderData() {} + bool hasShaderCode = false; QSGGuiThreadShaderEffectManager::ShaderInfo shaderInfo; QVector<VariableData> varData; }; @@ -373,7 +373,7 @@ public: HighQualitySubPixelAntialiasing }; - QSGGlyphNode() : m_ownerElement(0) {} + QSGGlyphNode() {} virtual void setGlyphs(const QPointF &position, const QGlyphRun &glyphs) = 0; virtual void setColor(const QColor &color) = 0; @@ -394,7 +394,7 @@ public: void accept(QSGNodeVisitorEx *visitor) override { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); } protected: QRectF m_bounding_rect; - QQuickItem *m_ownerElement; + QQuickItem *m_ownerElement = nullptr; }; class Q_QUICK_PRIVATE_EXPORT QSGDistanceFieldGlyphConsumer @@ -421,24 +421,24 @@ public: }; struct TexCoord { - qreal x; - qreal y; - qreal width; - qreal height; - qreal xMargin; - qreal yMargin; + qreal x = 0; + qreal y = 0; + qreal width = -1; + qreal height = -1; + qreal xMargin = 0; + qreal yMargin = 0; - TexCoord() : x(0), y(0), width(-1), height(-1), xMargin(0), yMargin(0) { } + TexCoord() {} bool isNull() const { return width <= 0 || height <= 0; } bool isValid() const { return width >= 0 && height >= 0; } }; struct Texture { - uint textureId; + uint textureId = 0; QSize size; - Texture() : textureId(0), size(QSize()) { } + Texture() : size(QSize()) { } bool operator == (const Texture &other) const { return textureId == other.textureId; } }; @@ -478,13 +478,13 @@ protected: }; struct GlyphData { - Texture *texture; + Texture *texture = nullptr; TexCoord texCoord; QRectF boundingRect; QPainterPath path; - quint32 ref; + quint32 ref = 0; - GlyphData() : texture(0), ref(0) { } + GlyphData() {} }; virtual void requestGlyphs(const QSet<glyph_t> &glyphs) = 0; diff --git a/src/quick/scenegraph/qsgbasicglyphnode.cpp b/src/quick/scenegraph/qsgbasicglyphnode.cpp index 38f650a82c..4559b7951c 100644 --- a/src/quick/scenegraph/qsgbasicglyphnode.cpp +++ b/src/quick/scenegraph/qsgbasicglyphnode.cpp @@ -44,7 +44,7 @@ QT_BEGIN_NAMESPACE QSGBasicGlyphNode::QSGBasicGlyphNode() : m_style(QQuickText::Normal) - , m_material(0) + , m_material(nullptr) , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0) { m_geometry.setDrawingMode(QSGGeometry::DrawTriangles); @@ -59,7 +59,7 @@ QSGBasicGlyphNode::~QSGBasicGlyphNode() void QSGBasicGlyphNode::setColor(const QColor &color) { m_color = color; - if (m_material != 0) { + if (m_material != nullptr) { setMaterialColor(color); markDirty(DirtyMaterial); } @@ -67,7 +67,7 @@ void QSGBasicGlyphNode::setColor(const QColor &color) void QSGBasicGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs) { - if (m_material != 0) + if (m_material != nullptr) delete m_material; m_position = position; diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index fb66a6ebb1..d9ed25c099 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -363,13 +363,6 @@ void QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine) } /*! - Factory function for texture objects. - - If \a image is a valid image, the QSGTexture::setImage function - will be called with \a image as argument. - */ - -/*! Factory function for the scene graph renderers. The renderers are used for the toplevel renderer and once for every @@ -379,7 +372,7 @@ void QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine) QSGTexture *QSGRenderContext::textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window) { if (!factory) - return 0; + return nullptr; m_mutex.lock(); QSGTexture *texture = m_textures.value(factory); @@ -404,6 +397,20 @@ void QSGRenderContext::textureFactoryDestroyed(QObject *o) m_mutex.unlock(); } +/*! + Return the texture corresponding to a texture factory. + + This may optionally manipulate the texture in some way; for example by returning + an atlased texture. + + This function is not a replacement for textureForFactory; both should be used + for a single texture (this might atlas, while the other might cache). +*/ +QSGTexture *QSGRenderContext::compressedTextureForFactory(const QSGCompressedTextureFactory *) const +{ + return nullptr; +} + #include "qsgcontext.moc" #include "moc_qsgcontext_p.cpp" diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index 84a2523f26..6d70d7ef6b 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -78,6 +78,7 @@ class QSGMaterial; class QSGRenderLoop; class QSGLayer; class QQuickTextureFactory; +class QSGCompressedTextureFactory; class QSGContext; class QQuickPaintedItem; class QSGRendererInterface; @@ -109,8 +110,8 @@ public: MsaaAntialiasing }; - explicit QSGContext(QObject *parent = 0); - virtual ~QSGContext(); + explicit QSGContext(QObject *parent = nullptr); + ~QSGContext() override; virtual void renderContextInitialized(QSGRenderContext *renderContext); virtual void renderContextInvalidated(QSGRenderContext *renderContext); @@ -158,7 +159,7 @@ public: }; QSGRenderContext(QSGContext *context); - virtual ~QSGRenderContext(); + ~QSGRenderContext() override; QSGContext *sceneGraphContext() const { return m_sg; } virtual bool isValid() const { return true; } @@ -173,6 +174,7 @@ public: virtual QSGTexture *createTexture(const QImage &image, uint flags = CreateTexture_Alpha) const = 0; virtual QSGRenderer *createRenderer() = 0; + virtual QSGTexture *compressedTextureForFactory(const QSGCompressedTextureFactory *) const; virtual void setAttachToGraphicsContext(bool attach) { Q_UNUSED(attach); } diff --git a/src/quick/scenegraph/qsgcontextplugin.cpp b/src/quick/scenegraph/qsgcontextplugin.cpp index 1c2550d197..31f1c4c722 100644 --- a/src/quick/scenegraph/qsgcontextplugin.cpp +++ b/src/quick/scenegraph/qsgcontextplugin.cpp @@ -74,8 +74,8 @@ struct QSGAdaptationBackendData { QSGAdaptationBackendData(); - bool tried; - QSGContextFactoryInterface *factory; + bool tried = false; + QSGContextFactoryInterface *factory = nullptr; QString name; QSGContextFactoryInterface::Flags flags; @@ -85,9 +85,7 @@ struct QSGAdaptationBackendData }; QSGAdaptationBackendData::QSGAdaptationBackendData() - : tried(false) - , factory(nullptr) - , flags(0) + : flags(nullptr) { // Fill in the table with the built-in adaptations. builtIns.append(new QSGSoftwareAdaptation); @@ -140,7 +138,9 @@ QSGAdaptationBackendData *contextFactory() #ifdef Q_OS_HTML5 requestedBackend = QString::fromLocal8Bit("software"); #endif + if (!requestedBackend.isEmpty()) { + qCDebug(QSG_LOG_INFO, "Loading backend %s", qUtf8Printable(requestedBackend)); // First look for a built-in adaptation. for (QSGContextFactoryInterface *builtInBackend : qAsConst(backendData->builtIns)) { @@ -210,7 +210,7 @@ QQuickTextureFactory *QSGContext::createTextureFactoryFromImage(const QImage &im QSGAdaptationBackendData *backendData = contextFactory(); if (backendData->factory) return backendData->factory->createTextureFactoryFromImage(image); - return 0; + return nullptr; } @@ -224,7 +224,7 @@ QSGRenderLoop *QSGContext::createWindowManager() QSGAdaptationBackendData *backendData = contextFactory(); if (backendData->factory) return backendData->factory->createWindowManager(); - return 0; + return nullptr; } void QSGContext::setBackend(const QString &backend) diff --git a/src/quick/scenegraph/qsgcontextplugin_p.h b/src/quick/scenegraph/qsgcontextplugin_p.h index 02d4b79b76..d37d4df270 100644 --- a/src/quick/scenegraph/qsgcontextplugin_p.h +++ b/src/quick/scenegraph/qsgcontextplugin_p.h @@ -87,13 +87,13 @@ class Q_QUICK_PRIVATE_EXPORT QSGContextPlugin : public QObject, public QSGContex Q_OBJECT Q_INTERFACES(QSGContextFactoryInterface:QFactoryInterface) public: - explicit QSGContextPlugin(QObject *parent = 0); + explicit QSGContextPlugin(QObject *parent = nullptr); virtual ~QSGContextPlugin(); QStringList keys() const override = 0; - QQuickTextureFactory *createTextureFactoryFromImage(const QImage &) override { return 0; } - QSGRenderLoop *createWindowManager() override { return 0; } + QQuickTextureFactory *createTextureFactoryFromImage(const QImage &) override { return nullptr; } + QSGRenderLoop *createWindowManager() override { return nullptr; } }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp index be5fec9dab..9a0ac66690 100644 --- a/src/quick/scenegraph/qsgdefaultcontext.cpp +++ b/src/quick/scenegraph/qsgdefaultcontext.cpp @@ -149,20 +149,23 @@ void QSGDefaultContext::renderContextInitialized(QSGRenderContext *renderContext dumped = true; QSurfaceFormat format = openglRenderContext->openglContext()->format(); QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - qCDebug(QSG_LOG_INFO) << "R/G/B/A Buffers: " << format.redBufferSize() << format.greenBufferSize() << format.blueBufferSize() << format.alphaBufferSize(); - qCDebug(QSG_LOG_INFO) << "Depth Buffer: " << format.depthBufferSize(); - qCDebug(QSG_LOG_INFO) << "Stencil Buffer: " << format.stencilBufferSize(); - qCDebug(QSG_LOG_INFO) << "Samples: " << format.samples(); - qCDebug(QSG_LOG_INFO) << "GL_VENDOR: " << (const char *) funcs->glGetString(GL_VENDOR); - qCDebug(QSG_LOG_INFO) << "GL_RENDERER: " << (const char *) funcs->glGetString(GL_RENDERER); - qCDebug(QSG_LOG_INFO) << "GL_VERSION: " << (const char *) funcs->glGetString(GL_VERSION); + qCDebug(QSG_LOG_INFO, "R/G/B/A Buffers: %d %d %d %d", format.redBufferSize(), + format.greenBufferSize(), format.blueBufferSize(), format.alphaBufferSize()); + qCDebug(QSG_LOG_INFO, "Depth Buffer: %d", format.depthBufferSize()); + qCDebug(QSG_LOG_INFO, "Stencil Buffer: %d", format.stencilBufferSize()); + qCDebug(QSG_LOG_INFO, "Samples: %d", format.samples()); + qCDebug(QSG_LOG_INFO, "GL_VENDOR: %s", (const char*)funcs->glGetString(GL_VENDOR)); + qCDebug(QSG_LOG_INFO, "GL_RENDERER: %s", + (const char*)funcs->glGetString(GL_RENDERER)); + qCDebug(QSG_LOG_INFO, "GL_VERSION: %s", (const char*)funcs->glGetString(GL_VERSION)); QSet<QByteArray> exts = openglRenderContext->openglContext()->extensions(); QByteArray all; for (const QByteArray &e : qAsConst(exts)) all += ' ' + e; - qCDebug(QSG_LOG_INFO) << "GL_EXTENSIONS: " << all.constData(); - qCDebug(QSG_LOG_INFO) << "Max Texture Size: " << openglRenderContext->maxTextureSize(); - qCDebug(QSG_LOG_INFO) << "Debug context: " << format.testOption(QSurfaceFormat::DebugContext); + qCDebug(QSG_LOG_INFO, "GL_EXTENSIONS: %s", all.constData()); + qCDebug(QSG_LOG_INFO, "Max Texture Size: %d", openglRenderContext->maxTextureSize()); + qCDebug(QSG_LOG_INFO, "Debug context: %s", + format.testOption(QSurfaceFormat::DebugContext) ? "true" : "false"); } m_mutex.unlock(); diff --git a/src/quick/scenegraph/qsgdefaultcontext_p.h b/src/quick/scenegraph/qsgdefaultcontext_p.h index b2964bf403..6dfd197cf6 100644 --- a/src/quick/scenegraph/qsgdefaultcontext_p.h +++ b/src/quick/scenegraph/qsgdefaultcontext_p.h @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE class Q_QUICK_PRIVATE_EXPORT QSGDefaultContext : public QSGContext, public QSGRendererInterface { public: - QSGDefaultContext(QObject *parent = 0); + QSGDefaultContext(QObject *parent = nullptr); ~QSGDefaultContext(); void renderContextInitialized(QSGRenderContext *renderContext) override; diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp index 7789ef8fb1..ef189ba461 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp @@ -63,12 +63,12 @@ QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QOpenGLCont : QSGDistanceFieldGlyphCache(c, font) , m_maxTextureSize(0) , m_maxTextureCount(3) - , m_blitProgram(0) + , m_blitProgram(nullptr) , m_blitBuffer(QOpenGLBuffer::VertexBuffer) - , m_fboGuard(0) + , m_fboGuard(nullptr) , m_funcs(c->functions()) #if !defined(QT_OPENGL_ES_2) - , m_coreFuncs(0) + , m_coreFuncs(nullptr) #endif { if (Q_LIKELY(m_blitBuffer.create())) { @@ -89,7 +89,7 @@ QSGDefaultDistanceFieldGlyphCache::~QSGDefaultDistanceFieldGlyphCache() for (int i = 0; i < m_textures.count(); ++i) m_funcs->glDeleteTextures(1, &m_textures[i].texture); - if (m_fboGuard != 0) + if (m_fboGuard != nullptr) m_fboGuard->free(); delete m_blitProgram; @@ -400,7 +400,7 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); #endif m_funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); + GL_RGBA, GL_UNSIGNED_BYTE, nullptr); m_funcs->glBindTexture(GL_TEXTURE_2D, 0); m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_texture, 0); diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h index fe365495c2..76c0d20647 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h @@ -91,10 +91,9 @@ private: QSize size; QRect allocatedArea; QDistanceField image; - int padding; + int padding = -1; - TextureInfo(const QRect &preallocRect = QRect()) : texture(0), allocatedArea(preallocRect), padding(-1) - { } + TextureInfo(const QRect &preallocRect = QRect()) : texture(0), allocatedArea(preallocRect) { } }; void createTexture(TextureInfo * texInfo, int width, int height); diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index 0169f097bc..dc473a6640 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -107,7 +107,7 @@ protected: char const *const *QSGTextMaskShader::attributeNames() const { - static char const *const attr[] = { "vCoord", "tCoord", 0 }; + static char const *const attr[] = { "vCoord", "tCoord", nullptr }; return attr; } @@ -141,13 +141,13 @@ void QSGTextMaskShader::updateState(const RenderState &state, QSGMaterial *newEf { QSGTextMaskMaterial *material = static_cast<QSGTextMaskMaterial *>(newEffect); QSGTextMaskMaterial *oldMaterial = static_cast<QSGTextMaskMaterial *>(oldEffect); - Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); + Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); bool updated = material->ensureUpToDate(); Q_ASSERT(material->texture()); - Q_ASSERT(oldMaterial == 0 || oldMaterial->texture()); + Q_ASSERT(oldMaterial == nullptr || oldMaterial->texture()); if (updated - || oldMaterial == 0 + || oldMaterial == nullptr || oldMaterial->texture()->textureId() != material->texture()->textureId()) { program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->cacheTextureWidth(), 1.0 / material->cacheTextureHeight())); @@ -190,7 +190,7 @@ void QSG8BitTextMaskShader::updateState(const RenderState &state, QSGMaterial *n QSGTextMaskMaterial *material = static_cast<QSGTextMaskMaterial *>(newEffect); QSGTextMaskMaterial *oldMaterial = static_cast<QSGTextMaskMaterial *>(oldEffect); - if (oldMaterial == 0 || material->color() != oldMaterial->color() || state.isOpacityDirty()) { + if (oldMaterial == nullptr || material->color() != oldMaterial->color() || state.isOpacityDirty()) { QVector4D color = qsg_premultiply(material->color(), state.opacity()); program()->setUniformValue(m_color_id, color); } @@ -282,7 +282,7 @@ void QSG24BitTextMaskShader::updateState(const RenderState &state, QSGMaterial * QSGTextMaskMaterial *material = static_cast<QSGTextMaskMaterial *>(newEffect); QSGTextMaskMaterial *oldMaterial = static_cast<QSGTextMaskMaterial *>(oldEffect); - if (oldMaterial == 0 || material->color() != oldMaterial->color() || state.isOpacityDirty()) { + if (oldMaterial == nullptr || material->color() != oldMaterial->color() || state.isOpacityDirty()) { QVector4D color = material->color(); if (useSRGB()) color = qt_sRGB_to_linear_RGB(color); @@ -346,20 +346,20 @@ void QSGStyledTextShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) { - Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); + Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); QSGStyledTextMaterial *material = static_cast<QSGStyledTextMaterial *>(newEffect); QSGStyledTextMaterial *oldMaterial = static_cast<QSGStyledTextMaterial *>(oldEffect); - if (oldMaterial == 0 || oldMaterial->styleShift() != material->styleShift()) + if (oldMaterial == nullptr || oldMaterial->styleShift() != material->styleShift()) program()->setUniformValue(m_shift_id, material->styleShift()); - if (oldMaterial == 0 || material->color() != oldMaterial->color() || state.isOpacityDirty()) { + if (oldMaterial == nullptr || material->color() != oldMaterial->color() || state.isOpacityDirty()) { QVector4D color = qsg_premultiply(material->color(), state.opacity()); program()->setUniformValue(m_color_id, color); } - if (oldMaterial == 0 || material->styleColor() != oldMaterial->styleColor() || state.isOpacityDirty()) { + if (oldMaterial == nullptr || material->styleColor() != oldMaterial->styleColor() || state.isOpacityDirty()) { QVector4D styleColor = qsg_premultiply(material->styleColor(), state.opacity()); program()->setUniformValue(m_styleColor_id, styleColor); } @@ -367,9 +367,9 @@ void QSGStyledTextShader::updateState(const RenderState &state, bool updated = material->ensureUpToDate(); Q_ASSERT(material->texture()); - Q_ASSERT(oldMaterial == 0 || oldMaterial->texture()); + Q_ASSERT(oldMaterial == nullptr || oldMaterial->texture()); if (updated - || oldMaterial == 0 + || oldMaterial == nullptr || oldMaterial->texture()->textureId() != material->texture()->textureId()) { program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->cacheTextureWidth(), 1.0 / material->cacheTextureHeight())); @@ -400,8 +400,8 @@ public: }; QSGTextMaskMaterial::QSGTextMaskMaterial(const QRawFont &font, QFontEngine::GlyphFormat glyphFormat) - : m_texture(0) - , m_glyphCache(0) + : m_texture(nullptr) + , m_glyphCache(nullptr) , m_font(font) { init(glyphFormat); @@ -419,7 +419,7 @@ void QSGTextMaskMaterial::init(QFontEngine::GlyphFormat glyphFormat) setFlag(Blending, true); QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext()); - Q_ASSERT(ctx != 0); + Q_ASSERT(ctx != 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 diff --git a/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp b/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp index a5a6da06a7..5dd6eaa4ca 100644 --- a/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp +++ b/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp @@ -83,7 +83,6 @@ QSGMaterialShader *QSGSmoothTextureMaterial::createShader() const } SmoothTextureMaterialShader::SmoothTextureMaterialShader() - : QSGTextureMaterialShader() { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/smoothtexture.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/smoothtexture.frag")); @@ -91,7 +90,7 @@ SmoothTextureMaterialShader::SmoothTextureMaterialShader() void SmoothTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) { - if (oldEffect == 0) { + if (oldEffect == nullptr) { // The viewport is constant, so set the pixel size uniform only once. QRect r = state.viewportRect(); program()->setUniformValue(m_pixelSizeLoc, 2.0f / r.width(), 2.0f / r.height()); @@ -106,7 +105,7 @@ char const *const *SmoothTextureMaterialShader::attributeNames() const "multiTexCoord", "vertexOffset", "texCoordOffset", - 0 + nullptr }; return attributes; } @@ -171,7 +170,7 @@ void QSGDefaultInternalImageNode::updateMaterialAntialiasing() { if (m_antialiasing) { setMaterial(&m_smoothMaterial); - setOpaqueMaterial(0); + setOpaqueMaterial(nullptr); } else { setMaterial(&m_materialO); setOpaqueMaterial(&m_material); diff --git a/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp index e52dcaad52..fd0dcebd57 100644 --- a/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp +++ b/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp @@ -67,7 +67,6 @@ private: }; SmoothColorMaterialShader::SmoothColorMaterialShader() - : QSGMaterialShader() { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/smoothcolor.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/smoothcolor.frag")); @@ -81,7 +80,7 @@ void SmoothColorMaterialShader::updateState(const RenderState &state, QSGMateria if (state.isMatrixDirty()) program()->setUniformValue(m_matrixLoc, state.combinedMatrix()); - if (oldEffect == 0) { + if (oldEffect == nullptr) { // The viewport is constant, so set the pixel size uniform only once. QRect r = state.viewportRect(); program()->setUniformValue(m_pixelSizeLoc, 2.0f / r.width(), 2.0f / r.height()); @@ -94,7 +93,7 @@ char const *const *SmoothColorMaterialShader::attributeNames() const "vertex", "vertexColor", "vertexOffset", - 0 + nullptr }; return attributes; } diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp index cd9c4a9a90..b2b123912f 100644 --- a/src/quick/scenegraph/qsgdefaultlayer.cpp +++ b/src/quick/scenegraph/qsgdefaultlayer.cpp @@ -90,15 +90,15 @@ namespace QSGDefaultLayer::QSGDefaultLayer(QSGRenderContext *context) : QSGLayer() - , m_item(0) + , m_item(nullptr) , m_device_pixel_ratio(1) , m_format(GL_RGBA) - , m_renderer(0) - , m_fbo(0) - , m_secondaryFbo(0) + , m_renderer(nullptr) + , m_fbo(nullptr) + , m_secondaryFbo(nullptr) , m_transparentTexture(0) #ifdef QSG_DEBUG_FBO_OVERLAY - , m_debugOverlay(0) + , m_debugOverlay(nullptr) #endif , m_samples(0) , m_mipmap(false) @@ -122,13 +122,13 @@ QSGDefaultLayer::~QSGDefaultLayer() void QSGDefaultLayer::invalidated() { delete m_renderer; - m_renderer = 0; + m_renderer = nullptr; delete m_fbo; delete m_secondaryFbo; - m_fbo = m_secondaryFbo = 0; + m_fbo = m_secondaryFbo = nullptr; #ifdef QSG_DEBUG_FBO_OVERLAY delete m_debugOverlay; - m_debugOverlay = 0; + m_debugOverlay = nullptr; #endif if (m_transparentTexture) { QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_transparentTexture); @@ -204,7 +204,7 @@ void QSGDefaultLayer::setItem(QSGNode *item) if (m_live && !m_item) { delete m_fbo; delete m_secondaryFbo; - m_fbo = m_secondaryFbo = 0; + m_fbo = m_secondaryFbo = nullptr; m_depthStencilBuffer.clear(); } @@ -228,7 +228,7 @@ void QSGDefaultLayer::setSize(const QSize &size) if (m_live && m_size.isNull()) { delete m_fbo; delete m_secondaryFbo; - m_fbo = m_secondaryFbo = 0; + m_fbo = m_secondaryFbo = nullptr; m_depthStencilBuffer.clear(); } @@ -252,7 +252,7 @@ void QSGDefaultLayer::setLive(bool live) if (m_live && (!m_item || m_size.isNull())) { delete m_fbo; delete m_secondaryFbo; - m_fbo = m_secondaryFbo = 0; + m_fbo = m_secondaryFbo = nullptr; m_depthStencilBuffer.clear(); } @@ -295,7 +295,7 @@ void QSGDefaultLayer::grab() if (!m_item || m_size.isNull()) { delete m_fbo; delete m_secondaryFbo; - m_fbo = m_secondaryFbo = 0; + m_fbo = m_secondaryFbo = nullptr; m_depthStencilBuffer.clear(); m_dirtyTexture = false; return; @@ -362,7 +362,7 @@ void QSGDefaultLayer::grab() delete m_fbo; delete m_secondaryFbo; m_fbo = new QOpenGLFramebufferObject(m_size, format); - m_secondaryFbo = 0; + m_secondaryFbo = nullptr; funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_fbo); diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp index 95f3555994..7882496062 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp +++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp @@ -44,6 +44,7 @@ #include <QtQuick/private/qsgbatchrenderer_p.h> #include <QtQuick/private/qsgrenderer_p.h> #include <QtQuick/private/qsgatlastexture_p.h> +#include <QtQuick/private/qsgcompressedtexture_p.h> #include <QtQuick/private/qsgdefaultdistancefieldglyphcache_p.h> QT_BEGIN_NAMESPACE @@ -156,14 +157,14 @@ void QSGDefaultRenderContext::invalidate() m_fontEnginesToClean.clear(); delete m_depthStencilManager; - m_depthStencilManager = 0; + m_depthStencilManager = nullptr; 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 = 0; + m_gl = nullptr; if (m_sg) m_sg->renderContextInvalidated(this); @@ -210,7 +211,7 @@ QSharedPointer<QSGDepthStencilBuffer> QSGDefaultRenderContext::depthStencilBuffe QSGDepthStencilBufferManager *QSGDefaultRenderContext::depthStencilBufferManager() { if (!m_gl) - return 0; + return nullptr; if (!m_depthStencilManager) m_depthStencilManager = new QSGDepthStencilBufferManager(m_gl); return m_depthStencilManager; @@ -243,6 +244,14 @@ QSGRenderer *QSGDefaultRenderContext::createRenderer() return new QSGBatchRenderer::Renderer(this); } +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); + return nullptr; +} + /*! Compile \a shader, optionally using \a vertexCode and \a fragmentCode as replacement for the source code supplied by \a shader. diff --git a/src/quick/scenegraph/qsgdefaultrendercontext_p.h b/src/quick/scenegraph/qsgdefaultrendercontext_p.h index 2537a06988..eb62586a94 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext_p.h +++ b/src/quick/scenegraph/qsgdefaultrendercontext_p.h @@ -84,8 +84,9 @@ public: QSGTexture *createTexture(const QImage &image, uint flags) const override; QSGRenderer *createRenderer() override; + QSGTexture *compressedTextureForFactory(const QSGCompressedTextureFactory *factory) const override; - virtual void compileShader(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode = 0, const char *fragmentCode = 0); + virtual void compileShader(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode = nullptr, const char *fragmentCode = nullptr); virtual void initializeShader(QSGMaterialShader *shader); void setAttachToGraphicsContext(bool attach) override; diff --git a/src/quick/scenegraph/qsgdefaultspritenode.cpp b/src/quick/scenegraph/qsgdefaultspritenode.cpp index 7fe6048d59..8761d99c1f 100644 --- a/src/quick/scenegraph/qsgdefaultspritenode.cpp +++ b/src/quick/scenegraph/qsgdefaultspritenode.cpp @@ -70,26 +70,18 @@ public: return this - static_cast<const QQuickSpriteMaterial *>(other); } - QSGTexture *texture; - - float animT; - float animX1; - float animY1; - float animX2; - float animY2; - float animW; - float animH; + QSGTexture *texture = nullptr; + + float animT = 0.0f; + float animX1 = 0.0f; + float animY1 = 0.0f; + float animX2 = 0.0f; + float animY2 = 0.0f; + float animW = 1.0f; + float animH = 1.0f; }; QQuickSpriteMaterial::QQuickSpriteMaterial() - : texture(0) - , animT(0.0f) - , animX1(0.0f) - , animY1(0.0f) - , animX2(0.0f) - , animY2(0.0f) - , animW(1.0f) - , animH(1.0f) { setFlag(Blending, true); } @@ -103,7 +95,6 @@ class SpriteMaterialData : public QSGMaterialShader { public: SpriteMaterialData() - : QSGMaterialShader() { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/sprite.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/sprite.frag")); @@ -133,7 +124,7 @@ public: static const char *attr[] = { "vPos", "vTex", - 0 + nullptr }; return attr; } diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp index 32eda2d142..ae6336718e 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp @@ -46,12 +46,12 @@ QT_BEGIN_NAMESPACE QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGRenderContext *context) : m_glyphNodeType(RootGlyphNode) , m_context(context) - , m_material(0) - , m_glyph_cache(0) + , m_material(nullptr) + , m_glyph_cache(nullptr) , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0) , m_style(QQuickText::Normal) , m_antialiasingMode(GrayAntialiasing) - , m_texture(0) + , m_texture(nullptr) , m_dirtyGeometry(false) , m_dirtyMaterial(false) { @@ -80,7 +80,7 @@ QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode() void QSGDistanceFieldGlyphNode::setColor(const QColor &color) { m_color = color; - if (m_material != 0) { + if (m_material != nullptr) { m_material->setColor(color); markDirty(DirtyMaterial); } else { @@ -113,7 +113,7 @@ void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphR return; if (m_glyph_cache != oldCache) { - Q_ASSERT(ownerElement() != 0); + Q_ASSERT(ownerElement() != nullptr); if (oldCache) { oldCache->unregisterGlyphNode(this); oldCache->unregisterOwnerElement(ownerElement()); @@ -181,7 +181,7 @@ void QSGDistanceFieldGlyphNode::updateGeometry() // Remove previously created sub glyph nodes // We assume all the children are sub glyph nodes QSGNode *subnode = firstChild(); - QSGNode *nextNode = 0; + QSGNode *nextNode = nullptr; while (subnode) { nextNode = subnode->nextSibling(); delete subnode; diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp index a67c659c99..aa58218505 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp @@ -61,37 +61,27 @@ protected: void updateColor(const QVector4D &c); void updateTextureScale(const QVector2D &ts); - float m_fontScale; - float m_matrixScale; + float m_fontScale = 1.0; + float m_matrixScale = 1.0; - int m_matrix_id; - int m_textureScale_id; - int m_alphaMin_id; - int m_alphaMax_id; - int m_color_id; + int m_matrix_id = -1; + int m_textureScale_id = -1; + int m_alphaMin_id = -1; + int m_alphaMax_id = -1; + int m_color_id = -1; QVector2D m_lastTextureScale; QVector4D m_lastColor; - float m_lastAlphaMin; - float m_lastAlphaMax; + float m_lastAlphaMin = -1; + float m_lastAlphaMax = -1; }; char const *const *QSGDistanceFieldTextMaterialShader::attributeNames() const { - static char const *const attr[] = { "vCoord", "tCoord", 0 }; + static char const *const attr[] = { "vCoord", "tCoord", nullptr }; return attr; } QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader() - : QSGMaterialShader(), - m_fontScale(1.0) - , m_matrixScale(1.0) - , m_matrix_id(-1) - , m_textureScale_id(-1) - , m_alphaMin_id(-1) - , m_alphaMax_id(-1) - , m_color_id(-1) - , m_lastAlphaMin(-1) - , m_lastAlphaMax(-1) { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldtext.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldtext.frag")); @@ -166,13 +156,13 @@ void QSGDistanceFieldTextMaterialShader::initialize() void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) { - Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); + Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect); QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect); bool updated = material->updateTextureSize(); - if (oldMaterial == 0 + if (oldMaterial == nullptr || material->color() != oldMaterial->color() || state.isOpacityDirty()) { QVector4D color = material->color(); @@ -181,7 +171,7 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q } bool updateRange = false; - if (oldMaterial == 0 + if (oldMaterial == nullptr || material->fontScale() != oldMaterial->fontScale()) { m_fontScale = material->fontScale(); updateRange = true; @@ -198,12 +188,12 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q Q_ASSERT(material->glyphCache()); if (updated - || oldMaterial == 0 + || oldMaterial == nullptr || oldMaterial->texture()->textureId != material->texture()->textureId) { updateTextureScale(QVector2D(1.0 / material->textureSize().width(), 1.0 / material->textureSize().height())); - QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); + QOpenGLFunctions *funcs = state.context()->functions(); funcs->glBindTexture(GL_TEXTURE_2D, material->texture()->textureId); if (updated) { @@ -218,8 +208,8 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q } QSGDistanceFieldTextMaterial::QSGDistanceFieldTextMaterial() - : m_glyph_cache(0) - , m_texture(0) + : m_glyph_cache(nullptr) + , m_texture(nullptr) , m_fontScale(1.0) { setFlag(Blending | RequiresDeterminant, true); @@ -288,12 +278,11 @@ public: protected: void initialize() override; - int m_styleColor_id; + int m_styleColor_id = -1; }; DistanceFieldStyledTextMaterialShader::DistanceFieldStyledTextMaterialShader() : QSGDistanceFieldTextMaterialShader() - , m_styleColor_id(-1) { } @@ -310,7 +299,7 @@ void DistanceFieldStyledTextMaterialShader::updateState(const RenderState &state QSGDistanceFieldStyledTextMaterial *material = static_cast<QSGDistanceFieldStyledTextMaterial *>(newEffect); QSGDistanceFieldStyledTextMaterial *oldMaterial = static_cast<QSGDistanceFieldStyledTextMaterial *>(oldEffect); - if (oldMaterial == 0 + if (oldMaterial == nullptr || material->styleColor() != oldMaterial->styleColor() || (state.isOpacityDirty())) { QVector4D color = material->styleColor(); @@ -358,14 +347,12 @@ protected: void updateOutlineAlphaRange(int dfRadius); - int m_outlineAlphaMax0_id; - int m_outlineAlphaMax1_id; + int m_outlineAlphaMax0_id = -1; + int m_outlineAlphaMax1_id = -1; }; DistanceFieldOutlineTextMaterialShader::DistanceFieldOutlineTextMaterialShader() : DistanceFieldStyledTextMaterialShader() - , m_outlineAlphaMax0_id(-1) - , m_outlineAlphaMax1_id(-1) { setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldoutlinetext.frag")); } @@ -398,7 +385,7 @@ void DistanceFieldOutlineTextMaterialShader::updateState(const RenderState &stat QSGDistanceFieldOutlineTextMaterial *material = static_cast<QSGDistanceFieldOutlineTextMaterial *>(newEffect); QSGDistanceFieldOutlineTextMaterial *oldMaterial = static_cast<QSGDistanceFieldOutlineTextMaterial *>(oldEffect); - if (oldMaterial == 0 + if (oldMaterial == nullptr || material->fontScale() != oldMaterial->fontScale() || state.isMatrixDirty()) updateOutlineAlphaRange(material->glyphCache()->distanceFieldRadius()); @@ -438,12 +425,11 @@ protected: void updateShift(qreal fontScale, const QPointF& shift); - int m_shift_id; + int m_shift_id = -1; }; DistanceFieldShiftedStyleTextMaterialShader::DistanceFieldShiftedStyleTextMaterialShader() : DistanceFieldStyledTextMaterialShader() - , m_shift_id(-1) { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldshiftedtext.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldshiftedtext.frag")); @@ -462,7 +448,7 @@ void DistanceFieldShiftedStyleTextMaterialShader::updateState(const RenderState QSGDistanceFieldShiftedStyleTextMaterial *material = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(newEffect); QSGDistanceFieldShiftedStyleTextMaterial *oldMaterial = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(oldEffect); - if (oldMaterial == 0 + if (oldMaterial == nullptr || oldMaterial->fontScale() != material->fontScale() || oldMaterial->shift() != material->shift() || oldMaterial->textureSize() != material->textureSize()) { @@ -516,14 +502,12 @@ public: void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; private: - int m_fontScale_id; - int m_vecDelta_id; + int m_fontScale_id = -1; + int m_vecDelta_id = -1; }; QSGHiQSubPixelDistanceFieldTextMaterialShader::QSGHiQSubPixelDistanceFieldTextMaterialShader() : QSGDistanceFieldTextMaterialShader() - , m_fontScale_id(-1) - , m_vecDelta_id(-1) { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag")); @@ -550,19 +534,19 @@ void QSGHiQSubPixelDistanceFieldTextMaterialShader::deactivate() void QSGHiQSubPixelDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) { - Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); + Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect); QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect); - if (oldMaterial == 0 || material->color() != oldMaterial->color()) { + if (oldMaterial == nullptr || material->color() != oldMaterial->color()) { QVector4D c = material->color(); state.context()->functions()->glBlendColor(c.x(), c.y(), c.z(), 1.0f); } - if (oldMaterial == 0 || material->fontScale() != oldMaterial->fontScale()) + if (oldMaterial == nullptr || material->fontScale() != oldMaterial->fontScale()) program()->setUniformValue(m_fontScale_id, GLfloat(material->fontScale())); - if (oldMaterial == 0 || state.isMatrixDirty()) { + if (oldMaterial == nullptr || state.isMatrixDirty()) { int viewportWidth = state.viewportRect().width(); QMatrix4x4 mat = state.combinedMatrix().inverted(); program()->setUniformValue(m_vecDelta_id, mat.column(0) * (qreal(2) / viewportWidth)); diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index 58450d7a50..9e5cc27cd8 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -76,7 +76,7 @@ QT_BEGIN_NAMESPACE extern bool qsg_useConsistentTiming(); extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); #if QT_CONFIG(opengl) -/*! +/* expectations for this manager to work: - one opengl context to render multiple windows - OpenGL pipeline will not block for vsync in swap @@ -88,7 +88,7 @@ extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_ DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP); DEFINE_BOOL_CONFIG_OPTION(qmlForceThreadedRenderer, QML_FORCE_THREADED_RENDERER); // Might trigger graphics driver threading bugs, use at own risk #endif -QSGRenderLoop *QSGRenderLoop::s_instance = 0; +QSGRenderLoop *QSGRenderLoop::s_instance = nullptr; QSGRenderLoop::~QSGRenderLoop() { @@ -107,11 +107,11 @@ void QSGRenderLoop::cleanup() QQuickWindowPrivate *wd = QQuickWindowPrivate::get(w); if (wd->windowManager == s_instance) { s_instance->windowDestroyed(w); - wd->windowManager = 0; + wd->windowManager = nullptr; } } delete s_instance; - s_instance = 0; + s_instance = nullptr; } /*! @@ -155,7 +155,7 @@ public: void releaseResources(QQuickWindow *) override; - QAnimationDriver *animationDriver() const override { return 0; } + QAnimationDriver *animationDriver() const override { return nullptr; } QSGContext *sceneGraphContext() const override; QSGRenderContext *createRenderContext(QSGContext *) const override { return rc; } @@ -282,7 +282,7 @@ void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window, } #if QT_CONFIG(opengl) QSGGuiThreadRenderLoop::QSGGuiThreadRenderLoop() - : gl(0) + : gl(nullptr) { if (qsg_useConsistentTiming()) { QUnifiedTimer::instance(true)->setConsistentTiming(true); @@ -334,7 +334,7 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window) current = gl->makeCurrent(surface); } if (Q_UNLIKELY(!current)) - qCDebug(QSG_LOG_RENDERLOOP) << "cleanup without an OpenGL context"; + qCDebug(QSG_LOG_RENDERLOOP, "cleanup without an OpenGL context"); #if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl) QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache(); @@ -344,7 +344,7 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window) if (m_windows.size() == 0) { rc->invalidate(); delete gl; - gl = 0; + gl = nullptr; } else if (gl && window == gl->surface() && current) { gl->doneCurrent(); } @@ -371,7 +371,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) if (!gl->create()) { const bool isEs = gl->isOpenGLES(); delete gl; - gl = 0; + gl = nullptr; handleContextCreationFailure(window, isEs); } else { cd->fireOpenGLContextCreated(gl); diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 4a712d3cdd..8262708320 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -115,7 +115,7 @@ QT_BEGIN_NAMESPACE -#define QSG_RT_PAD " (RT)" +#define QSG_RT_PAD " (RT) %s" static inline int qsgrl_animation_interval() { qreal refreshRate = QGuiApplication::primaryScreen()->refreshRate(); @@ -167,7 +167,7 @@ template <typename T> T *windowFor(const QList<T> &list, QQuickWindow *window) if (t.window == window) return const_cast<T *>(&t); } - return 0; + return nullptr; } @@ -270,13 +270,13 @@ class QSGRenderThread : public QThread public: QSGRenderThread(QSGThreadedRenderLoop *w, QSGRenderContext *renderContext) : wm(w) - , gl(0) - , animatorDriver(0) + , gl(nullptr) + , animatorDriver(nullptr) , pendingUpdate(0) , sleeping(false) , syncResultedInChanges(false) , active(false) - , window(0) + , window(nullptr) , stopEventProcessing(false) { sgrc = static_cast<QSGDefaultRenderContext *>(renderContext); @@ -315,7 +315,7 @@ public: public slots: void sceneGraphChanged() { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "sceneGraphChanged"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "sceneGraphChanged"); syncResultedInChanges = true; } @@ -358,15 +358,15 @@ bool QSGRenderThread::event(QEvent *e) switch ((int) e->type()) { case WM_Obscure: { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_Obscure"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "WM_Obscure"); Q_ASSERT(!window || window == static_cast<WMWindowEvent *>(e)->window); mutex.lock(); if (window) { QQuickWindowPrivate::get(window)->fireAboutToStop(); - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- window removed"; - window = 0; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- window removed"); + window = nullptr; } waitCondition.wakeOne(); mutex.unlock(); @@ -374,7 +374,7 @@ bool QSGRenderThread::event(QEvent *e) return true; } case WM_RequestSync: { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_RequestSync"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "WM_RequestSync"); WMSyncEvent *se = static_cast<WMSyncEvent *>(e); if (sleeping) stopEventProcessing = true; @@ -383,33 +383,33 @@ bool QSGRenderThread::event(QEvent *e) pendingUpdate |= SyncRequest; if (se->syncInExpose) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- triggered from expose"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- triggered from expose"); pendingUpdate |= ExposeRequest; } if (se->forceRenderPass) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- repaint regardless"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- repaint regardless"); pendingUpdate |= RepaintRequest; } return true; } case WM_TryRelease: { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_TryRelease"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "WM_TryRelease"); mutex.lock(); wm->m_lockedForSync = true; WMTryReleaseEvent *wme = static_cast<WMTryReleaseEvent *>(e); if (!window || wme->inDestructor) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- setting exit flag and invalidating OpenGL"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- setting exit flag and invalidating OpenGL"); invalidateOpenGL(wme->window, wme->inDestructor, wme->fallbackSurface); active = gl; Q_ASSERT_X(!wme->inDestructor || !active, "QSGRenderThread::invalidateOpenGL()", "Thread's active state is not set to false when shutting down"); if (sleeping) stopEventProcessing = true; } else { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- not releasing because window is still active"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- not releasing because window is still active"); if (window) { QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); if (d->renderer) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- requesting renderer to release cached resources"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- requesting renderer to release cached resources"); d->renderer->releaseCachedResources(); } } @@ -421,7 +421,7 @@ bool QSGRenderThread::event(QEvent *e) } case WM_Grab: { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_Grab"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "WM_Grab"); WMGrabEvent *ce = static_cast<WMGrabEvent *>(e); Q_ASSERT(ce->window); Q_ASSERT(ce->window == window || !window); @@ -429,41 +429,41 @@ bool QSGRenderThread::event(QEvent *e) if (ce->window) { gl->makeCurrent(ce->window); - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- sync scene graph"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- sync scene graph"); QQuickWindowPrivate *d = QQuickWindowPrivate::get(ce->window); d->syncSceneGraph(); sgrc->endSync(); - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- rendering scene graph"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- rendering scene graph"); QQuickWindowPrivate::get(ce->window)->renderSceneGraph(ce->window->size()); - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- grabbing result"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- grabbing result"); bool alpha = ce->window->format().alphaBufferSize() > 0 && ce->window->color().alpha() != 255; *ce->image = qt_gl_read_framebuffer(windowSize * ce->window->effectiveDevicePixelRatio(), alpha, alpha); ce->image->setDevicePixelRatio(ce->window->effectiveDevicePixelRatio()); } - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- waking gui to handle result"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- waking gui to handle result"); waitCondition.wakeOne(); mutex.unlock(); return true; } case WM_PostJob: { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_PostJob"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "WM_PostJob"); WMJobEvent *ce = static_cast<WMJobEvent *>(e); Q_ASSERT(ce->window == window); if (window) { gl->makeCurrent(window); ce->job->run(); delete ce->job; - ce->job = 0; - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- job done"; + ce->job = nullptr; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- job done"); } return true; } case WM_RequestRepaint: - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_RequestPaint"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "WM_RequestPaint"); // When GUI posts this event, it is followed by a polishAndSync, so we mustn't // exit the event loop yet. pendingUpdate |= RepaintRequest; @@ -477,13 +477,13 @@ bool QSGRenderThread::event(QEvent *e) void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor, QOffscreenSurface *fallback) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "invalidateOpenGL()"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "invalidateOpenGL()"); if (!gl) return; if (!window) { - qCWarning(QSG_LOG_RENDERLOOP()) << "QSGThreadedRenderLoop:QSGRenderThread: no window to make current..."; + qCWarning(QSG_LOG_RENDERLOOP, "QSGThreadedRenderLoop:QSGRenderThread: no window to make current..."); return; } @@ -493,7 +493,7 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor, bool current = gl->makeCurrent(fallback ? static_cast<QSurface *>(fallback) : static_cast<QSurface *>(window)); if (Q_UNLIKELY(!current)) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- cleanup without an OpenGL context"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- cleanup without an OpenGL context"); } QQuickWindowPrivate *dd = QQuickWindowPrivate::get(window); @@ -506,7 +506,7 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor, if (wipeSG) { dd->cleanupNodesOnShutdown(); } else { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- persistent SG, avoiding cleanup"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- persistent SG, avoiding cleanup"); if (current) gl->doneCurrent(); return; @@ -514,29 +514,29 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor, sgrc->invalidate(); QCoreApplication::processEvents(); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); if (inDestructor) delete dd->animationController; if (current) gl->doneCurrent(); - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- invalidating scene graph"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- invalidating scene graph"); if (wipeGL) { delete gl; - gl = 0; - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- invalidated OpenGL"; + gl = nullptr; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- invalidated OpenGL"); } else { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- persistent GL, avoiding cleanup"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- persistent GL, avoiding cleanup"); } } -/*! +/* Enters the mutex lock to make sure GUI is blocking and performs sync, then wakes GUI. */ void QSGRenderThread::sync(bool inExpose) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "sync()"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "sync()"); mutex.lock(); Q_ASSERT_X(wm->m_lockedForSync, "QSGRenderThread::sync()", "sync triggered on bad terms as gui is not already locked..."); @@ -554,7 +554,7 @@ void QSGRenderThread::sync(bool inExpose) } if (current) { QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); - bool hadRenderer = d->renderer != 0; + bool hadRenderer = d->renderer != nullptr; // If the scene graph was touched since the last sync() make sure it sends the // changed signal. if (d->renderer) @@ -562,7 +562,7 @@ void QSGRenderThread::sync(bool inExpose) d->syncSceneGraph(); sgrc->endSync(); if (!hadRenderer && d->renderer) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- renderer was created"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- renderer was created"); syncResultedInChanges = true; connect(d->renderer, SIGNAL(sceneGraphChanged()), this, SLOT(sceneGraphChanged()), Qt::DirectConnection); } @@ -570,13 +570,13 @@ void QSGRenderThread::sync(bool inExpose) // Process deferred deletes now, directly after the sync as // deleteLater on the GUI must now also have resulted in SG changes // and the delete is a safe operation. - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); } else { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- window has bad size, sync aborted"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- window has bad size, sync aborted"); } if (!inExpose) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- sync complete, waking Gui"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- sync complete, waking Gui"); waitCondition.wakeOne(); mutex.unlock(); } @@ -594,7 +594,7 @@ void QSGRenderThread::syncAndRender() QElapsedTimer waitTimer; waitTimer.start(); - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "syncAndRender()"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "syncAndRender()"); syncResultedInChanges = false; QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); @@ -605,7 +605,7 @@ void QSGRenderThread::syncAndRender() pendingUpdate = 0; if (syncRequested) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- updatePending, doing sync"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- updatePending, doing sync"); sync(exposeRequested); } #ifndef QSG_NO_RENDER_TIMING @@ -616,14 +616,14 @@ void QSGRenderThread::syncAndRender() QQuickProfiler::SceneGraphRenderLoopSync); if (!syncResultedInChanges && !repaintRequested && sgrc->isValid()) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- no changes, render aborted"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- no changes, render aborted"); int waitTime = vsyncDelta - (int) waitTimer.elapsed(); if (waitTime > 0) msleep(waitTime); return; } - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- rendering started"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- rendering started"); if (animatorDriver->isRunning()) { @@ -653,10 +653,10 @@ void QSGRenderThread::syncAndRender() } else { Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphRenderLoopFrame, QQuickProfiler::SceneGraphRenderLoopSync, 1); - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- window not ready, skipping render"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- window not ready, skipping render"); } - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- rendering done"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- rendering done"); // Though it would be more correct to put this block directly after // fireFrameSwapped in the if (current) branch above, we don't do @@ -664,7 +664,7 @@ void QSGRenderThread::syncAndRender() // has started rendering with a bad window, causing makeCurrent to // fail or if the window has a bad size. if (exposeRequested) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- wake Gui after initial expose"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- wake Gui after initial expose"); waitCondition.wakeOne(); mutex.unlock(); } @@ -692,31 +692,31 @@ void QSGRenderThread::postEvent(QEvent *e) void QSGRenderThread::processEvents() { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "--- begin processEvents()"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "--- begin processEvents()"); while (eventQueue.hasMoreEvents()) { QEvent *e = eventQueue.takeEvent(false); event(e); delete e; } - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "--- done processEvents()"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "--- done processEvents()"); } void QSGRenderThread::processEventsAndWaitForMore() { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "--- begin processEventsAndWaitForMore()"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "--- begin processEventsAndWaitForMore()"); stopEventProcessing = false; while (!stopEventProcessing) { QEvent *e = eventQueue.takeEvent(true); event(e); delete e; } - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "--- done processEventsAndWaitForMore()"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "--- done processEventsAndWaitForMore()"); } void QSGRenderThread::run() { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "run()"; - animatorDriver = sgrc->sceneGraphContext()->createAnimationDriver(0); + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "run()"); + animatorDriver = sgrc->sceneGraphContext()->createAnimationDriver(nullptr); animatorDriver->install(); if (QQmlDebugConnector::service<QQmlProfilerService>()) QQuickProfiler::registerAnimationCallback(); @@ -733,7 +733,7 @@ void QSGRenderThread::run() QCoreApplication::processEvents(); if (active && (pendingUpdate == 0 || !window)) { - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "done drawing, sleep..."; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "done drawing, sleep..."); sleeping = true; processEventsAndWaitForMore(); sleeping = false; @@ -742,10 +742,10 @@ void QSGRenderThread::run() Q_ASSERT_X(!gl, "QSGRenderThread::run()", "The OpenGL context should be cleaned up before exiting the render thread..."); - qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "run() completed"; + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "run() completed"); delete animatorDriver; - animatorDriver = 0; + animatorDriver = nullptr; sgrc->moveToThread(wm->thread()); moveToThread(wm->thread()); @@ -809,7 +809,7 @@ bool QSGThreadedRenderLoop::interleaveIncubation() const void QSGThreadedRenderLoop::animationStarted() { - qCDebug(QSG_LOG_RENDERLOOP) << "- animationStarted()"; + qCDebug(QSG_LOG_RENDERLOOP, "- animationStarted()"); startOrStopAnimationTimer(); for (int i=0; i<m_windows.size(); ++i) @@ -818,7 +818,7 @@ void QSGThreadedRenderLoop::animationStarted() void QSGThreadedRenderLoop::animationStopped() { - qCDebug(QSG_LOG_RENDERLOOP) << "- animationStopped()"; + qCDebug(QSG_LOG_RENDERLOOP, "- animationStopped()"); startOrStopAnimationTimer(); } @@ -826,7 +826,7 @@ void QSGThreadedRenderLoop::animationStopped() void QSGThreadedRenderLoop::startOrStopAnimationTimer() { int exposedWindows = 0; - const Window *theOne = 0; + const Window *theOne = nullptr; for (int i=0; i<m_windows.size(); ++i) { const Window &w = m_windows.at(i); if (w.window->isVisible() && w.window->isExposed()) { @@ -836,14 +836,14 @@ void QSGThreadedRenderLoop::startOrStopAnimationTimer() } if (m_animation_timer != 0 && (exposedWindows == 1 || !m_animation_driver->isRunning())) { - qCDebug(QSG_LOG_RENDERLOOP) << "*** Stopping animation timer"; + qCDebug(QSG_LOG_RENDERLOOP, "*** Stopping animation timer"); killTimer(m_animation_timer); m_animation_timer = 0; // If animations are running, make sure we keep on animating if (m_animation_driver->isRunning()) maybePostPolishRequest(const_cast<Window *>(theOne)); } else if (m_animation_timer == 0 && exposedWindows != 1 && m_animation_driver->isRunning()) { - qCDebug(QSG_LOG_RENDERLOOP) << "*** Starting animation timer"; + qCDebug(QSG_LOG_RENDERLOOP, "*** Starting animation timer"); m_animation_timer = startTimer(qsgrl_animation_interval()); } } @@ -870,7 +870,7 @@ void QSGThreadedRenderLoop::hide(QQuickWindow *window) } -/*! +/* If the window is first hide it, then perform a complete cleanup with releaseResources which will take down the GL context and exit the rendering thread. @@ -920,7 +920,7 @@ void QSGThreadedRenderLoop::exposureChanged(QQuickWindow *window) } } -/*! +/* Will post an event to the render thread that this window should start to render. */ @@ -930,7 +930,7 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window) Window *w = windowFor(m_windows, window); if (!w) { - qCDebug(QSG_LOG_RENDERLOOP) << "- adding window to list"; + qCDebug(QSG_LOG_RENDERLOOP, "- adding window to list"); Window win; win.window = window; win.actualWindowFormat = window->format(); @@ -962,7 +962,7 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window) // Start render thread if it is not running if (!w->thread->isRunning()) { - qCDebug(QSG_LOG_RENDERLOOP) << "- starting render thread"; + qCDebug(QSG_LOG_RENDERLOOP, "- starting render thread"); if (!w->thread->gl) { w->thread->gl = new QOpenGLContext(); @@ -973,7 +973,7 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window) if (!w->thread->gl->create()) { const bool isEs = w->thread->gl->isOpenGLES(); delete w->thread->gl; - w->thread->gl = 0; + w->thread->gl = nullptr; handleContextCreationFailure(w->window, isEs); return; } @@ -981,7 +981,7 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window) QQuickWindowPrivate::get(w->window)->fireOpenGLContextCreated(w->thread->gl); w->thread->gl->moveToThread(w->thread); - qCDebug(QSG_LOG_RENDERLOOP) << "- OpenGL context created"; + qCDebug(QSG_LOG_RENDERLOOP, "- OpenGL context created"); } QQuickAnimatorController *controller = QQuickWindowPrivate::get(w->window)->animationController; @@ -998,16 +998,16 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window) qFatal("Render thread failed to start, aborting application."); } else { - qCDebug(QSG_LOG_RENDERLOOP) << "- render thread already running"; + qCDebug(QSG_LOG_RENDERLOOP, "- render thread already running"); } polishAndSync(w, true); - qCDebug(QSG_LOG_RENDERLOOP) << "- done with handleExposure()"; + qCDebug(QSG_LOG_RENDERLOOP, "- done with handleExposure()"); startOrStopAnimationTimer(); } -/*! +/* This function posts an event to the render thread to remove the window from the list of windowses to render. @@ -1029,7 +1029,7 @@ void QSGThreadedRenderLoop::handleObscurity(Window *w) void QSGThreadedRenderLoop::handleUpdateRequest(QQuickWindow *window) { - qCDebug(QSG_LOG_RENDERLOOP) << "- polish and sync update request"; + qCDebug(QSG_LOG_RENDERLOOP, "- polish and sync update request"); Window *w = windowFor(m_windows, window); if (w) polishAndSync(w); @@ -1042,7 +1042,7 @@ void QSGThreadedRenderLoop::maybeUpdate(QQuickWindow *window) maybeUpdate(w); } -/*! +/* Called whenever the QML scene has changed. Will post an event to ourselves that a sync is needed. */ @@ -1065,7 +1065,7 @@ void QSGThreadedRenderLoop::maybeUpdate(Window *w) // Call this function from the Gui thread later as startTimer cannot be // called from the render thread. if (current == w->thread) { - qCDebug(QSG_LOG_RENDERLOOP) << "- on render thread"; + qCDebug(QSG_LOG_RENDERLOOP, "- on render thread"); w->updateDuringSync = true; return; } @@ -1073,7 +1073,7 @@ void QSGThreadedRenderLoop::maybeUpdate(Window *w) maybePostPolishRequest(w); } -/*! +/* Called when the QQuickWindow should be explicitly repainted. This function can also be called on the render thread when the GUI thread is blocked to keep render thread animations alive. @@ -1105,7 +1105,7 @@ void QSGThreadedRenderLoop::releaseResources(QQuickWindow *window) releaseResources(w, false); } -/*! +/* * Release resources will post an event to the render thread to * free up the SG and GL resources and exists the render thread. */ @@ -1123,15 +1123,15 @@ void QSGThreadedRenderLoop::releaseResources(Window *w, bool inDestructor) // and the OpenGL resources. // QOffscreenSurface must be created on the GUI thread, so we // create it here and pass it on to QSGRenderThread::invalidateGL() - QOffscreenSurface *fallback = 0; + QOffscreenSurface *fallback = nullptr; if (!window->handle()) { - qCDebug(QSG_LOG_RENDERLOOP) << "- using fallback surface"; + qCDebug(QSG_LOG_RENDERLOOP, "- using fallback surface"); fallback = new QOffscreenSurface(); fallback->setFormat(w->actualWindowFormat); fallback->create(); } - qCDebug(QSG_LOG_RENDERLOOP) << "- posting release request to render thread"; + qCDebug(QSG_LOG_RENDERLOOP, "- posting release request to render thread"); w->thread->postEvent(new WMTryReleaseEvent(window, inDestructor, fallback)); w->thread->waitCondition.wait(&w->thread->mutex); delete fallback; @@ -1161,7 +1161,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose) QQuickWindow *window = w->window; if (!w->thread || !w->thread->window) { - qCDebug(QSG_LOG_RENDERLOOP) << "- not exposed, abort"; + qCDebug(QSG_LOG_RENDERLOOP, "- not exposed, abort"); return; } @@ -1170,7 +1170,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose) // The delivery of the event might have caused the window to stop rendering w = windowFor(m_windows, window); if (!w || !w->thread || !w->thread->window) { - qCDebug(QSG_LOG_RENDERLOOP) << "- removed after event flushing, abort"; + qCDebug(QSG_LOG_RENDERLOOP, "- removed after event flushing, abort"); return; } @@ -1196,13 +1196,13 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose) emit window->afterAnimating(); - qCDebug(QSG_LOG_RENDERLOOP) << "- lock for sync"; + qCDebug(QSG_LOG_RENDERLOOP, "- lock for sync"); w->thread->mutex.lock(); m_lockedForSync = true; w->thread->postEvent(new WMSyncEvent(window, inExpose, w->forceRenderPass)); w->forceRenderPass = false; - qCDebug(QSG_LOG_RENDERLOOP) << "- wait for sync"; + qCDebug(QSG_LOG_RENDERLOOP, "- wait for sync"); if (profileFrames) waitTime = timer.nsecsElapsed(); Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync, @@ -1210,7 +1210,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose) w->thread->waitCondition.wait(&w->thread->mutex); m_lockedForSync = false; w->thread->mutex.unlock(); - qCDebug(QSG_LOG_RENDERLOOP) << "- unlock after sync"; + qCDebug(QSG_LOG_RENDERLOOP, "- unlock after sync"); if (profileFrames) syncTime = timer.nsecsElapsed(); @@ -1218,9 +1218,9 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose) QQuickProfiler::SceneGraphPolishAndSyncSync); if (m_animation_timer == 0 && m_animation_driver->isRunning()) { - qCDebug(QSG_LOG_RENDERLOOP) << "- advancing animations"; + qCDebug(QSG_LOG_RENDERLOOP, "- advancing animations"); m_animation_driver->advance(); - qCDebug(QSG_LOG_RENDERLOOP) << "- animations done.."; + qCDebug(QSG_LOG_RENDERLOOP, "- animations done.."); // We need to trigger another sync to keep animations running... maybePostPolishRequest(w); emit timeToIncubate(); @@ -1247,7 +1247,7 @@ bool QSGThreadedRenderLoop::event(QEvent *e) case QEvent::Timer: { QTimerEvent *te = static_cast<QTimerEvent *>(e); if (te->timerId() == m_animation_timer) { - qCDebug(QSG_LOG_RENDERLOOP) << "- ticking non-visual timer"; + qCDebug(QSG_LOG_RENDERLOOP, "- ticking non-visual timer"); m_animation_driver->advance(); emit timeToIncubate(); return true; @@ -1286,25 +1286,25 @@ QImage QSGThreadedRenderLoop::grab(QQuickWindow *window) if (!window->handle()) window->create(); - qCDebug(QSG_LOG_RENDERLOOP) << "- polishing items"; + qCDebug(QSG_LOG_RENDERLOOP, "- polishing items"); QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); d->polishItems(); QImage result; w->thread->mutex.lock(); m_lockedForSync = true; - qCDebug(QSG_LOG_RENDERLOOP) << "- posting grab event"; + qCDebug(QSG_LOG_RENDERLOOP, "- posting grab event"); w->thread->postEvent(new WMGrabEvent(window, &result)); w->thread->waitCondition.wait(&w->thread->mutex); m_lockedForSync = false; w->thread->mutex.unlock(); - qCDebug(QSG_LOG_RENDERLOOP) << "- grab complete"; + qCDebug(QSG_LOG_RENDERLOOP, "- grab complete"); return result; } -/*! +/* * Posts a new job event to the render thread. * Returns true if posting succeeded. */ diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp index e33f31f2ac..3b2737b8e1 100644 --- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp +++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp @@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); -#define RLDEBUG(x) qCDebug(QSG_LOG_RENDERLOOP) << x; +#define RLDEBUG(x) qCDebug(QSG_LOG_RENDERLOOP, x) static QElapsedTimer qsg_render_timer; #define QSG_LOG_TIME_SAMPLE(sampleName) \ @@ -78,7 +78,7 @@ static QElapsedTimer qsg_render_timer; QSGWindowsRenderLoop::QSGWindowsRenderLoop() - : m_gl(0) + : m_gl(nullptr) , m_sg(QSGContext::createDefaultContext()) , m_updateTimer(0) , m_animationTimer(0) @@ -117,7 +117,7 @@ QSGWindowsRenderLoop::WindowData *QSGWindowsRenderLoop::windowData(QQuickWindow if (wd.window == window) return &wd; } - return 0; + return nullptr; } void QSGWindowsRenderLoop::maybePostUpdateTimer() @@ -158,7 +158,7 @@ void QSGWindowsRenderLoop::stopped() void QSGWindowsRenderLoop::show(QQuickWindow *window) { RLDEBUG("show"); - if (windowData(window) != 0) + if (windowData(window) != nullptr) return; // This happens before the platform window is shown, but after @@ -178,7 +178,7 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window) if (!created) { const bool isEs = m_gl->isOpenGLES(); delete m_gl; - m_gl = 0; + m_gl = nullptr; handleContextCreationFailure(window, isEs); return; } @@ -243,7 +243,7 @@ void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window) current = m_gl->makeCurrent(surface); } if (Q_UNLIKELY(!current)) - qCDebug(QSG_LOG_RENDERLOOP) << "cleanup without an OpenGL context"; + RLDEBUG("cleanup without an OpenGL context"); #if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl) QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache(); @@ -253,7 +253,7 @@ void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window) if (m_windows.size() == 0) { d->context->invalidate(); delete m_gl; - m_gl = 0; + m_gl = nullptr; } else if (m_gl && current) { m_gl->doneCurrent(); } @@ -272,7 +272,7 @@ bool QSGWindowsRenderLoop::anyoneShowing() const void QSGWindowsRenderLoop::exposureChanged(QQuickWindow *window) { - if (windowData(window) == 0) + if (windowData(window) == nullptr) return; if (window->isExposed() && window->isVisible()) { diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index b5c72f521c..4fa3e7b6bf 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -1,4 +1,4 @@ -DEFINES += QSG_SEPARATE_INDEX_BUFFER +# DEFINES += QSG_SEPARATE_INDEX_BUFFER # DEFINES += QSG_DISTANCEFIELD_CACHE_DEBUG # Core API @@ -230,8 +230,15 @@ SOURCES += \ qtConfig(opengl(es1|es2)?) { HEADERS += \ - $$PWD/compressedtexture/qsgpkmhandler_p.h + $$PWD/compressedtexture/qsgcompressedatlastexture_p.h \ + $$PWD/compressedtexture/qsgcompressedtexture_p.h \ + $$PWD/compressedtexture/qsgtexturefilehandler_p.h \ + $$PWD/compressedtexture/qsgpkmhandler_p.h \ + $$PWD/compressedtexture/qsgktxhandler_p.h SOURCES += \ - $$PWD/compressedtexture/qsgpkmhandler.cpp + $$PWD/compressedtexture/qsgcompressedatlastexture.cpp \ + $$PWD/compressedtexture/qsgcompressedtexture.cpp \ + $$PWD/compressedtexture/qsgpkmhandler.cpp \ + $$PWD/compressedtexture/qsgktxhandler.cpp } diff --git a/src/quick/scenegraph/util/qsgareaallocator.cpp b/src/quick/scenegraph/util/qsgareaallocator.cpp index 67a9fa285a..cd270a1d63 100644 --- a/src/quick/scenegraph/util/qsgareaallocator.cpp +++ b/src/quick/scenegraph/util/qsgareaallocator.cpp @@ -72,8 +72,8 @@ struct QSGAreaAllocatorNode QSGAreaAllocatorNode::QSGAreaAllocatorNode(QSGAreaAllocatorNode *parent) : parent(parent) - , left(0) - , right(0) + , left(nullptr) + , right(nullptr) , isOccupied(false) { } @@ -86,14 +86,14 @@ QSGAreaAllocatorNode::~QSGAreaAllocatorNode() bool QSGAreaAllocatorNode::isLeaf() { - Q_ASSERT((left != 0) == (right != 0)); + Q_ASSERT((left != nullptr) == (right != nullptr)); return !left; } QSGAreaAllocator::QSGAreaAllocator(const QSize &size) : m_size(size) { - m_root = new QSGAreaAllocatorNode(0); + m_root = new QSGAreaAllocatorNode(nullptr); } QSGAreaAllocator::~QSGAreaAllocator() @@ -179,13 +179,13 @@ bool QSGAreaAllocator::deallocateInNode(const QPoint &pos, QSGAreaAllocatorNode void QSGAreaAllocator::mergeNodeWithNeighbors(QSGAreaAllocatorNode *node) { bool done = false; - QSGAreaAllocatorNode *parent = 0; - QSGAreaAllocatorNode *current = 0; + QSGAreaAllocatorNode *parent = nullptr; + QSGAreaAllocatorNode *current = nullptr; QSGAreaAllocatorNode *sibling; while (!done) { Q_ASSERT(node->isLeaf()); Q_ASSERT(!node->isOccupied); - if (node->parent == 0) + if (node->parent == nullptr) return; // No neighbours. SplitType splitType = SplitType(node->parent->splitType); @@ -238,7 +238,7 @@ void QSGAreaAllocator::mergeNodeWithNeighbors(QSGAreaAllocatorNode *node) } sibling->parent = parent->parent; *nodeRef = sibling; - parent->left = parent->right = 0; + parent->left = parent->right = nullptr; delete parent; delete neighbor; done = false; @@ -276,7 +276,7 @@ void QSGAreaAllocator::mergeNodeWithNeighbors(QSGAreaAllocatorNode *node) } sibling->parent = parent->parent; *nodeRef = sibling; - parent->left = parent->right = 0; + parent->left = parent->right = nullptr; delete parent; delete neighbor; done = false; diff --git a/src/quick/scenegraph/util/qsgareaallocator_p.h b/src/quick/scenegraph/util/qsgareaallocator_p.h index aa40ff0a6e..8bc05a5a5b 100644 --- a/src/quick/scenegraph/util/qsgareaallocator_p.h +++ b/src/quick/scenegraph/util/qsgareaallocator_p.h @@ -67,7 +67,7 @@ public: QRect allocate(const QSize &size); bool deallocate(const QRect &rect); - bool isEmpty() const { return m_root == 0; } + bool isEmpty() const { return m_root == nullptr; } QSize size() const { return m_size; } private: bool allocateInNode(const QSize &size, QPoint &result, const QRect ¤tRect, QSGAreaAllocatorNode *node); diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index 22f0b13f46..7608a81ddc 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -44,6 +44,7 @@ #include <QtCore/QtMath> #include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLTexture> #include <QtGui/QOpenGLFunctions> #include <QtGui/QGuiApplication> #include <QtGui/QScreen> @@ -51,7 +52,10 @@ #include <QtGui/QWindow> #include <QtGui/qpa/qplatformnativeinterface.h> +#include <private/qqmlglobal_p.h> #include <private/qsgtexture_p.h> +#include <private/qsgcompressedtexture_p.h> +#include <private/qsgcompressedatlastexture_p.h> #include <private/qquickprofiler_p.h> @@ -65,11 +69,13 @@ int qt_sg_envInt(const char *name, int defaultValue); static QElapsedTimer qsg_renderer_timer; +DEFINE_BOOL_CONFIG_OPTION(qsgEnableCompressedAtlas, QSG_ENABLE_COMPRESSED_ATLAS) + namespace QSGAtlasTexture { Manager::Manager() - : m_atlas(0) + : m_atlas(nullptr) { QOpenGLContext *gl = QOpenGLContext::currentContext(); Q_ASSERT(gl); @@ -99,7 +105,8 @@ Manager::Manager() Manager::~Manager() { - Q_ASSERT(m_atlas == 0); + Q_ASSERT(m_atlas == nullptr); + Q_ASSERT(m_atlases.isEmpty()); } void Manager::invalidate() @@ -107,13 +114,21 @@ void Manager::invalidate() if (m_atlas) { m_atlas->invalidate(); m_atlas->deleteLater(); - m_atlas = 0; + m_atlas = nullptr; + } + + QHash<unsigned int, QSGCompressedAtlasTexture::Atlas*>::iterator i = m_atlases.begin(); + while (i != m_atlases.end()) { + i.value()->invalidate(); + i.value()->deleteLater(); + ++i; } + m_atlases.clear(); } QSGTexture *Manager::create(const QImage &image, bool hasAlphaChannel) { - Texture *t = 0; + Texture *t = nullptr; if (image.width() < m_atlas_size_limit && image.height() < m_atlas_size_limit) { if (!m_atlas) m_atlas = new Atlas(m_atlas_size); @@ -125,13 +140,147 @@ QSGTexture *Manager::create(const QImage &image, bool hasAlphaChannel) return t; } -Atlas::Atlas(const QSize &size) +QSGTexture *Manager::create(const QSGCompressedTextureFactory *factory) +{ + QSGTexture *t = nullptr; + if (!qsgEnableCompressedAtlas() || !factory->m_textureData || !factory->m_textureData->isValid()) + return t; + + // TODO: further abstract the atlas and remove this restriction + unsigned int format = factory->m_textureData->format; + switch (format) { + case QOpenGLTexture::RGB8_ETC1: + case QOpenGLTexture::RGB8_ETC2: + case QOpenGLTexture::RGBA8_ETC2_EAC: + case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2: + break; + default: + return t; + } + + QSize size = factory->m_textureData->size; + if (size.width() < m_atlas_size_limit && size.height() < m_atlas_size_limit) { + QHash<unsigned int, QSGCompressedAtlasTexture::Atlas*>::iterator i = m_atlases.find(format); + if (i == m_atlases.end()) + i = m_atlases.insert(format, new QSGCompressedAtlasTexture::Atlas(m_atlas_size, format)); + // must be multiple of 4 + QSize paddedSize(((size.width() + 3) / 4) * 4, ((size.height() + 3) / 4) * 4); + QByteArray data = factory->m_textureData->data; + t = i.value()->create(data, factory->m_textureData->sizeInBytes(), factory->m_textureData->dataOffset, size, paddedSize); + } + return t; +} + +AtlasBase::AtlasBase(const QSize &size) : m_allocator(size) , m_texture_id(0) , m_size(size) - , m_atlas_transient_image_threshold(0) , m_allocated(false) { +} + +AtlasBase::~AtlasBase() +{ + Q_ASSERT(!m_texture_id); +} + +void AtlasBase::invalidate() +{ + if (m_texture_id && QOpenGLContext::currentContext()) + QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id); + m_texture_id = 0; +} + +int AtlasBase::textureId() const +{ + if (!m_texture_id) { + Q_ASSERT(QOpenGLContext::currentContext()); + QOpenGLContext::currentContext()->functions()->glGenTextures(1, &const_cast<AtlasBase *>(this)->m_texture_id); + } + + return m_texture_id; +} + +void AtlasBase::bind(QSGTexture::Filtering filtering) +{ + QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); + if (!m_allocated) { + m_allocated = true; + + while (funcs->glGetError() != GL_NO_ERROR) ; + + funcs->glGenTextures(1, &m_texture_id); + funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#if !defined(QT_OPENGL_ES_2) + if (!QOpenGLContext::currentContext()->isOpenGLES()) + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); +#endif + generateTexture(); + + GLenum errorCode = funcs->glGetError(); + if (errorCode == GL_OUT_OF_MEMORY) { + qDebug("QSGTextureAtlas: texture atlas allocation failed, out of memory"); + funcs->glDeleteTextures(1, &m_texture_id); + m_texture_id = 0; + } else if (errorCode != GL_NO_ERROR) { + qDebug("QSGTextureAtlas: texture atlas allocation failed, code=%x", errorCode); + funcs->glDeleteTextures(1, &m_texture_id); + m_texture_id = 0; + } + } else { + funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id); + } + + if (m_texture_id == 0) + return; + + // Upload all pending images.. + for (int i=0; i<m_pending_uploads.size(); ++i) { + + bool profileFrames = QSG_LOG_TIME_TEXTURE().isDebugEnabled(); + if (profileFrames) + qsg_renderer_timer.start(); + + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphTexturePrepare); + + // Skip bind, convert, swizzle; they're irrelevant + Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphTexturePrepare, + QQuickProfiler::SceneGraphTexturePrepareStart, 3); + + uploadPendingTexture(i); + + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare, + QQuickProfiler::SceneGraphTexturePrepareUpload); + + // Skip mipmap; unused + Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphTexturePrepare, + QQuickProfiler::SceneGraphTexturePrepareUpload, 1); + Q_QUICK_SG_PROFILE_REPORT(QQuickProfiler::SceneGraphTexturePrepare, + QQuickProfiler::SceneGraphTexturePrepareMipmap); + } + + GLenum f = filtering == QSGTexture::Nearest ? GL_NEAREST : GL_LINEAR; + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, f); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, f); + + m_pending_uploads.clear(); +} + +void AtlasBase::remove(TextureBase *t) +{ + QRect atlasRect = t->atlasSubRect(); + m_allocator.deallocate(atlasRect); + m_pending_uploads.removeOne(t); +} + +Atlas::Atlas(const QSize &size) + : AtlasBase(size) + , m_atlas_transient_image_threshold(0) +{ m_internalFormat = GL_RGBA; m_externalFormat = GL_BGRA; @@ -188,14 +337,6 @@ Atlas::Atlas(const QSize &size) Atlas::~Atlas() { - Q_ASSERT(!m_texture_id); -} - -void Atlas::invalidate() -{ - if (m_texture_id && QOpenGLContext::currentContext()) - QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id); - m_texture_id = 0; } Texture *Atlas::create(const QImage &image) @@ -207,18 +348,7 @@ Texture *Atlas::create(const QImage &image) m_pending_uploads << t; return t; } - return 0; -} - - -int Atlas::textureId() const -{ - if (!m_texture_id) { - Q_ASSERT(QOpenGLContext::currentContext()); - QOpenGLContext::currentContext()->functions()->glGenTextures(1, &const_cast<Atlas *>(this)->m_texture_id); - } - - return m_texture_id; + return nullptr; } static void swizzleBGRAToRGBA(QImage *image) @@ -334,122 +464,70 @@ void Atlas::uploadBgra(Texture *texture) } } -void Atlas::bind(QSGTexture::Filtering filtering) +void Atlas::generateTexture() { QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - if (!m_allocated) { - m_allocated = true; - - while (funcs->glGetError() != GL_NO_ERROR) ; - - funcs->glGenTextures(1, &m_texture_id); - funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -#if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isOpenGLES()) - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); -#endif - funcs->glTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_size.width(), m_size.height(), 0, m_externalFormat, GL_UNSIGNED_BYTE, 0); + funcs->glTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_size.width(), m_size.height(), 0, m_externalFormat, GL_UNSIGNED_BYTE, nullptr); #if 0 - QImage pink(m_size.width(), m_size.height(), QImage::Format_ARGB32_Premultiplied); - pink.fill(0); - QPainter p(&pink); - QLinearGradient redGrad(0, 0, m_size.width(), 0); - redGrad.setColorAt(0, Qt::black); - redGrad.setColorAt(1, Qt::red); - p.fillRect(0, 0, m_size.width(), m_size.height(), redGrad); - p.setCompositionMode(QPainter::CompositionMode_Plus); - QLinearGradient blueGrad(0, 0, 0, m_size.height()); - blueGrad.setColorAt(0, Qt::black); - blueGrad.setColorAt(1, Qt::blue); - p.fillRect(0, 0, m_size.width(), m_size.height(), blueGrad); - p.end(); - - funcs->glTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_size.width(), m_size.height(), 0, m_externalFormat, GL_UNSIGNED_BYTE, pink.constBits()); + QImage pink(m_size.width(), m_size.height(), QImage::Format_ARGB32_Premultiplied); + pink.fill(0); + QPainter p(&pink); + QLinearGradient redGrad(0, 0, m_size.width(), 0); + redGrad.setColorAt(0, Qt::black); + redGrad.setColorAt(1, Qt::red); + p.fillRect(0, 0, m_size.width(), m_size.height(), redGrad); + p.setCompositionMode(QPainter::CompositionMode_Plus); + QLinearGradient blueGrad(0, 0, 0, m_size.height()); + blueGrad.setColorAt(0, Qt::black); + blueGrad.setColorAt(1, Qt::blue); + p.fillRect(0, 0, m_size.width(), m_size.height(), blueGrad); + p.end(); + + funcs->glTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_size.width(), m_size.height(), 0, m_externalFormat, GL_UNSIGNED_BYTE, pink.constBits()); #endif +} - GLenum errorCode = funcs->glGetError(); - if (errorCode == GL_OUT_OF_MEMORY) { - qDebug("QSGTextureAtlas: texture atlas allocation failed, out of memory"); - funcs->glDeleteTextures(1, &m_texture_id); - m_texture_id = 0; - } else if (errorCode != GL_NO_ERROR) { - qDebug("QSGTextureAtlas: texture atlas allocation failed, code=%x", errorCode); - funcs->glDeleteTextures(1, &m_texture_id); - m_texture_id = 0; - } +void Atlas::uploadPendingTexture(int i) +{ + Texture *t = static_cast<Texture*>(m_pending_uploads.at(i)); + if (m_externalFormat == GL_BGRA && + !m_use_bgra_fallback) { + uploadBgra(t); } else { - funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id); + upload(t); } - - if (m_texture_id == 0) - return; - - // Upload all pending images.. - for (int i=0; i<m_pending_uploads.size(); ++i) { - - bool profileFrames = QSG_LOG_TIME_TEXTURE().isDebugEnabled(); - if (profileFrames) - qsg_renderer_timer.start(); - - Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphTexturePrepare); - - // Skip bind, convert, swizzle; they're irrelevant - Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphTexturePrepare, - QQuickProfiler::SceneGraphTexturePrepareStart, 3); - - Texture *t = m_pending_uploads.at(i); - if (m_externalFormat == GL_BGRA && - !m_use_bgra_fallback) { - uploadBgra(t); - } else { - upload(t); - } - const QSize textureSize = t->textureSize(); - if (textureSize.width() > m_atlas_transient_image_threshold || - textureSize.height() > m_atlas_transient_image_threshold) - t->releaseImage(); - - qCDebug(QSG_LOG_TIME_TEXTURE).nospace() << "atlastexture uploaded in: " << qsg_renderer_timer.elapsed() - << "ms (" << t->textureSize().width() << "x" - << t->textureSize().height() << ")"; - - Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare, - QQuickProfiler::SceneGraphTexturePrepareUpload); - - // Skip mipmap; unused - Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphTexturePrepare, - QQuickProfiler::SceneGraphTexturePrepareUpload, 1); - Q_QUICK_SG_PROFILE_REPORT(QQuickProfiler::SceneGraphTexturePrepare, - QQuickProfiler::SceneGraphTexturePrepareMipmap); - } - - GLenum f = filtering == QSGTexture::Nearest ? GL_NEAREST : GL_LINEAR; - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, f); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, f); - - m_pending_uploads.clear(); + const QSize textureSize = t->textureSize(); + if (textureSize.width() > m_atlas_transient_image_threshold || + textureSize.height() > m_atlas_transient_image_threshold) + t->releaseImage(); + + qCDebug(QSG_LOG_TIME_TEXTURE, "atlastexture uploaded in: %lldms (%dx%d)", + qsg_renderer_timer.elapsed(), + t->textureSize().width(), + t->textureSize().height()); } -void Atlas::remove(Texture *t) +TextureBase::TextureBase(AtlasBase *atlas, const QRect &textureRect) + : m_allocated_rect(textureRect) + , m_atlas(atlas) { - QRect atlasRect = t->atlasSubRect(); - m_allocator.deallocate(atlasRect); - m_pending_uploads.removeOne(t); } +TextureBase::~TextureBase() +{ + m_atlas->remove(this); +} +void TextureBase::bind() +{ + m_atlas->bind(filtering()); +} Texture::Texture(Atlas *atlas, const QRect &textureRect, const QImage &image) - : QSGTexture() - , m_allocated_rect(textureRect) + : TextureBase(atlas, textureRect) , m_image(image) - , m_atlas(atlas) - , m_nonatlas_texture(0) + , m_nonatlas_texture(nullptr) , m_has_alpha(image.hasAlphaChannel()) { float w = atlas->size().width(); @@ -463,16 +541,10 @@ Texture::Texture(Atlas *atlas, const QRect &textureRect, const QImage &image) Texture::~Texture() { - m_atlas->remove(this); if (m_nonatlas_texture) delete m_nonatlas_texture; } -void Texture::bind() -{ - m_atlas->bind(filtering()); -} - QSGTexture *Texture::removedFromAtlas() const { if (m_nonatlas_texture) { @@ -508,7 +580,7 @@ QSGTexture *Texture::removedFromAtlas() const QRect r = atlasSubRectWithoutPadding(); // and copy atlas into our texture. while (f->glGetError() != GL_NO_ERROR) ; - f->glCopyTexImage2D(GL_TEXTURE_2D, 0, m_atlas->internalFormat(), r.x(), r.y(), r.width(), r.height(), 0); + f->glCopyTexImage2D(GL_TEXTURE_2D, 0, static_cast<Atlas*>(m_atlas)->internalFormat(), r.x(), r.y(), r.width(), r.height(), 0); // BGRA may have been rejected by some GLES implementations if (f->glGetError() != GL_NO_ERROR) f->glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, r.x(), r.y(), r.width(), r.height(), 0); diff --git a/src/quick/scenegraph/util/qsgatlastexture_p.h b/src/quick/scenegraph/util/qsgatlastexture_p.h index 3dee539547..14dc8f7958 100644 --- a/src/quick/scenegraph/util/qsgatlastexture_p.h +++ b/src/quick/scenegraph/util/qsgatlastexture_p.h @@ -61,10 +61,16 @@ QT_BEGIN_NAMESPACE +namespace QSGCompressedAtlasTexture { + class Atlas; +} +class QSGCompressedTextureFactory; + namespace QSGAtlasTexture { class Texture; +class TextureBase; class Atlas; class Manager : public QObject @@ -76,93 +82,121 @@ public: ~Manager(); QSGTexture *create(const QImage &image, bool hasAlphaChannel); + QSGTexture *create(const QSGCompressedTextureFactory *factory); void invalidate(); private: Atlas *m_atlas; + // set of atlases for different compressed formats + QHash<unsigned int, QSGCompressedAtlasTexture::Atlas*> m_atlases; QSize m_atlas_size; int m_atlas_size_limit; }; -class Atlas : public QObject +class AtlasBase : public QObject { + Q_OBJECT public: - Atlas(const QSize &size); - ~Atlas(); + AtlasBase(const QSize &size); + ~AtlasBase(); void invalidate(); int textureId() const; void bind(QSGTexture::Filtering filtering); + void remove(TextureBase *t); + + QSize size() const { return m_size; } + +protected: + virtual void generateTexture() = 0; + virtual void uploadPendingTexture(int i) = 0; + +protected: + QSGAreaAllocator m_allocator; + unsigned int m_texture_id; + QSize m_size; + QList<TextureBase *> m_pending_uploads; + +private: + bool m_allocated; +}; + +class Atlas : public AtlasBase +{ +public: + Atlas(const QSize &size); + ~Atlas(); + + void generateTexture() override; + void uploadPendingTexture(int i) override; + void upload(Texture *texture); void uploadBgra(Texture *texture); Texture *create(const QImage &image); - void remove(Texture *t); - - QSize size() const { return m_size; } uint internalFormat() const { return m_internalFormat; } uint externalFormat() const { return m_externalFormat; } private: - QSGAreaAllocator m_allocator; - unsigned int m_texture_id; - QSize m_size; - QList<Texture *> m_pending_uploads; - uint m_internalFormat; uint m_externalFormat; int m_atlas_transient_image_threshold; - uint m_allocated : 1; uint m_use_bgra_fallback: 1; - uint m_debug_overlay : 1; }; -class Texture : public QSGTexture +class TextureBase : public QSGTexture +{ + Q_OBJECT +public: + TextureBase(AtlasBase *atlas, const QRect &textureRect); + ~TextureBase(); + + int textureId() const override { return m_atlas->textureId(); } + bool isAtlasTexture() const override { return true; } + + QRect atlasSubRect() const { return m_allocated_rect; } + + void bind() override; + +protected: + QRect m_allocated_rect; + AtlasBase *m_atlas; +}; + +class Texture : public TextureBase { Q_OBJECT public: Texture(Atlas *atlas, const QRect &textureRect, const QImage &image); ~Texture(); - int textureId() const override { return m_atlas->textureId(); } QSize textureSize() const override { return atlasSubRectWithoutPadding().size(); } void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; } bool hasAlphaChannel() const override { return m_has_alpha; } bool hasMipmaps() const override { return false; } - bool isAtlasTexture() const override { return true; } QRectF normalizedTextureSubRect() const override { return m_texture_coords_rect; } QRect atlasSubRect() const { return m_allocated_rect; } QRect atlasSubRectWithoutPadding() const { return m_allocated_rect.adjusted(1, 1, -1, -1); } - bool isTexture() const { return true; } - QSGTexture *removedFromAtlas() const override; void releaseImage() { m_image = QImage(); } const QImage &image() const { return m_image; } - void bind() override; - private: - QRect m_allocated_rect; QRectF m_texture_coords_rect; - QImage m_image; - - Atlas *m_atlas; - mutable QSGPlainTexture *m_nonatlas_texture; - - uint m_has_alpha : 1; + bool m_has_alpha; }; } diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp index 9ffd1b4b08..981ea089be 100644 --- a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp +++ b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp @@ -78,11 +78,11 @@ QSGDefaultPainterNode::QSGDefaultPainterNode(QQuickPaintedItem *item) , m_preferredRenderTarget(QQuickPaintedItem::Image) , m_actualRenderTarget(QQuickPaintedItem::Image) , m_item(item) - , m_fbo(0) - , m_multisampledFbo(0) + , m_fbo(nullptr) + , m_multisampledFbo(nullptr) , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) - , m_texture(0) - , m_gl_device(0) + , m_texture(nullptr) + , m_gl_device(nullptr) , m_fillColor(Qt::transparent) , m_contentsScale(1.0) , m_dirtyContents(false) @@ -260,8 +260,8 @@ void QSGDefaultPainterNode::updateRenderTarget() delete m_fbo; delete m_multisampledFbo; delete m_gl_device; - m_fbo = m_multisampledFbo = 0; - m_gl_device = 0; + m_fbo = m_multisampledFbo = nullptr; + m_gl_device = nullptr; } if (m_actualRenderTarget == QQuickPaintedItem::FramebufferObject || @@ -275,7 +275,7 @@ void QSGDefaultPainterNode::updateRenderTarget() delete m_fbo; delete m_multisampledFbo; - m_fbo = m_multisampledFbo = 0; + m_fbo = m_multisampledFbo = nullptr; if (m_gl_device) m_gl_device->setSize(m_fboSize); diff --git a/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp b/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp index ba0207aca8..56508af152 100644 --- a/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp +++ b/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp @@ -43,7 +43,7 @@ QT_BEGIN_NAMESPACE QSGDepthStencilBuffer::QSGDepthStencilBuffer(QOpenGLContext *context, const Format &format) : m_functions(context) - , m_manager(0) + , m_manager(nullptr) , m_format(format) , m_depthBuffer(0) , m_stencilBuffer(0) @@ -160,7 +160,7 @@ QSGDepthStencilBufferManager::~QSGDepthStencilBufferManager() for (Hash::const_iterator it = m_buffers.constBegin(), cend = m_buffers.constEnd(); it != cend; ++it) { QSGDepthStencilBuffer *buffer = it.value().data(); buffer->free(); - buffer->m_manager = 0; + buffer->m_manager = nullptr; } } @@ -174,7 +174,7 @@ QSharedPointer<QSGDepthStencilBuffer> QSGDepthStencilBufferManager::bufferForFor void QSGDepthStencilBufferManager::insertBuffer(const QSharedPointer<QSGDepthStencilBuffer> &buffer) { - Q_ASSERT(buffer->m_manager == 0); + Q_ASSERT(buffer->m_manager == nullptr); Q_ASSERT(!m_buffers.contains(buffer->m_format)); buffer->m_manager = this; m_buffers.insert(buffer->m_format, buffer.toWeakRef()); diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp index dffe199224..91fa46033c 100644 --- a/src/quick/scenegraph/util/qsgengine.cpp +++ b/src/quick/scenegraph/util/qsgengine.cpp @@ -157,7 +157,7 @@ QSGAbstractRenderer *QSGEngine::createRenderer() const { Q_D(const QSGEngine); if (!d->sgRenderContext->isValid()) - return 0; + return nullptr; QSGRenderer *renderer = d->sgRenderContext->createRenderer(); renderer->setCustomRenderMode(qgetenv("QSG_VISUALIZE")); @@ -178,7 +178,7 @@ QSGTexture *QSGEngine::createTextureFromImage(const QImage &image, CreateTexture { Q_D(const QSGEngine); if (!d->sgRenderContext->isValid()) - return 0; + return nullptr; uint flags = 0; if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas; if (!(options & TextureIsOpaque)) flags |= QSGRenderContext::CreateTexture_Alpha; @@ -206,7 +206,7 @@ QSGTexture *QSGEngine::createTextureFromId(uint id, const QSize &size, CreateTex texture->setTextureSize(size); return texture; } - return 0; + return nullptr; } /*! diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h index 514e6e8c2b..e9e01dc710 100644 --- a/src/quick/scenegraph/util/qsgengine.h +++ b/src/quick/scenegraph/util/qsgengine.h @@ -68,7 +68,7 @@ public: Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption) explicit QSGEngine(QObject *parent = nullptr); - ~QSGEngine(); + ~QSGEngine() override; void initialize(QOpenGLContext *context); void invalidate(); diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp index a0c71b5340..28f6113a60 100644 --- a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp +++ b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp @@ -77,13 +77,13 @@ FlatColorMaterialShader::FlatColorMaterialShader() void FlatColorMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) { #if QT_CONFIG(opengl) - Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); + Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); QSGFlatColorMaterial *oldMaterial = static_cast<QSGFlatColorMaterial *>(oldEffect); QSGFlatColorMaterial *newMaterial = static_cast<QSGFlatColorMaterial *>(newEffect); const QColor &c = newMaterial->color(); - if (oldMaterial == 0 || c != oldMaterial->color() || state.isOpacityDirty()) { + if (oldMaterial == nullptr || c != oldMaterial->color() || state.isOpacityDirty()) { float opacity = state.opacity() * c.alphaF(); QVector4D v(c.redF() * opacity, c.greenF() * opacity, @@ -103,7 +103,7 @@ void FlatColorMaterialShader::updateState(const RenderState &state, QSGMaterial char const *const *FlatColorMaterialShader::attributeNames() const { - static char const *const attr[] = { "vCoord", 0 }; + static char const *const attr[] = { "vCoord", nullptr }; return attr; } diff --git a/src/quick/scenegraph/util/qsgimagenode.cpp b/src/quick/scenegraph/util/qsgimagenode.cpp index c03c91d1cb..b154023247 100644 --- a/src/quick/scenegraph/util/qsgimagenode.cpp +++ b/src/quick/scenegraph/util/qsgimagenode.cpp @@ -168,7 +168,7 @@ QT_BEGIN_NAMESPACE */ /*! - \fn QSGImageNode::TextureCoordinatesTransformMode textureCoordinatesTransform() const + \fn QSGImageNode::TextureCoordinatesTransformMode QSGImageNode::textureCoordinatesTransform() const Returns the mode used to generate texture coordinates for this node. */ @@ -187,6 +187,15 @@ QT_BEGIN_NAMESPACE \return \c true if the node takes ownership of the texture; otherwise \c false. */ +/*! + Updates the geometry \a g with the \a texture, the coordinates + in \a rect, and the texture coordinates from \a sourceRect. + + \a g is assumed to be a triangle strip of four vertices of type + QSGGeometry::TexturedPoint2D. + + \a texCoordMode is used for normalizing the \a sourceRect. + */ void QSGImageNode::rebuildGeometry(QSGGeometry *g, QSGTexture *texture, const QRectF &rect, diff --git a/src/quick/scenegraph/util/qsgimagenode.h b/src/quick/scenegraph/util/qsgimagenode.h index 0e053c307f..526f52b7e5 100644 --- a/src/quick/scenegraph/util/qsgimagenode.h +++ b/src/quick/scenegraph/util/qsgimagenode.h @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE class Q_QUICK_EXPORT QSGImageNode : public QSGGeometryNode { public: - virtual ~QSGImageNode() { } + ~QSGImageNode() override { } virtual void setRect(const QRectF &rect) = 0; inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); } diff --git a/src/quick/scenegraph/util/qsgninepatchnode.h b/src/quick/scenegraph/util/qsgninepatchnode.h index 8509cbd326..e76afd3c4a 100644 --- a/src/quick/scenegraph/util/qsgninepatchnode.h +++ b/src/quick/scenegraph/util/qsgninepatchnode.h @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE class Q_QUICK_EXPORT QSGNinePatchNode : public QSGGeometryNode { public: - virtual ~QSGNinePatchNode() { } + ~QSGNinePatchNode() override { } virtual void setTexture(QSGTexture *texture) = 0; virtual void setBounds(const QRectF &bounds) = 0; diff --git a/src/quick/scenegraph/util/qsgrectanglenode.h b/src/quick/scenegraph/util/qsgrectanglenode.h index 8e0da1d9c7..ba52b65b07 100644 --- a/src/quick/scenegraph/util/qsgrectanglenode.h +++ b/src/quick/scenegraph/util/qsgrectanglenode.h @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class Q_QUICK_EXPORT QSGRectangleNode : public QSGGeometryNode { public: - virtual ~QSGRectangleNode() { } + ~QSGRectangleNode() override { } virtual void setRect(const QRectF &rect) = 0; inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); } diff --git a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp index e134a5d4d3..93fc213f2e 100644 --- a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp +++ b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp @@ -262,8 +262,8 @@ void QSGShaderSourceBuilder::addDefinition(const QByteArray &definition) tok.initialize(input); // First find #version, #extension's and "void main() { ... " - const char *versionPos = 0; - const char *extensionPos = 0; + const char *versionPos = nullptr; + const char *extensionPos = nullptr; bool inSingleLineComment = false; bool inMultiLineComment = false; bool foundVersionStart = false; @@ -325,8 +325,8 @@ void QSGShaderSourceBuilder::removeVersion() tok.initialize(input); // First find #version beginning and end (if present) - const char *versionStartPos = 0; - const char *versionEndPos = 0; + const char *versionStartPos = nullptr; + const char *versionEndPos = nullptr; bool inSingleLineComment = false; bool inMultiLineComment = false; bool foundVersionStart = false; @@ -361,7 +361,7 @@ void QSGShaderSourceBuilder::removeVersion() t = tok.next(); } - if (versionStartPos == 0) + if (versionStartPos == nullptr) return; // Construct a new shader string, inserting the definition diff --git a/src/quick/scenegraph/util/qsgsimplematerial.cpp b/src/quick/scenegraph/util/qsgsimplematerial.cpp index f29c58ad9e..376f7dce5c 100644 --- a/src/quick/scenegraph/util/qsgsimplematerial.cpp +++ b/src/quick/scenegraph/util/qsgsimplematerial.cpp @@ -173,17 +173,17 @@ /*! - \fn char const *const *QSGSimpleMaterialShader::attributeNames() const + \fn template <typename State> char const *const *QSGSimpleMaterialShader<State>::attributeNames() const \internal */ /*! - \fn void QSGSimpleMaterialShader::initialize() + \fn template <typename State> void QSGSimpleMaterialShader<State>::initialize() \internal */ /*! - \fn void QSGSimpleMaterialShader::resolveUniforms() + \fn template <typename State> void QSGSimpleMaterialShader<State>::resolveUniforms() Reimplement this function to resolve the location of named uniforms in the shader program. @@ -192,34 +192,34 @@ */ /*! - \fn const char *QSGSimpleMaterialShader::uniformMatrixName() const + \fn template <typename State> const char *QSGSimpleMaterialShader<State>::uniformMatrixName() const Returns the name for the transform matrix uniform of this item. The default value is \c qt_Matrix. */ /*! - \fn const char *QSGSimpleMaterialShader::uniformOpacityName() const + \fn template <typename State> const char *QSGSimpleMaterialShader<State>::uniformOpacityName() const Returns the name for the opacity uniform of this item. The default value is \c qt_Opacity. */ /*! - \fn void QSGSimpleMaterialShader::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) + \fn template <typename State> void QSGSimpleMaterialShader<State>::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) \internal */ /*! - \fn QList<QByteArray> QSGSimpleMaterialShader::attributes() const + \fn template <typename State> QList<QByteArray> QSGSimpleMaterialShader<State>::attributes() const Returns a list of names, declaring the vertex attributes in the vertex shader. */ /*! - \fn void QSGSimpleMaterialShader::updateState(const State *newState, const State *oldState) + \fn template <typename State> void QSGSimpleMaterialShader<State>::updateState(const State *newState, const State *oldState) Called whenever the state of this shader should be updated from \a oldState to \a newState, typical for each new set of diff --git a/src/quick/scenegraph/util/qsgsimplematerial.h b/src/quick/scenegraph/util/qsgsimplematerial.h index b5b8815b4a..79180ca8e2 100644 --- a/src/quick/scenegraph/util/qsgsimplematerial.h +++ b/src/quick/scenegraph/util/qsgsimplematerial.h @@ -138,7 +138,7 @@ template <typename State> class QSGSimpleMaterial : public QSGMaterial { public: -#ifndef qdoc +#ifndef Q_CLANG_QDOC QSGSimpleMaterial(const State &aState, PtrShaderCreateFunc func) : m_state(aState) , m_func(func) @@ -185,7 +185,7 @@ public: QSGSimpleMaterialComparableMaterial(PtrShaderCreateFunc func) : QSGSimpleMaterial<State>(func) {} - int compare(const QSGMaterial *other) const { + int compare(const QSGMaterial *other) const override { return QSGSimpleMaterialComparableMaterial<State>::state()->compare(static_cast<const QSGSimpleMaterialComparableMaterial<State> *>(other)->state()); } }; @@ -207,7 +207,7 @@ Q_INLINE_TEMPLATE void QSGSimpleMaterialShader<State>::updateState(const RenderS Q_UNUSED(state) #endif State *ns = static_cast<QSGSimpleMaterial<State> *>(newMaterial)->state(); - State *old = 0; + State *old = nullptr; if (oldMaterial) old = static_cast<QSGSimpleMaterial<State> *>(oldMaterial)->state(); updateState(ns, old); diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp index 6ce37de7cb..0c49ca9aa5 100644 --- a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp +++ b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp @@ -47,8 +47,7 @@ class QSGSimpleTextureNodePrivate : public QSGGeometryNodePrivate { public: QSGSimpleTextureNodePrivate() - : QSGGeometryNodePrivate() - , texCoordMode(QSGSimpleTextureNode::NoTransform) + : texCoordMode(QSGSimpleTextureNode::NoTransform) , isAtlasTexture(false) , ownsTexture(false) {} diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.h b/src/quick/scenegraph/util/qsgsimpletexturenode.h index 09e4277c66..010463d3c6 100644 --- a/src/quick/scenegraph/util/qsgsimpletexturenode.h +++ b/src/quick/scenegraph/util/qsgsimpletexturenode.h @@ -52,7 +52,7 @@ class Q_QUICK_EXPORT QSGSimpleTextureNode : public QSGGeometryNode { public: QSGSimpleTextureNode(); - ~QSGSimpleTextureNode(); + ~QSGSimpleTextureNode() override; void setRect(const QRectF &rect); inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); } diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index 4f11d95e70..fea92a5121 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -53,7 +53,7 @@ #endif #include <private/qsgmaterialshader_p.h> -#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && !defined(__UCLIBC__) +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && defined(__GLIBC__) #define CAN_BACKTRACE_EXECINFO #endif @@ -399,7 +399,7 @@ QSGTexture::~QSGTexture() QSGTexture *QSGTexture::removedFromAtlas() const { Q_ASSERT_X(!isAtlasTexture(), "QSGTexture::removedFromAtlas()", "Called on a non-atlas texture"); - return 0; + return nullptr; } /*! diff --git a/src/quick/scenegraph/util/qsgtexture.h b/src/quick/scenegraph/util/qsgtexture.h index 032129434e..7bd57a16e3 100644 --- a/src/quick/scenegraph/util/qsgtexture.h +++ b/src/quick/scenegraph/util/qsgtexture.h @@ -54,7 +54,7 @@ class Q_QUICK_EXPORT QSGTexture : public QObject public: QSGTexture(); - ~QSGTexture(); + ~QSGTexture() override; enum WrapMode { Repeat, diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h index 52dc6db2d0..18dd5eff68 100644 --- a/src/quick/scenegraph/util/qsgtexture_p.h +++ b/src/quick/scenegraph/util/qsgtexture_p.h @@ -83,7 +83,7 @@ class Q_QUICK_PRIVATE_EXPORT QSGPlainTexture : public QSGTexture Q_OBJECT public: QSGPlainTexture(); - virtual ~QSGPlainTexture(); + ~QSGPlainTexture() override; void setOwnsTexture(bool owns) { m_owns_texture = owns; } bool ownsTexture() const { return m_owns_texture; } diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp index fbc8f27a63..7b1d5abb26 100644 --- a/src/quick/scenegraph/util/qsgtexturematerial.cpp +++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp @@ -57,7 +57,6 @@ inline static bool isPowerOfTwo(int x) QSGMaterialType QSGOpaqueTextureMaterialShader::type; QSGOpaqueTextureMaterialShader::QSGOpaqueTextureMaterialShader() - : QSGMaterialShader() { #if QT_CONFIG(opengl) setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/opaquetexture.vert")); @@ -67,7 +66,7 @@ QSGOpaqueTextureMaterialShader::QSGOpaqueTextureMaterialShader() char const *const *QSGOpaqueTextureMaterialShader::attributeNames() const { - static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 }; + static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", nullptr }; return attr; } @@ -80,7 +79,7 @@ void QSGOpaqueTextureMaterialShader::initialize() void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) { - Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); + Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); QSGOpaqueTextureMaterial *tx = static_cast<QSGOpaqueTextureMaterial *>(newEffect); QSGOpaqueTextureMaterial *oldTx = static_cast<QSGOpaqueTextureMaterial *>(oldEffect); @@ -112,7 +111,7 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa t->setMipmapFiltering(tx->mipmapFiltering()); t->setAnisotropyLevel(tx->anisotropyLevel()); - if (oldTx == 0 || oldTx->texture()->textureId() != t->textureId()) + if (oldTx == nullptr || oldTx->texture()->textureId() != t->textureId()) t->bind(); else t->updateBindOptions(); @@ -169,7 +168,7 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa */ QSGOpaqueTextureMaterial::QSGOpaqueTextureMaterial() - : m_texture(0) + : m_texture(nullptr) , m_filtering(QSGTexture::Nearest) , m_mipmap_filtering(QSGTexture::None) , m_horizontal_wrap(QSGTexture::ClampToEdge) @@ -304,7 +303,17 @@ void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture) The default vertical wrap mode is \c QSGTexture::ClampToEdge. */ +/*! + \fn void QSGOpaqueTextureMaterial::setAnisotropyLevel(QSGTexture::AnisotropyLevel level) + + Sets this material's anistropy level to \a level. +*/ + +/*! + \fn QSGTexture::AnisotropyLevel QSGOpaqueTextureMaterial::anisotropyLevel() const + Returns this material's anistropy level. +*/ /*! \internal @@ -388,7 +397,7 @@ QSGTextureMaterialShader::QSGTextureMaterialShader() void QSGTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) { - Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); + Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); #if QT_CONFIG(opengl) if (state.isOpacityDirty()) program()->setUniformValue(m_opacity_id, state.opacity()); diff --git a/src/quick/scenegraph/util/qsgtexturereader.cpp b/src/quick/scenegraph/util/qsgtexturereader.cpp index 61729ada18..8af2c8e7cd 100644 --- a/src/quick/scenegraph/util/qsgtexturereader.cpp +++ b/src/quick/scenegraph/util/qsgtexturereader.cpp @@ -43,40 +43,71 @@ #if QT_CONFIG(opengl) #include <private/qsgpkmhandler_p.h> +#include <private/qsgktxhandler_p.h> #endif +#include <QFileInfo> + QT_BEGIN_NAMESPACE -QSGTextureReader::QSGTextureReader() +QSGTextureReader::QSGTextureReader(QIODevice *device, const QString &fileName) + : m_device(device), m_fileInfo(fileName) { +} +QSGTextureReader::~QSGTextureReader() +{ + delete m_handler; } -QQuickTextureFactory *QSGTextureReader::read(QIODevice *device, const QByteArray &format) +QQuickTextureFactory *QSGTextureReader::read() { #if QT_CONFIG(opengl) - if (format == QByteArrayLiteral("pkm")) { - QSGPkmHandler handler; - return handler.read(device); - } + if (!isTexture()) + return nullptr; + return m_handler->read(); #else - Q_UNUSED(device) - Q_UNUSED(format) -#endif return nullptr; +#endif } -bool QSGTextureReader::isTexture(QIODevice *device, const QByteArray &format) +bool QSGTextureReader::isTexture() { #if QT_CONFIG(opengl) - if (format == QByteArrayLiteral("pkm")) { - return device->peek(4) == QByteArrayLiteral("PKM "); + if (!checked) { + checked = true; + if (!init()) + return false; + + QByteArray headerBlock = m_device->peek(64); + QByteArray suffix = m_fileInfo.suffix().toLower().toLatin1(); + QByteArray logName = m_fileInfo.fileName().toUtf8(); + + // Currently the handlers are hardcoded; later maybe a list of plugins + if (QSGPkmHandler::canRead(suffix, headerBlock)) { + m_handler = new QSGPkmHandler(m_device, logName); + } else if (QSGKtxHandler::canRead(suffix, headerBlock)) { + m_handler = new QSGKtxHandler(m_device, logName); + } + // else if OtherHandler::canRead() ...etc. } + return (m_handler != nullptr); #else - Q_UNUSED(device) - Q_UNUSED(format) -#endif return false; +#endif +} + +QList<QByteArray> QSGTextureReader::supportedFileFormats() +{ + // Hardcoded for now + return {QByteArrayLiteral("pkm"), QByteArrayLiteral("ktx")}; +} + +bool QSGTextureReader::init() +{ + if (!m_device) + return false; + return m_device->isReadable(); } QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgtexturereader_p.h b/src/quick/scenegraph/util/qsgtexturereader_p.h index 7d2fc314a6..19e33bf5c3 100644 --- a/src/quick/scenegraph/util/qsgtexturereader_p.h +++ b/src/quick/scenegraph/util/qsgtexturereader_p.h @@ -52,19 +52,34 @@ // #include <QString> +#include <QFileInfo> QT_BEGIN_NAMESPACE class QIODevice; class QQuickTextureFactory; +class QSGTextureFileHandler; class QSGTextureReader { public: - QSGTextureReader(); + QSGTextureReader(QIODevice *device, const QString &fileName = QString()); + ~QSGTextureReader(); - static QQuickTextureFactory *read(QIODevice *device, const QByteArray &format); - static bool isTexture(QIODevice *device, const QByteArray &format); + QQuickTextureFactory *read(); + bool isTexture(); + + // TBD access function to params + // TBD ask for identified fmt + + static QList<QByteArray> supportedFileFormats(); + +private: + bool init(); + QIODevice *m_device = nullptr; + QFileInfo m_fileInfo; + QSGTextureFileHandler *m_handler = nullptr; + bool checked = false; }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp index 42c589b14a..cb61430e2e 100644 --- a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp +++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp @@ -64,7 +64,6 @@ private: QSGMaterialType QSGVertexColorMaterialShader::type; QSGVertexColorMaterialShader::QSGVertexColorMaterialShader() - : QSGMaterialShader() { #if QT_CONFIG(opengl) setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/vertexcolor.vert")); @@ -87,7 +86,7 @@ void QSGVertexColorMaterialShader::updateState(const RenderState &state, QSGMate char const *const *QSGVertexColorMaterialShader::attributeNames() const { - static const char *const attr[] = { "vertexCoord", "vertexColor", 0 }; + static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr }; return attr; } |