Add Image::mipmap to support mipmapping of images.
authorGunnar Sletta <gunnar.sletta@jollamobile.com>
Mon, 27 Jan 2014 09:08:14 +0000 (10:08 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Wed, 12 Feb 2014 08:24:40 +0000 (09:24 +0100)
[ChangeLog][QtQuick] New feature: Image.mipmap

Task-number: QTBUG-19961

Change-Id: I13acb2408d5b126790adaf9d324ad4beda1e3646
Reviewed-by: Michael Brasser <michael.brasser@live.com>
15 files changed:
src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
src/quick/items/context2d/qquickcontext2dtexture.cpp
src/quick/items/qquickimage.cpp
src/quick/items/qquickimage_p.h
src/quick/items/qquickimage_p_p.h
src/quick/items/qquickitemsmodule.cpp
src/quick/items/qquickwindow.cpp
src/quick/scenegraph/util/qsgatlastexture.cpp
src/quick/scenegraph/util/qsgpainternode.cpp
src/quick/scenegraph/util/qsgtexture.cpp
src/quick/scenegraph/util/qsgtexture_p.h
tests/auto/quick/scenegraph/data/mipmap_large.png [new file with mode: 0644]
tests/auto/quick/scenegraph/data/mipmap_small.png [new file with mode: 0644]
tests/auto/quick/scenegraph/data/render_Mipmap.qml [new file with mode: 0644]
tests/auto/quick/scenegraph/tst_scenegraph.cpp

index 16075f0..278733d 100644 (file)
@@ -729,6 +729,9 @@ with multiple windows.
   QQuickWindow::setColor() will be used in a call to \c glClear(),
   which is potentially faster.
 
+  \li Mipmapped Image items are not placed in global atlas and will
+  not be batched.
+
   \endlist
 
   If an application performs poorly, make sure that rendering is
index 8dd48b4..d3f2a95 100644 (file)
@@ -427,7 +427,6 @@ QSGTexture *QQuickContext2DFBOTexture::textureForNextFrame(QSGTexture *lastTextu
     if (m_fbo) {
         if (!texture) {
             texture = new QSGPlainTexture();
-            texture->setHasMipmaps(false);
             texture->setHasAlphaChannel(true);
             texture->setOwnsTexture(false);
             m_dirtyTexture = true;
@@ -655,7 +654,6 @@ QSGTexture *QQuickContext2DImageTexture::textureForNextFrame(QSGTexture *last)
 
     if (!texture) {
         texture = new QSGPlainTexture();
-        texture->setHasMipmaps(false);
         texture->setHasAlphaChannel(true);
         m_dirtyTexture = true;
     }
index 62ac72d..b6b8a2a 100644 (file)
@@ -72,7 +72,7 @@ public:
     QSGTexture *texture() const {
         if (m_texture) {
             m_texture->setFiltering(m_smooth ? QSGTexture::Linear : QSGTexture::Nearest);
-            m_texture->setMipmapFiltering(QSGTexture::Nearest);
+            m_texture->setMipmapFiltering(m_mipmap ? QSGTexture::Linear : QSGTexture::None);
             m_texture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
             m_texture->setVerticalWrapMode(QSGTexture::ClampToEdge);
         }
@@ -83,6 +83,7 @@ public:
 
     QSGTexture *m_texture;
     bool m_smooth;
+    bool m_mipmap;
 };
 
 #include "qquickimage.moc"
@@ -92,6 +93,7 @@ QQuickImagePrivate::QQuickImagePrivate()
     , paintedWidth(0)
     , paintedHeight(0)
     , pixmapChanged(false)
+    , mipmap(false)
     , hAlign(QQuickImage::AlignHCenter)
     , vAlign(QQuickImage::AlignVCenter)
     , provider(0)
@@ -372,6 +374,8 @@ qreal QQuickImage::paintedHeight() const
     no visual or performance effect.
 
     By default, this property is set to true.
+
+    \sa mipmap
 */
 
 /*!
@@ -549,6 +553,7 @@ QSGTextureProvider *QQuickImage::textureProvider() const
         QQuickImagePrivate *dd = const_cast<QQuickImagePrivate *>(d);
         dd->provider = new QQuickImageTextureProvider;
         dd->provider->m_smooth = d->smooth;
+        dd->provider->m_mipmap = d->mipmap;
         dd->provider->updateTexture(d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window()));
     }
 
@@ -564,6 +569,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
     // Copy over the current texture state into the texture provider...
     if (d->provider) {
         d->provider->m_smooth = d->smooth;
+        d->provider->m_mipmap = d->mipmap;
         d->provider->updateTexture(texture);
     }
 
@@ -673,13 +679,14 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
     if (d->pixmapChanged) {
         // force update the texture in the node to trigger reconstruction of
         // geometry and the likes when a atlas segment has changed.
-        if (texture->isAtlasTexture() && (hWrap == QSGTexture::Repeat || vWrap == QSGTexture::Repeat))
+        if (texture->isAtlasTexture() && (hWrap == QSGTexture::Repeat || vWrap == QSGTexture::Repeat || d->mipmap))
             node->setTexture(texture->removedFromAtlas());
         else
             node->setTexture(texture);
         d->pixmapChanged = false;
     }
 
+    node->setMipmapFiltering(d->mipmap ? QSGTexture::Linear : QSGTexture::None);
     node->setHorizontalWrapMode(hWrap);
     node->setVerticalWrapMode(vWrap);
     node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
@@ -746,4 +753,38 @@ void QQuickImage::setHorizontalAlignment(HAlignment align)
     emit horizontalAlignmentChanged(align);
 }
 
+/*!
+    \qmlproperty bool QtQuick::Image::mipmap
+    \since 5.3
+
+    This property holds whether the image uses mipmap filtering when scaled or
+    transformed.
+
+    Mipmap filtering gives better visual quality when scaling down
+    compared to smooth, but it may come at a performance cost (both when
+    initializing the image and during rendering).
+
+    By default, this property is set to false.
+
+    \sa smooth
+ */
+
+bool QQuickImage::mipmap() const
+{
+    Q_D(const QQuickImage);
+    return d->mipmap;
+}
+
+void QQuickImage::setMipmap(bool use)
+{
+    Q_D(QQuickImage);
+    if (d->mipmap == use)
+        return;
+    d->mipmap = use;
+    emit mipmapChanged(d->mipmap);
+
+    d->pixmapChanged = true;
+    update();
+}
+
 QT_END_NAMESPACE
index e62c355..902e613 100644 (file)
@@ -60,6 +60,7 @@ class Q_AUTOTEST_EXPORT QQuickImage : public QQuickImageBase
     Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedGeometryChanged)
     Q_PROPERTY(HAlignment horizontalAlignment READ horizontalAlignment WRITE setHorizontalAlignment NOTIFY horizontalAlignmentChanged)
     Q_PROPERTY(VAlignment verticalAlignment READ verticalAlignment WRITE setVerticalAlignment NOTIFY verticalAlignmentChanged)
+    Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged REVISION 1)
 
 public:
     QQuickImage(QQuickItem *parent=0);
@@ -91,11 +92,15 @@ public:
     bool isTextureProvider() const { return true; }
     QSGTextureProvider *textureProvider() const;
 
+    bool mipmap() const;
+    void setMipmap(bool use);
+
 Q_SIGNALS:
     void fillModeChanged();
     void paintedGeometryChanged();
     void horizontalAlignmentChanged(HAlignment alignment);
     void verticalAlignmentChanged(VAlignment alignment);
+    void mipmapChanged(bool);
 
 protected:
     QQuickImage(QQuickImagePrivate &dd, QQuickItem *parent);
index 632f76c..de88662 100644 (file)
@@ -73,6 +73,7 @@ public:
     void setImage(const QImage &img);
 
     bool pixmapChanged : 1;
+    bool mipmap : 1;
     QQuickImage::HAlignment hAlign;
     QQuickImage::VAlignment vAlign;
 
index a52ccf4..c9c8eea 100644 (file)
@@ -272,6 +272,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
 
     qmlRegisterType<QQuickText, 3>(uri, 2, 3, "Text");
     qmlRegisterType<QQuickTextEdit, 3>(uri, 2, 3, "TextEdit");
+    qmlRegisterType<QQuickImage, 1>(uri, 2, 3,"Image");
 }
 
 static void initResources()
index 6778cf1..3828c89 100644 (file)
@@ -3094,7 +3094,6 @@ QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, Create
         QSGPlainTexture *texture = new QSGPlainTexture();
         texture->setTextureId(id);
         texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
-        texture->setHasMipmaps(options & TextureHasMipmaps);
         texture->setOwnsTexture(options & TextureOwnsGLTexture);
         texture->setTextureSize(size);
         return texture;
index e6a2096..e399492 100644 (file)
@@ -459,6 +459,7 @@ QSGTexture *Texture::removedFromAtlas() const
         m_nonatlas_texture = new QSGPlainTexture();
         m_nonatlas_texture->setImage(m_image);
         m_nonatlas_texture->setFiltering(filtering());
+        m_nonatlas_texture->setMipmapFiltering(mipmapFiltering());
     }
     return m_nonatlas_texture;
 }
