Add samples property for Item.layer and ShaderEffectSource
[ChangeLog][Qt Quick] Added the properties ShaderEffectSource.samples and Item.layer.samples to allow requesting MSAA rendering of an item subtree, without enabling multisampling for the entire scene. Task-number: QTBUG-58945 Change-Id: I9102cfabba10d4dc1e7ad2aa0b258ada6d9a5a47 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
parent
0abdf6db0e
commit
48c3173338
|
@ -86,6 +86,7 @@ public:
|
||||||
void setDevicePixelRatio(qreal ratio) override;
|
void setDevicePixelRatio(qreal ratio) override;
|
||||||
void setMirrorHorizontal(bool mirror) override;
|
void setMirrorHorizontal(bool mirror) override;
|
||||||
void setMirrorVertical(bool mirror) override;
|
void setMirrorVertical(bool mirror) override;
|
||||||
|
void setSamples(int) override { }
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void markDirtyTexture() override;
|
void markDirtyTexture() override;
|
||||||
|
|
|
@ -7865,6 +7865,7 @@ QQuickItemLayer::QQuickItemLayer(QQuickItem *item)
|
||||||
, m_effect(0)
|
, m_effect(0)
|
||||||
, m_effectSource(0)
|
, m_effectSource(0)
|
||||||
, m_textureMirroring(QQuickShaderEffectSource::MirrorVertically)
|
, m_textureMirroring(QQuickShaderEffectSource::MirrorVertically)
|
||||||
|
, m_samples(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7939,6 +7940,7 @@ void QQuickItemLayer::activate()
|
||||||
m_effectSource->setWrapMode(m_wrapMode);
|
m_effectSource->setWrapMode(m_wrapMode);
|
||||||
m_effectSource->setFormat(m_format);
|
m_effectSource->setFormat(m_format);
|
||||||
m_effectSource->setTextureMirroring(m_textureMirroring);
|
m_effectSource->setTextureMirroring(m_textureMirroring);
|
||||||
|
m_effectSource->setSamples(m_samples);
|
||||||
|
|
||||||
if (m_effectComponent)
|
if (m_effectComponent)
|
||||||
activateEffect();
|
activateEffect();
|
||||||
|
@ -8231,6 +8233,44 @@ void QQuickItemLayer::setTextureMirroring(QQuickShaderEffectSource::TextureMirro
|
||||||
emit textureMirroringChanged(mirroring);
|
emit textureMirroringChanged(mirroring);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty enumeration QtQuick::Item::layer.samples
|
||||||
|
\since 5.10
|
||||||
|
|
||||||
|
This property allows requesting multisampled rendering in the layer.
|
||||||
|
|
||||||
|
By default multisampling is enabled whenever multisampling is
|
||||||
|
enabled for the entire window, assuming the scenegraph renderer in
|
||||||
|
use and the underlying graphics API supports this.
|
||||||
|
|
||||||
|
By setting the value to 2, 4, etc. multisampled rendering can be requested
|
||||||
|
for a part of the scene without enabling multisampling for the entire
|
||||||
|
scene. This way multisampling is applied only to a given subtree, which can
|
||||||
|
lead to significant performance gains since multisampling is not applied to
|
||||||
|
other parts of the scene.
|
||||||
|
|
||||||
|
\note Enabling multisampling can be potentially expensive regardless of the
|
||||||
|
layer's size, as it incurs a hardware and driver dependent performance and
|
||||||
|
memory cost.
|
||||||
|
|
||||||
|
\note This property is only functional when support for multisample
|
||||||
|
renderbuffers and framebuffer blits is available. Otherwise the value is
|
||||||
|
silently ignored.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void QQuickItemLayer::setSamples(int count)
|
||||||
|
{
|
||||||
|
if (m_samples == count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_samples = count;
|
||||||
|
|
||||||
|
if (m_effectSource)
|
||||||
|
m_effectSource->setSamples(m_samples);
|
||||||
|
|
||||||
|
emit samplesChanged(count);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty string QtQuick::Item::layer.samplerName
|
\qmlproperty string QtQuick::Item::layer.samplerName
|
||||||
|
|
||||||
|
|
|
@ -152,6 +152,8 @@ class QQuickItemLayer : public QObject, public QQuickItemChangeListener
|
||||||
Q_PROPERTY(QByteArray samplerName READ name WRITE setName NOTIFY nameChanged)
|
Q_PROPERTY(QByteArray samplerName READ name WRITE setName NOTIFY nameChanged)
|
||||||
Q_PROPERTY(QQmlComponent *effect READ effect WRITE setEffect NOTIFY effectChanged)
|
Q_PROPERTY(QQmlComponent *effect READ effect WRITE setEffect NOTIFY effectChanged)
|
||||||
Q_PROPERTY(QQuickShaderEffectSource::TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged)
|
Q_PROPERTY(QQuickShaderEffectSource::TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged)
|
||||||
|
Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QQuickItemLayer(QQuickItem *item);
|
QQuickItemLayer(QQuickItem *item);
|
||||||
~QQuickItemLayer();
|
~QQuickItemLayer();
|
||||||
|
@ -189,6 +191,9 @@ public:
|
||||||
QQuickShaderEffectSource::TextureMirroring textureMirroring() const { return m_textureMirroring; }
|
QQuickShaderEffectSource::TextureMirroring textureMirroring() const { return m_textureMirroring; }
|
||||||
void setTextureMirroring(QQuickShaderEffectSource::TextureMirroring mirroring);
|
void setTextureMirroring(QQuickShaderEffectSource::TextureMirroring mirroring);
|
||||||
|
|
||||||
|
int samples() const { return m_samples; }
|
||||||
|
void setSamples(int count);
|
||||||
|
|
||||||
QQuickShaderEffectSource *effectSource() const { return m_effectSource; }
|
QQuickShaderEffectSource *effectSource() const { return m_effectSource; }
|
||||||
|
|
||||||
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
|
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
|
||||||
|
@ -213,6 +218,7 @@ Q_SIGNALS:
|
||||||
void formatChanged(QQuickShaderEffectSource::Format format);
|
void formatChanged(QQuickShaderEffectSource::Format format);
|
||||||
void sourceRectChanged(const QRectF &sourceRect);
|
void sourceRectChanged(const QRectF &sourceRect);
|
||||||
void textureMirroringChanged(QQuickShaderEffectSource::TextureMirroring mirroring);
|
void textureMirroringChanged(QQuickShaderEffectSource::TextureMirroring mirroring);
|
||||||
|
void samplesChanged(int count);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class QQuickTransformAnimatorJob;
|
friend class QQuickTransformAnimatorJob;
|
||||||
|
@ -237,6 +243,7 @@ private:
|
||||||
QQuickItem *m_effect;
|
QQuickItem *m_effect;
|
||||||
QQuickShaderEffectSource *m_effectSource;
|
QQuickShaderEffectSource *m_effectSource;
|
||||||
QQuickShaderEffectSource::TextureMirroring m_textureMirroring;
|
QQuickShaderEffectSource::TextureMirroring m_textureMirroring;
|
||||||
|
int m_samples;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -385,6 +385,10 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
|
||||||
qmlRegisterUncreatableType<QQuickBasePositioner, 9>(uri, 2, 9, "Positioner",
|
qmlRegisterUncreatableType<QQuickBasePositioner, 9>(uri, 2, 9, "Positioner",
|
||||||
QStringLiteral("Positioner is an abstract type that is only available as an attached property."));
|
QStringLiteral("Positioner is an abstract type that is only available as an attached property."));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if QT_CONFIG(quick_shadereffect)
|
||||||
|
qmlRegisterType<QQuickShaderEffectSource, 2>(uri, 2, 9, "ShaderEffectSource");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initResources()
|
static void initResources()
|
||||||
|
|
|
@ -189,6 +189,7 @@ QQuickShaderEffectSource::QQuickShaderEffectSource(QQuickItem *parent)
|
||||||
, m_sourceItem(0)
|
, m_sourceItem(0)
|
||||||
, m_textureSize(0, 0)
|
, m_textureSize(0, 0)
|
||||||
, m_format(RGBA)
|
, m_format(RGBA)
|
||||||
|
, m_samples(0)
|
||||||
, m_live(true)
|
, m_live(true)
|
||||||
, m_hideSource(false)
|
, m_hideSource(false)
|
||||||
, m_mipmap(false)
|
, m_mipmap(false)
|
||||||
|
@ -581,6 +582,44 @@ void QQuickShaderEffectSource::setTextureMirroring(TextureMirroring mirroring)
|
||||||
emit textureMirroringChanged();
|
emit textureMirroringChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty int QtQuick::ShaderEffectSource::samples
|
||||||
|
\since 5.10
|
||||||
|
|
||||||
|
This property allows requesting multisampled rendering.
|
||||||
|
|
||||||
|
By default multisampling is enabled whenever multisampling is enabled for
|
||||||
|
the entire window, assuming the scenegraph renderer in use and the
|
||||||
|
underlying graphics API supports this.
|
||||||
|
|
||||||
|
By setting the value to 2, 4, etc. multisampled rendering can be requested
|
||||||
|
for a part of the scene without enabling multisampling for the entire
|
||||||
|
scene. This way multisampling is applied only to a given subtree, which can
|
||||||
|
lead to significant performance gains since multisampling is not applied to
|
||||||
|
other parts of the scene.
|
||||||
|
|
||||||
|
\note Enabling multisampling can be potentially expensive regardless of the
|
||||||
|
layer's size, as it incurs a hardware and driver dependent performance and
|
||||||
|
memory cost.
|
||||||
|
|
||||||
|
\note This property is only functional when support for multisample
|
||||||
|
renderbuffers and framebuffer blits is available. Otherwise the value is
|
||||||
|
silently ignored.
|
||||||
|
*/
|
||||||
|
int QQuickShaderEffectSource::samples() const
|
||||||
|
{
|
||||||
|
return m_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QQuickShaderEffectSource::setSamples(int count)
|
||||||
|
{
|
||||||
|
if (count == m_samples)
|
||||||
|
return;
|
||||||
|
m_samples = count;
|
||||||
|
update();
|
||||||
|
emit samplesChanged();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlmethod QtQuick::ShaderEffectSource::scheduleUpdate()
|
\qmlmethod QtQuick::ShaderEffectSource::scheduleUpdate()
|
||||||
|
|
||||||
|
@ -683,6 +722,7 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
|
||||||
m_texture->setHasMipmaps(m_mipmap);
|
m_texture->setHasMipmaps(m_mipmap);
|
||||||
m_texture->setMirrorHorizontal(m_textureMirroring & MirrorHorizontally);
|
m_texture->setMirrorHorizontal(m_textureMirroring & MirrorHorizontally);
|
||||||
m_texture->setMirrorVertical(m_textureMirroring & MirrorVertically);
|
m_texture->setMirrorVertical(m_textureMirroring & MirrorVertically);
|
||||||
|
m_texture->setSamples(m_samples);
|
||||||
|
|
||||||
if (m_grab)
|
if (m_grab)
|
||||||
m_texture->scheduleUpdate();
|
m_texture->scheduleUpdate();
|
||||||
|
|
|
@ -88,6 +88,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectSource : public QQuickItem, publi
|
||||||
Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged)
|
Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged)
|
||||||
Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
|
Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
|
||||||
Q_PROPERTY(TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged REVISION 1)
|
Q_PROPERTY(TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged REVISION 1)
|
||||||
|
Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged REVISION 2)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum WrapMode {
|
enum WrapMode {
|
||||||
|
@ -150,6 +151,9 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void scheduleUpdate();
|
Q_INVOKABLE void scheduleUpdate();
|
||||||
|
|
||||||
|
int samples() const;
|
||||||
|
void setSamples(int count);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void wrapModeChanged();
|
void wrapModeChanged();
|
||||||
void sourceItemChanged();
|
void sourceItemChanged();
|
||||||
|
@ -161,6 +165,7 @@ Q_SIGNALS:
|
||||||
void mipmapChanged();
|
void mipmapChanged();
|
||||||
void recursiveChanged();
|
void recursiveChanged();
|
||||||
void textureMirroringChanged();
|
void textureMirroringChanged();
|
||||||
|
void samplesChanged();
|
||||||
|
|
||||||
void scheduledUpdateCompleted();
|
void scheduledUpdateCompleted();
|
||||||
|
|
||||||
|
@ -185,6 +190,7 @@ private:
|
||||||
QRectF m_sourceRect;
|
QRectF m_sourceRect;
|
||||||
QSize m_textureSize;
|
QSize m_textureSize;
|
||||||
Format m_format;
|
Format m_format;
|
||||||
|
int m_samples;
|
||||||
uint m_live : 1;
|
uint m_live : 1;
|
||||||
uint m_hideSource : 1;
|
uint m_hideSource : 1;
|
||||||
uint m_mipmap : 1;
|
uint m_mipmap : 1;
|
||||||
|
|
|
@ -93,6 +93,7 @@ public:
|
||||||
void setDevicePixelRatio(qreal ratio) override;
|
void setDevicePixelRatio(qreal ratio) override;
|
||||||
void setMirrorHorizontal(bool mirror) override;
|
void setMirrorHorizontal(bool mirror) override;
|
||||||
void setMirrorVertical(bool mirror) override;
|
void setMirrorVertical(bool mirror) override;
|
||||||
|
void setSamples(int) override { }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void markDirtyTexture() override;
|
void markDirtyTexture() override;
|
||||||
|
|
|
@ -209,6 +209,7 @@ public:
|
||||||
virtual void setDevicePixelRatio(qreal ratio) = 0;
|
virtual void setDevicePixelRatio(qreal ratio) = 0;
|
||||||
virtual void setMirrorHorizontal(bool mirror) = 0;
|
virtual void setMirrorHorizontal(bool mirror) = 0;
|
||||||
virtual void setMirrorVertical(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 markDirtyTexture() = 0;
|
||||||
Q_SLOT virtual void invalidated() = 0;
|
Q_SLOT virtual void invalidated() = 0;
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,7 @@ QSGDefaultLayer::QSGDefaultLayer(QSGRenderContext *context)
|
||||||
#ifdef QSG_DEBUG_FBO_OVERLAY
|
#ifdef QSG_DEBUG_FBO_OVERLAY
|
||||||
, m_debugOverlay(0)
|
, m_debugOverlay(0)
|
||||||
#endif
|
#endif
|
||||||
|
, m_samples(0)
|
||||||
, m_mipmap(false)
|
, m_mipmap(false)
|
||||||
, m_live(true)
|
, m_live(true)
|
||||||
, m_recursive(false)
|
, m_recursive(false)
|
||||||
|
@ -313,11 +314,20 @@ void QSGDefaultLayer::grab()
|
||||||
|
|
||||||
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
|
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
|
||||||
bool deleteFboLater = false;
|
bool deleteFboLater = false;
|
||||||
if (!m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format
|
|
||||||
|| (!m_fbo->format().mipmap() && m_mipmap))
|
int effectiveSamples = m_samples;
|
||||||
{
|
// By default m_samples is 0. Fall back to the context's setting in this case.
|
||||||
|
if (effectiveSamples == 0)
|
||||||
|
effectiveSamples = m_context->openglContext()->format().samples();
|
||||||
|
|
||||||
|
const bool needsNewFbo = !m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format;
|
||||||
|
const bool mipmapGotEnabled = m_fbo && !m_fbo->format().mipmap() && m_mipmap;
|
||||||
|
const bool msaaGotEnabled = effectiveSamples > 1 && (!m_secondaryFbo || m_secondaryFbo->format().samples() != effectiveSamples);
|
||||||
|
const bool msaaGotDisabled = effectiveSamples <= 1 && m_secondaryFbo;
|
||||||
|
|
||||||
|
if (needsNewFbo || mipmapGotEnabled || msaaGotEnabled || msaaGotDisabled) {
|
||||||
if (!m_multisamplingChecked) {
|
if (!m_multisamplingChecked) {
|
||||||
if (m_context->openglContext()->format().samples() <= 1) {
|
if (effectiveSamples <= 1) {
|
||||||
m_multisampling = false;
|
m_multisampling = false;
|
||||||
} else {
|
} else {
|
||||||
const QSet<QByteArray> extensions = m_context->openglContext()->extensions();
|
const QSet<QByteArray> extensions = m_context->openglContext()->extensions();
|
||||||
|
@ -333,7 +343,7 @@ void QSGDefaultLayer::grab()
|
||||||
QOpenGLFramebufferObjectFormat format;
|
QOpenGLFramebufferObjectFormat format;
|
||||||
|
|
||||||
format.setInternalTextureFormat(m_format);
|
format.setInternalTextureFormat(m_format);
|
||||||
format.setSamples(m_context->openglContext()->format().samples());
|
format.setSamples(effectiveSamples);
|
||||||
m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
|
m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
|
||||||
m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
|
m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -113,6 +113,9 @@ public:
|
||||||
|
|
||||||
QRectF normalizedTextureSubRect() const Q_DECL_OVERRIDE;
|
QRectF normalizedTextureSubRect() const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
int samples() const { return m_samples; }
|
||||||
|
void setSamples(int samples) Q_DECL_OVERRIDE { m_samples = samples; }
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void markDirtyTexture() Q_DECL_OVERRIDE;
|
void markDirtyTexture() Q_DECL_OVERRIDE;
|
||||||
void invalidated() Q_DECL_OVERRIDE;
|
void invalidated() Q_DECL_OVERRIDE;
|
||||||
|
@ -138,6 +141,7 @@ private:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QSGDefaultRenderContext *m_context;
|
QSGDefaultRenderContext *m_context;
|
||||||
|
int m_samples;
|
||||||
|
|
||||||
uint m_mipmap : 1;
|
uint m_mipmap : 1;
|
||||||
uint m_live : 1;
|
uint m_live : 1;
|
||||||
|
|
Loading…
Reference in New Issue