blob: 6baee33b5352a9992f1a8213af581414befe8a2a [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSGADAPTATIONLAYER_P_H
#define QSGADAPTATIONLAYER_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 <QtQuick/qsgnode.h>
#include <QtQuick/qsgtexture.h>
#include <QtCore/qobject.h>
#include <QtCore/qrect.h>
#include <QtGui/qbrush.h>
#include <QtGui/qcolor.h>
#include <QtCore/qsharedpointer.h>
#include <QtGui/qglyphrun.h>
#include <QtCore/qurl.h>
#include <private/qfontengine_p.h>
#include <QtGui/private/qdatabuffer_p.h>
#include <private/qdistancefield_p.h>
#include <private/qintrusivelist_p.h>
#include <QtGui/private/qshader_p.h>
// ### remove
#include <QtQuick/private/qquicktext_p.h>
QT_BEGIN_NAMESPACE
class QSGNode;
class QImage;
class TextureReference;
class QSGDistanceFieldGlyphNode;
class QSGInternalImageNode;
class QSGPainterNode;
class QSGInternalRectangleNode;
class QSGGlyphNode;
class QSGRootNode;
class QSGSpriteNode;
class QSGRenderNode;
class QSGRenderContext;
class QRhiTexture;
class Q_QUICK_PRIVATE_EXPORT QSGNodeVisitorEx
{
public:
virtual ~QSGNodeVisitorEx() {}
// visit(...) returns true if the children are supposed to be
// visisted and false if they're supposed to be skipped by the visitor.
virtual bool visit(QSGTransformNode *) = 0;
virtual void endVisit(QSGTransformNode *) = 0;
virtual bool visit(QSGClipNode *) = 0;
virtual void endVisit(QSGClipNode *) = 0;
virtual bool visit(QSGGeometryNode *) = 0;
virtual void endVisit(QSGGeometryNode *) = 0;
virtual bool visit(QSGOpacityNode *) = 0;
virtual void endVisit(QSGOpacityNode *) = 0;
virtual bool visit(QSGInternalImageNode *) = 0;
virtual void endVisit(QSGInternalImageNode *) = 0;
virtual bool visit(QSGPainterNode *) = 0;
virtual void endVisit(QSGPainterNode *) = 0;
virtual bool visit(QSGInternalRectangleNode *) = 0;
virtual void endVisit(QSGInternalRectangleNode *) = 0;
virtual bool visit(QSGGlyphNode *) = 0;
virtual void endVisit(QSGGlyphNode *) = 0;
virtual bool visit(QSGRootNode *) = 0;
virtual void endVisit(QSGRootNode *) = 0;
#if QT_CONFIG(quick_sprite)
virtual bool visit(QSGSpriteNode *) = 0;
virtual void endVisit(QSGSpriteNode *) = 0;
#endif
virtual bool visit(QSGRenderNode *) = 0;
virtual void endVisit(QSGRenderNode *) = 0;
void visitChildren(QSGNode *node);
};
class Q_QUICK_PRIVATE_EXPORT QSGVisitableNode : public QSGGeometryNode
{
public:
QSGVisitableNode() { setFlag(IsVisitableNode); }
virtual void accept(QSGNodeVisitorEx *) = 0;
};
class Q_QUICK_PRIVATE_EXPORT QSGInternalRectangleNode : public QSGVisitableNode
{
public:
virtual void setRect(const QRectF &rect) = 0;
virtual void setColor(const QColor &color) = 0;
virtual void setPenColor(const QColor &color) = 0;
virtual void setPenWidth(qreal width) = 0;
virtual void setGradientStops(const QGradientStops &stops) = 0;
virtual void setGradientVertical(bool vertical) = 0;
virtual void setRadius(qreal radius) = 0;
virtual void setAntialiasing(bool antialiasing) { Q_UNUSED(antialiasing) }
virtual void setAligned(bool aligned) = 0;
virtual void update() = 0;
void accept(QSGNodeVisitorEx *visitor) override { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); }
};
class Q_QUICK_PRIVATE_EXPORT QSGInternalImageNode : public QSGVisitableNode
{
public:
virtual void setTargetRect(const QRectF &rect) = 0;
virtual void setInnerTargetRect(const QRectF &rect) = 0;
virtual void setInnerSourceRect(const QRectF &rect) = 0;
// The sub-source rect's width and height specify the number of times the inner source rect
// is repeated inside the inner target rect. The x and y specify which (normalized) location
// in the inner source rect maps to the upper-left corner of the inner target rect.
virtual void setSubSourceRect(const QRectF &rect) = 0;
virtual void setTexture(QSGTexture *texture) = 0;
virtual void setAntialiasing(bool antialiasing) { Q_UNUSED(antialiasing) }
virtual void setMirror(bool mirror) = 0;
virtual void setMipmapFiltering(QSGTexture::Filtering filtering) = 0;
virtual void setFiltering(QSGTexture::Filtering filtering) = 0;
virtual void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) = 0;
virtual void setVerticalWrapMode(QSGTexture::WrapMode wrapMode) = 0;
virtual void update() = 0;
void accept(QSGNodeVisitorEx *visitor) override { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); }
};
class Q_QUICK_PRIVATE_EXPORT QSGPainterNode : public QSGVisitableNode
{
public:
virtual void setPreferredRenderTarget(QQuickPaintedItem::RenderTarget target) = 0;
virtual void setSize(const QSize &size) = 0;
virtual void setDirty(const QRect &dirtyRect = QRect()) = 0;
virtual void setOpaquePainting(bool opaque) = 0;
virtual void setLinearFiltering(bool linearFiltering) = 0;
virtual void setMipmapping(bool mipmapping) = 0;
virtual void setSmoothPainting(bool s) = 0;
virtual void setFillColor(const QColor &c) = 0;
virtual void setContentsScale(qreal s) = 0;
virtual void setFastFBOResizing(bool dynamic) = 0;
virtual void setTextureSize(const QSize &size) = 0;
virtual QImage toImage() const = 0;
virtual void update() = 0;
virtual QSGTexture *texture() const = 0;
void accept(QSGNodeVisitorEx *visitor) override { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); }
};
class Q_QUICK_EXPORT QSGLayer : public QSGDynamicTexture
{
Q_OBJECT
public:
virtual void setItem(QSGNode *item) = 0;
virtual void setRect(const QRectF &rect) = 0;
virtual void setSize(const QSize &size) = 0;
virtual void scheduleUpdate() = 0;
virtual QImage toImage() const = 0;
virtual void setLive(bool live) = 0;
virtual void setRecursive(bool recursive) = 0;
virtual void setFormat(uint format) = 0;
virtual void setHasMipmaps(bool mipmap) = 0;
virtual void setDevicePixelRatio(qreal ratio) = 0;
virtual void setMirrorHorizontal(bool mirror) = 0;
virtual void setMirrorVertical(bool mirror) = 0;
virtual void setSamples(int samples) = 0;
Q_SLOT virtual void markDirtyTexture() = 0;
Q_SLOT virtual void invalidated() = 0;
Q_SIGNALS:
void updateRequested();
void scheduledUpdateCompleted();
protected:
QSGLayer(QSGTexturePrivate &dd);
};
#if QT_CONFIG(quick_sprite)
class Q_QUICK_PRIVATE_EXPORT QSGSpriteNode : public QSGVisitableNode
{
public:
virtual void setTexture(QSGTexture *texture) = 0;
virtual void setTime(float time) = 0;
virtual void setSourceA(const QPoint &source) = 0;
virtual void setSourceB(const QPoint &source) = 0;
virtual void setSpriteSize(const QSize &size) = 0;
virtual void setSheetSize(const QSize &size) = 0;
virtual void setSize(const QSizeF &size) = 0;
virtual void setFiltering(QSGTexture::Filtering filtering) = 0;
virtual void update() = 0;
void accept(QSGNodeVisitorEx *visitor) override { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); }
};
#endif
class Q_QUICK_PRIVATE_EXPORT QSGGuiThreadShaderEffectManager : public QObject
{
Q_OBJECT
public:
enum Status {
Compiled,
Uncompiled,
Error
};
virtual bool hasSeparateSamplerAndTextureObjects() const = 0;
virtual QString log() const = 0;
virtual Status status() const = 0;
struct ShaderInfo {
enum Type {
TypeVertex,
TypeFragment,
TypeOther
};
enum VariableType {
Constant, // cbuffer members or uniforms
Sampler,
Texture // for APIs with separate texture and sampler objects
};
struct Variable {
Variable() {}
VariableType type = Constant;
QByteArray name;
uint offset = 0; // for cbuffer members
uint size = 0; // for cbuffer members
int bindPoint = 0; // for textures/samplers, where applicable
};
QString name; // optional, f.ex. the filename, used for debugging purposes only
QByteArray blob; // source or bytecode (when not using QRhi)
QShader rhiShader;
Type type;
QVector<Variable> variables;
uint constantDataSize;
// Vertex inputs are not tracked here as QSGGeometry::AttributeSet
// hardwires that anyways so it is up to the shader to provide
// compatible inputs (e.g. compatible with
// QSGGeometry::defaultAttributes_TexturedPoint2D()).
};
virtual void prepareShaderCode(ShaderInfo::Type typeHint, const QByteArray &src, ShaderInfo *result) = 0;
Q_SIGNALS:
void shaderCodePrepared(bool ok, ShaderInfo::Type typeHint, const QByteArray &src, ShaderInfo *result);
void textureChanged();
void logAndStatusChanged();
};
#ifndef QT_NO_DEBUG_STREAM
Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug debug, const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &v);
#endif
class Q_QUICK_PRIVATE_EXPORT QSGShaderEffectNode : public QSGVisitableNode
{
public:
enum DirtyShaderFlag {
DirtyShaders = 0x01,
DirtyShaderConstant = 0x02,
DirtyShaderTexture = 0x04,
DirtyShaderGeometry = 0x08,
DirtyShaderMesh = 0x10,
DirtyShaderAll = 0xFF
};
Q_DECLARE_FLAGS(DirtyShaderFlags, DirtyShaderFlag)
enum CullMode { // must match ShaderEffect
NoCulling,
BackFaceCulling,
FrontFaceCulling
};
struct VariableData {
enum SpecialType { None, Unused, Source, SubRect, Opacity, Matrix };
QVariant value;
SpecialType specialType;
};
struct ShaderData {
ShaderData() {}
bool hasShaderCode = false;
QSGGuiThreadShaderEffectManager::ShaderInfo shaderInfo;
QVector<VariableData> varData;
};
struct SyncData {
DirtyShaderFlags dirty;
CullMode cullMode;
bool blending;
struct ShaderSyncData {
const ShaderData *shader;
const QSet<int> *dirtyConstants;
const QSet<int> *dirtyTextures;
};
ShaderSyncData vertex;
ShaderSyncData fragment;
};
// Each ShaderEffect item has one node (render thread) and one manager (gui thread).
QSGShaderEffectNode(QSGGuiThreadShaderEffectManager *) { }
virtual QRectF updateNormalizedTextureSubRect(bool supportsAtlasTextures) = 0;
virtual void syncMaterial(SyncData *syncData) = 0;
void accept(QSGNodeVisitorEx *visitor) override { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); }
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QSGShaderEffectNode::DirtyShaderFlags)
#ifndef QT_NO_DEBUG_STREAM
Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug debug, const QSGShaderEffectNode::VariableData &vd);
#endif
class Q_QUICK_PRIVATE_EXPORT QSGGlyphNode : public QSGVisitableNode
{
public:
enum AntialiasingMode
{
GrayAntialiasing,
LowQualitySubPixelAntialiasing,
HighQualitySubPixelAntialiasing
};
QSGGlyphNode() {}
virtual void setGlyphs(const QPointF &position, const QGlyphRun &glyphs) = 0;
virtual void setColor(const QColor &color) = 0;
virtual void setStyle(QQuickText::TextStyle style) = 0;
virtual void setStyleColor(const QColor &color) = 0;
virtual QPointF baseLine() const = 0;
virtual QRectF boundingRect() const { return m_bounding_rect; }
virtual void setBoundingRect(const QRectF &bounds) { m_bounding_rect = bounds; }
virtual void setPreferredAntialiasingMode(AntialiasingMode) = 0;
virtual void update() = 0;
void setOwnerElement(QQuickItem *ownerElement) { m_ownerElement = ownerElement; }
QQuickItem *ownerElement() const { return m_ownerElement; }
void accept(QSGNodeVisitorEx *visitor) override { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); }
protected:
QRectF m_bounding_rect;
QQuickItem *m_ownerElement = nullptr;
};
class Q_QUICK_PRIVATE_EXPORT QSGDistanceFieldGlyphConsumer
{
public:
virtual ~QSGDistanceFieldGlyphConsumer() {}
virtual void invalidateGlyphs(const QVector<quint32> &glyphs) = 0;
QIntrusiveListNode node;
};
typedef QIntrusiveList<QSGDistanceFieldGlyphConsumer, &QSGDistanceFieldGlyphConsumer::node> QSGDistanceFieldGlyphConsumerList;
class Q_QUICK_PRIVATE_EXPORT QSGDistanceFieldGlyphCache
{
public:
QSGDistanceFieldGlyphCache(const QRawFont &font);
virtual ~QSGDistanceFieldGlyphCache();
struct Metrics {
qreal width;
qreal height;
qreal baselineX;
qreal baselineY;
bool isNull() const { return width == 0 || height == 0; }
};
struct TexCoord {
qreal x = 0;
qreal y = 0;
qreal width = -1;
qreal height = -1;
qreal xMargin = 0;
qreal yMargin = 0;
TexCoord() {}
bool isNull() const { return width <= 0 || height <= 0; }
bool isValid() const { return width >= 0 && height >= 0; }
};
struct Texture {
uint textureId = 0;
QRhiTexture *texture = nullptr;
QSize size;
bool rhiBased = false;
bool operator == (const Texture &other) const {
if (rhiBased != other.rhiBased)
return false;
if (rhiBased)
return texture == other.texture;
else
return textureId == other.textureId;
}
};
const QRawFont &referenceFont() const { return m_referenceFont; }
qreal fontScale(qreal pixelSize) const
{
return pixelSize / QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution);
}
int distanceFieldRadius() const
{
return QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution);
}
int glyphCount() const { return m_glyphCount; }
bool doubleGlyphResolution() const { return m_doubleGlyphResolution; }
Metrics glyphMetrics(glyph_t glyph, qreal pixelSize);
inline TexCoord glyphTexCoord(glyph_t glyph);
inline const Texture *glyphTexture(glyph_t glyph);
void populate(const QVector<glyph_t> &glyphs);
void release(const QVector<glyph_t> &glyphs);
void update();
void registerGlyphNode(QSGDistanceFieldGlyphConsumer *node) { m_registeredNodes.insert(node); }
void unregisterGlyphNode(QSGDistanceFieldGlyphConsumer *node) { m_registeredNodes.remove(node); }
virtual void registerOwnerElement(QQuickItem *ownerElement);
virtual void unregisterOwnerElement(QQuickItem *ownerElement);
virtual void processPendingGlyphs();
virtual bool eightBitFormatIsAlphaSwizzled() const = 0;
protected:
struct GlyphPosition {
glyph_t glyph;
QPointF position;
};
struct GlyphData {
Texture *texture = nullptr;
TexCoord texCoord;
QRectF boundingRect;
QPainterPath path;
quint32 ref = 0;
GlyphData() {}
};
virtual void requestGlyphs(const QSet<glyph_t> &glyphs) = 0;
virtual void storeGlyphs(const QList<QDistanceField> &glyphs) = 0;
virtual void referenceGlyphs(const QSet<glyph_t> &glyphs) = 0;
virtual void releaseGlyphs(const QSet<glyph_t> &glyphs) = 0;
void setGlyphsPosition(const QList<GlyphPosition> &glyphs);
void setGlyphsTexture(const QVector<glyph_t> &glyphs, const Texture &tex);
void markGlyphsToRender(const QVector<glyph_t> &glyphs);
inline void removeGlyph(glyph_t glyph);
void updateTexture(uint oldTex, uint newTex, const QSize &newTexSize);
void updateRhiTexture(QRhiTexture *oldTex, QRhiTexture *newTex, const QSize &newTexSize);
inline bool containsGlyph(glyph_t glyph);
uint textureIdForGlyph(glyph_t glyph) const;
GlyphData &glyphData(glyph_t glyph);
GlyphData &emptyData(glyph_t glyph);
#if defined(QSG_DISTANCEFIELD_CACHE_DEBUG)
void saveTexture(GLuint textureId, int width, int height) const;
#endif
bool m_doubleGlyphResolution;
protected:
QRawFont m_referenceFont;
private:
int m_glyphCount;
QList<Texture> m_textures;
QHash<glyph_t, GlyphData> m_glyphsData;
QDataBuffer<glyph_t> m_pendingGlyphs;
QSet<glyph_t> m_populatingGlyphs;
QSGDistanceFieldGlyphConsumerList m_registeredNodes;
static Texture s_emptyTexture;
};
inline QSGDistanceFieldGlyphCache::TexCoord QSGDistanceFieldGlyphCache::glyphTexCoord(glyph_t glyph)
{
return glyphData(glyph).texCoord;
}
inline const QSGDistanceFieldGlyphCache::Texture *QSGDistanceFieldGlyphCache::glyphTexture(glyph_t glyph)
{
return glyphData(glyph).texture;
}
inline void QSGDistanceFieldGlyphCache::removeGlyph(glyph_t glyph)
{
GlyphData &gd = glyphData(glyph);
gd.texCoord = TexCoord();
gd.texture = &s_emptyTexture;
}
inline bool QSGDistanceFieldGlyphCache::containsGlyph(glyph_t glyph)
{
return glyphData(glyph).texCoord.isValid();
}
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QSGGuiThreadShaderEffectManager::ShaderInfo::Type)
#endif