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:
Laszlo Agocs 2017-02-17 09:47:49 +01:00
parent 0abdf6db0e
commit 48c3173338
10 changed files with 119 additions and 5 deletions

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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;