From 15999f14f146b5c04fb40b31b69ceeeece273430 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 27 Jan 2014 10:08:14 +0100 Subject: Add Image::mipmap to support mipmapping of images. [ChangeLog][QtQuick] New feature: Image.mipmap Task-number: QTBUG-19961 Change-Id: I13acb2408d5b126790adaf9d324ad4beda1e3646 Reviewed-by: Michael Brasser --- .../doc/src/concepts/visualcanvas/scenegraph.qdoc | 3 + .../items/context2d/qquickcontext2dtexture.cpp | 2 - src/quick/items/qquickimage.cpp | 45 +++++++++++- src/quick/items/qquickimage_p.h | 5 ++ src/quick/items/qquickimage_p_p.h | 1 + src/quick/items/qquickitemsmodule.cpp | 1 + src/quick/items/qquickwindow.cpp | 1 - src/quick/scenegraph/util/qsgatlastexture.cpp | 1 + src/quick/scenegraph/util/qsgpainternode.cpp | 1 - src/quick/scenegraph/util/qsgtexture.cpp | 15 +--- src/quick/scenegraph/util/qsgtexture_p.h | 4 +- tests/auto/quick/scenegraph/data/mipmap_large.png | Bin 0 -> 4465 bytes tests/auto/quick/scenegraph/data/mipmap_small.png | Bin 0 -> 170 bytes tests/auto/quick/scenegraph/data/render_Mipmap.qml | 77 +++++++++++++++++++++ tests/auto/quick/scenegraph/tst_scenegraph.cpp | 1 + 15 files changed, 135 insertions(+), 22 deletions(-) create mode 100644 tests/auto/quick/scenegraph/data/mipmap_large.png create mode 100644 tests/auto/quick/scenegraph/data/mipmap_small.png create mode 100644 tests/auto/quick/scenegraph/data/render_Mipmap.qml diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc index 16075f0db3..278733de8d 100644 --- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc @@ -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 diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp index 8dd48b4988..d3f2a956a3 100644 --- a/src/quick/items/context2d/qquickcontext2dtexture.cpp +++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp @@ -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; } diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp index 62ac72d244..b6b8a2a39b 100644 --- a/src/quick/items/qquickimage.cpp +++ b/src/quick/items/qquickimage.cpp @@ -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(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 diff --git a/src/quick/items/qquickimage_p.h b/src/quick/items/qquickimage_p.h index e62c355dd4..902e613b04 100644 --- a/src/quick/items/qquickimage_p.h +++ b/src/quick/items/qquickimage_p.h @@ -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); diff --git a/src/quick/items/qquickimage_p_p.h b/src/quick/items/qquickimage_p_p.h index 632f76c51f..de88662ab8 100644 --- a/src/quick/items/qquickimage_p_p.h +++ b/src/quick/items/qquickimage_p_p.h @@ -73,6 +73,7 @@ public: void setImage(const QImage &img); bool pixmapChanged : 1; + bool mipmap : 1; QQuickImage::HAlignment hAlign; QQuickImage::VAlignment vAlign; diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index a52ccf4832..c9c8eeace3 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -272,6 +272,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType(uri, 2, 3, "Text"); qmlRegisterType(uri, 2, 3, "TextEdit"); + qmlRegisterType(uri, 2, 3,"Image"); } static void initResources() diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 6778cf13e9..3828c89dbf 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -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; diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index e6a2096c80..e39949253f 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -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; } diff --git a/src/quick/scenegraph/util/qsgpainternode.cpp b/src/quick/scenegraph/util/qsgpainternode.cpp index 797fc4d145..ec44a994e0 100644 --- a/src/quick/scenegraph/util/qsgpainternode.cpp +++ b/src/quick/scenegraph/util/qsgpainternode.cpp @@ -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); diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index b738896a6c..9620e48588 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -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; } diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h index e0d386e20c..bc81569f84 100644 --- a/src/quick/scenegraph/util/qsgtexture_p.h +++ b/src/quick/scenegraph/util/qsgtexture_p.h @@ -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 index 0000000000..9cb0fc7de1 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 index 0000000000..dc5216fb6c 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 index 0000000000..0a6195fc1f --- /dev/null +++ b/tests/auto/quick/scenegraph/data/render_Mipmap.qml @@ -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; +} diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp index 780d5a97db..af5acde5f3 100644 --- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp +++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp @@ -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+)"); -- cgit v1.2.3