index 797fc4d..ec44a99 100644 (file)
@@ -205,7 +205,6 @@ void QSGPainterNode::update()
 
 void QSGPainterNode::updateTexture()
 {
-    m_texture->setHasMipmaps(m_mipmapping);
     m_texture->setHasAlphaChannel(!m_opaquePainting);
     m_material.setTexture(m_texture);
     m_materialO.setTexture(m_texture);
index b738896..9620e48 100644 (file)
@@ -533,7 +533,6 @@ QSGPlainTexture::QSGPlainTexture()
     : QSGTexture()
     , m_texture_id(0)
     , m_has_alpha(false)
-    , m_has_mipmaps(false)
     , m_dirty_texture(false)
     , m_dirty_bind_options(false)
     , m_owns_texture(true)
@@ -597,18 +596,11 @@ void QSGPlainTexture::setTextureId(int id)
     m_mipmaps_generated = false;
 }
 
-void QSGPlainTexture::setHasMipmaps(bool mm)
-{
-    m_has_mipmaps = mm;
-    m_mipmaps_generated = false;
-}
-
-
 void QSGPlainTexture::bind()
 {
     if (!m_dirty_texture) {
         glBindTexture(GL_TEXTURE_2D, m_texture_id);
-        if (m_has_mipmaps && !m_mipmaps_generated) {
+        if (mipmapFiltering() != QSGTexture::None && !m_mipmaps_generated) {
             QOpenGLContext *ctx = QOpenGLContext::currentContext();
             ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
             m_mipmaps_generated = true;
@@ -642,11 +634,8 @@ void QSGPlainTexture::bind()
         }
         m_texture_id = 0;
         m_texture_size = QSize();
-        m_has_mipmaps = false;
         m_has_alpha = false;
 
-
-
         return;
     }
 
@@ -726,7 +715,7 @@ void QSGPlainTexture::bind()
 #endif
 
 
-    if (m_has_mipmaps) {
+    if (mipmapFiltering() != QSGTexture::None) {
         context->functions()->glGenerateMipmap(GL_TEXTURE_2D);
         m_mipmaps_generated = true;
     }
index e0d386e..bc81569 100644 (file)
@@ -85,8 +85,7 @@ public:
     void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; }
     bool hasAlphaChannel() const { return m_has_alpha; }
 
-    void setHasMipmaps(bool mm);
-    bool hasMipmaps() const { return m_has_mipmaps; }
+    bool hasMipmaps() const { return mipmapFiltering() != QSGTexture::None; }
 
     void setImage(const QImage &image);
     const QImage &image() { return m_image; }
@@ -107,7 +106,6 @@ protected:
     QRectF m_texture_rect;
 
     uint m_has_alpha : 1;
-    uint m_has_mipmaps : 1;
     uint m_dirty_texture : 1;
     uint m_dirty_bind_options : 1;
     uint m_owns_texture : 1;
diff --git a/tests/auto/quick/scenegraph/data/mipmap_large.png b/tests/auto/quick/scenegraph/data/mipmap_large.png
new file mode 100644 (file)
index 0000000..9cb0fc7
Binary files /dev/null and b/tests/auto/quick/scenegraph/data/mipmap_large.png differ
diff --git a/tests/auto/quick/scenegraph/data/mipmap_small.png b/tests/auto/quick/scenegraph/data/mipmap_small.png
new file mode 100644 (file)
index 0000000..dc5216f
Binary files /dev/null and b/tests/auto/quick/scenegraph/data/mipmap_small.png differ
diff --git a/tests/auto/quick/scenegraph/data/render_Mipmap.qml b/tests/auto/quick/scenegraph/data/render_Mipmap.qml
new file mode 100644 (file)
index 0000000..0a6195f
--- /dev/null
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite 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 Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+
+/*
+    The test verifies that scaled down mipmapped images contains
+    colors from all pixels.
+
+    #samples: 2
+                 PixelPos     R    G    B    Error-tolerance
+    #final:        0   0     0.33 0.33 0.33        0.1
+    #final:        1   0     0.33 0.33 0.33        0.1
+*/
+
+RenderTestBase
+{
+    Image {
+        x: 0
+        y: 0
+        transformOrigin: Item.TopLeft
+        source: "mipmap_small.png"
+        mipmap: true
+        smooth: false
+        scale: 1 / width;
+    }
+
+    Image {
+        x: 1
+        y: 0
+        transformOrigin: Item.TopLeft
+        source: "mipmap_large.png"
+        mipmap: true
+        smooth: false
+        scale: 1 / width;
+    }
+
+    onEnterFinalStage: finalStageComplete = true;
+}
index 780d5a9..af5acde 100644 (file)
@@ -326,6 +326,7 @@ void tst_SceneGraph::render_data()
           << "data/render_BreakOpacityBatch.qml"
           << "data/render_OutOfFloatRange.qml"
           << "data/render_StackingOrder.qml"
+          << "data/render_Mipmap.qml"
         ;
 
     QRegExp sampleCount("#samples: *(\\d+)");