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 setMirrorHorizontal(bool mirror) override;
|
||||
void setMirrorVertical(bool mirror) override;
|
||||
void setSamples(int) override { }
|
||||
|
||||
public Q_SLOTS:
|
||||
void markDirtyTexture() override;
|
||||
|
|
|
@ -7865,6 +7865,7 @@ QQuickItemLayer::QQuickItemLayer(QQuickItem *item)
|
|||
, m_effect(0)
|
||||
, m_effectSource(0)
|
||||
, m_textureMirroring(QQuickShaderEffectSource::MirrorVertically)
|
||||
, m_samples(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -7939,6 +7940,7 @@ void QQuickItemLayer::activate()
|
|||
m_effectSource->setWrapMode(m_wrapMode);
|
||||
m_effectSource->setFormat(m_format);
|
||||
m_effectSource->setTextureMirroring(m_textureMirroring);
|
||||
m_effectSource->setSamples(m_samples);
|
||||
|
||||
if (m_effectComponent)
|
||||
activateEffect();
|
||||
|
@ -8231,6 +8233,44 @@ void QQuickItemLayer::setTextureMirroring(QQuickShaderEffectSource::TextureMirro
|
|||
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
|
||||
|
||||
|
|
|
@ -152,6 +152,8 @@ class QQuickItemLayer : public QObject, public QQuickItemChangeListener
|
|||
Q_PROPERTY(QByteArray samplerName READ name WRITE setName NOTIFY nameChanged)
|
||||
Q_PROPERTY(QQmlComponent *effect READ effect WRITE setEffect NOTIFY effectChanged)
|
||||
Q_PROPERTY(QQuickShaderEffectSource::TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged)
|
||||
Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged)
|
||||
|
||||
public:
|
||||
QQuickItemLayer(QQuickItem *item);
|
||||
~QQuickItemLayer();
|
||||
|
@ -189,6 +191,9 @@ public:
|
|||
QQuickShaderEffectSource::TextureMirroring textureMirroring() const { return m_textureMirroring; }
|
||||
void setTextureMirroring(QQuickShaderEffectSource::TextureMirroring mirroring);
|
||||
|
||||
int samples() const { return m_samples; }
|
||||
void setSamples(int count);
|
||||
|
||||
QQuickShaderEffectSource *effectSource() const { return m_effectSource; }
|
||||
|
||||
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
|
||||
|
@ -213,6 +218,7 @@ Q_SIGNALS:
|
|||
void formatChanged(QQuickShaderEffectSource::Format format);
|
||||
void sourceRectChanged(const QRectF &sourceRect);
|
||||
void textureMirroringChanged(QQuickShaderEffectSource::TextureMirroring mirroring);
|
||||
void samplesChanged(int count);
|
||||
|
||||
private:
|
||||
friend class QQuickTransformAnimatorJob;
|
||||
|
@ -237,6 +243,7 @@ private:
|
|||
QQuickItem *m_effect;
|
||||
QQuickShaderEffectSource *m_effectSource;
|
||||
QQuickShaderEffectSource::TextureMirroring m_textureMirroring;
|
||||
int m_samples;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -385,6 +385,10 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
|
|||
qmlRegisterUncreatableType<QQuickBasePositioner, 9>(uri, 2, 9, "Positioner",
|
||||
QStringLiteral("Positioner is an abstract type that is only available as an attached property."));
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(quick_shadereffect)
|
||||
qmlRegisterType<QQuickShaderEffectSource, 2>(uri, 2, 9, "ShaderEffectSource");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void initResources()
|
||||
|
|
|
@ -189,6 +189,7 @@ QQuickShaderEffectSource::QQuickShaderEffectSource(QQuickItem *parent)
|
|||
, m_sourceItem(0)
|
||||
, m_textureSize(0, 0)
|
||||
, m_format(RGBA)
|
||||
, m_samples(0)
|
||||
, m_live(true)
|
||||
, m_hideSource(false)
|
||||
, m_mipmap(false)
|
||||
|
@ -581,6 +582,44 @@ void QQuickShaderEffectSource::setTextureMirroring(TextureMirroring mirroring)
|
|||
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()
|
||||
|
||||
|
@ -683,6 +722,7 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
|
|||
m_texture->setHasMipmaps(m_mipmap);
|
||||
m_texture->setMirrorHorizontal(m_textureMirroring & MirrorHorizontally);
|
||||
m_texture->setMirrorVertical(m_textureMirroring & MirrorVertically);
|
||||
m_texture->setSamples(m_samples);
|
||||
|
||||
if (m_grab)
|
||||
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 recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
|
||||
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:
|
||||
enum WrapMode {
|
||||
|
@ -150,6 +151,9 @@ public:
|
|||
|
||||
Q_INVOKABLE void scheduleUpdate();
|
||||
|
||||
int samples() const;
|
||||
void setSamples(int count);
|
||||
|
||||
Q_SIGNALS:
|
||||
void wrapModeChanged();
|
||||
void sourceItemChanged();
|
||||
|
@ -161,6 +165,7 @@ Q_SIGNALS:
|
|||
void mipmapChanged();
|
||||
void recursiveChanged();
|
||||
void textureMirroringChanged();
|
||||
void samplesChanged();
|
||||
|
||||
void scheduledUpdateCompleted();
|
||||
|
||||
|
@ -185,6 +190,7 @@ private:
|
|||
QRectF m_sourceRect;
|
||||
QSize m_textureSize;
|
||||
Format m_format;
|
||||
int m_samples;
|
||||
uint m_live : 1;
|
||||
uint m_hideSource : 1;
|
||||
uint m_mipmap : 1;
|
||||
|
|
|
@ -93,6 +93,7 @@ public:
|
|||
void setDevicePixelRatio(qreal ratio) override;
|
||||
void setMirrorHorizontal(bool mirror) override;
|
||||
void setMirrorVertical(bool mirror) override;
|
||||
void setSamples(int) override { }
|
||||
|
||||
public slots:
|
||||
void markDirtyTexture() override;
|
||||
|
|
|
@ -209,6 +209,7 @@ public:
|
|||
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;
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ QSGDefaultLayer::QSGDefaultLayer(QSGRenderContext *context)
|
|||
#ifdef QSG_DEBUG_FBO_OVERLAY
|
||||
, m_debugOverlay(0)
|
||||
#endif
|
||||
, m_samples(0)
|
||||
, m_mipmap(false)
|
||||
, m_live(true)
|
||||
, m_recursive(false)
|
||||
|
@ -313,11 +314,20 @@ void QSGDefaultLayer::grab()
|
|||
|
||||
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
|
||||
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_context->openglContext()->format().samples() <= 1) {
|
||||
if (effectiveSamples <= 1) {
|
||||
m_multisampling = false;
|
||||
} else {
|
||||
const QSet<QByteArray> extensions = m_context->openglContext()->extensions();
|
||||
|
@ -333,7 +343,7 @@ void QSGDefaultLayer::grab()
|
|||
QOpenGLFramebufferObjectFormat format;
|
||||
|
||||
format.setInternalTextureFormat(m_format);
|
||||
format.setSamples(m_context->openglContext()->format().samples());
|
||||
format.setSamples(effectiveSamples);
|
||||
m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
|
||||
m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
|
||||
} else {
|
||||
|
|
|
@ -113,6 +113,9 @@ public:
|
|||
|
||||
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:
|
||||
void markDirtyTexture() Q_DECL_OVERRIDE;
|
||||
void invalidated() Q_DECL_OVERRIDE;
|
||||
|
@ -138,6 +141,7 @@ private:
|
|||
#endif
|
||||
|
||||
QSGDefaultRenderContext *m_context;
|
||||
int m_samples;
|
||||
|
||||
uint m_mipmap : 1;
|
||||
uint m_live : 1;
|
||||
|
|
Loading…
Reference in New Issue