Downscale textures which exceed the GL texture limit
This way they will at least render. [ChangeLog][QtQuick] Images exceeding GL_MAX_TEXTURE_SIZE will be downscaled to fit so they will still show. Change-Id: I169ecac768036812b8e14265ec1a0a8902655666 Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
This commit is contained in:
parent
15ee12508e
commit
8d0e307bc7
|
@ -253,6 +253,7 @@ void QSGContext::renderContextInitialized(QSGRenderContext *renderContext)
|
|||
QSet<QByteArray> exts = renderContext->openglContext()->extensions();
|
||||
QByteArray all; foreach (const QByteArray &e, exts) all += ' ' + e;
|
||||
qCDebug(QSG_LOG_INFO) << "GL_EXTENSIONS: " << all.constData();
|
||||
qCDebug(QSG_LOG_INFO) << "Max Texture Size: " << renderContext->maxTextureSize();
|
||||
}
|
||||
|
||||
d->mutex.unlock();
|
||||
|
@ -392,6 +393,7 @@ QSGRenderContext::QSGRenderContext(QSGContext *context)
|
|||
, m_atlasManager(0)
|
||||
, m_depthStencilManager(0)
|
||||
, m_distanceFieldCacheManager(0)
|
||||
, m_maxTextureSize(0)
|
||||
, m_brokenIBOs(false)
|
||||
, m_serializedRender(false)
|
||||
, m_attachToGLContext(true)
|
||||
|
@ -493,6 +495,9 @@ void QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine)
|
|||
*/
|
||||
void QSGRenderContext::initialize(QOpenGLContext *context)
|
||||
{
|
||||
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
|
||||
funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
|
||||
|
||||
// Sanity check the surface format, in case it was overridden by the application
|
||||
QSurfaceFormat requested = m_sg->defaultSurfaceFormat();
|
||||
QSurfaceFormat actual = context->format();
|
||||
|
@ -513,7 +518,6 @@ void QSGRenderContext::initialize(QOpenGLContext *context)
|
|||
m_sg->renderContextInitialized(this);
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
|
||||
const char *vendor = (const char *) funcs->glGetString(GL_VENDOR);
|
||||
if (strstr(vendor, "nouveau"))
|
||||
m_brokenIBOs = true;
|
||||
|
|
|
@ -126,6 +126,7 @@ public:
|
|||
static QSGRenderContext *from(QOpenGLContext *context);
|
||||
|
||||
bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; }
|
||||
int maxTextureSize() const { return m_maxTextureSize; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void initialized();
|
||||
|
@ -147,7 +148,7 @@ protected:
|
|||
QSGDistanceFieldGlyphCacheManager *m_distanceFieldCacheManager;
|
||||
|
||||
QSet<QFontEngine *> m_fontEnginesToClean;
|
||||
|
||||
int m_maxTextureSize;
|
||||
bool m_brokenIBOs;
|
||||
bool m_serializedRender;
|
||||
bool m_attachToGLContext;
|
||||
|
|
|
@ -671,12 +671,28 @@ void QSGPlainTexture::bind()
|
|||
bindTime = qsg_renderer_timer.nsecsElapsed();
|
||||
|
||||
// ### TODO: check for out-of-memory situations...
|
||||
int w = m_image.width();
|
||||
int h = m_image.height();
|
||||
|
||||
QImage tmp = (m_image.format() == QImage::Format_RGB32 || m_image.format() == QImage::Format_ARGB32_Premultiplied)
|
||||
? m_image
|
||||
: m_image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
|
||||
// Downscale the texture to fit inside the max texture limit if it is too big.
|
||||
// It would be better if the image was already downscaled to the right size,
|
||||
// but this information is not always available at that time, so as a last
|
||||
// resort we can do it here. Texture coordinates are normalized, so it
|
||||
// won't cause any problems and actual texture sizes will be written
|
||||
// based on QSGTexture::textureSize which is updated after this, so that
|
||||
// should be ok.
|
||||
int max;
|
||||
if (QSGRenderContext *rc = QSGRenderContext::from(context))
|
||||
max = rc->maxTextureSize();
|
||||
else
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
|
||||
if (tmp.width() > max || tmp.height() > max) {
|
||||
tmp = tmp.scaled(qMin(max, tmp.width()), qMin(max, tmp.height()), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
m_texture_size = tmp.size();
|
||||
}
|
||||
|
||||
if (tmp.width() * 4 != tmp.bytesPerLine())
|
||||
tmp = tmp.copy();
|
||||
|
||||
|
@ -726,7 +742,7 @@ void QSGPlainTexture::bind()
|
|||
if (profileFrames)
|
||||
swizzleTime = qsg_renderer_timer.nsecsElapsed();
|
||||
|
||||
funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, externalFormat, GL_UNSIGNED_BYTE, tmp.constBits());
|
||||
funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_texture_size.width(), m_texture_size.height(), 0, externalFormat, GL_UNSIGNED_BYTE, tmp.constBits());
|
||||
|
||||
qint64 uploadTime = 0;
|
||||
if (profileFrames)
|
||||
|
@ -741,7 +757,7 @@ void QSGPlainTexture::bind()
|
|||
if (profileFrames) {
|
||||
mipmapTime = qsg_renderer_timer.nsecsElapsed();
|
||||
qCDebug(QSG_LOG_TIME_TEXTURE,
|
||||
"plain texture uploaded in: %dms (%dx%d), bind=%d, convert=%d, swizzle=%d (%s->%s), upload=%d, mipmap=%d",
|
||||
"plain texture uploaded in: %dms (%dx%d), bind=%d, convert=%d, swizzle=%d (%s->%s), upload=%d, mipmap=%d%s",
|
||||
int(mipmapTime / 1000000),
|
||||
m_texture_size.width(), m_texture_size.height(),
|
||||
int(bindTime / 1000000),
|
||||
|
@ -750,7 +766,8 @@ void QSGPlainTexture::bind()
|
|||
(externalFormat == GL_BGRA ? "BGRA" : "RGBA"),
|
||||
(internalFormat == GL_BGRA ? "BGRA" : "RGBA"),
|
||||
int((uploadTime - swizzleTime)/1000000),
|
||||
int((mipmapTime - uploadTime)/1000000));
|
||||
int((mipmapTime - uploadTime)/1000000),
|
||||
m_texture_size != m_image.size() ? " (scaled to GL_MAX_TEXTURE_SIZE)" : "");
|
||||
}
|
||||
|
||||
Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphTexturePrepare, (
|
||||
|
@ -760,7 +777,6 @@ void QSGPlainTexture::bind()
|
|||
uploadTime - swizzleTime,
|
||||
qsg_renderer_timer.nsecsElapsed() - uploadTime));
|
||||
|
||||
m_texture_size = QSize(w, h);
|
||||
m_texture_rect = QRectF(0, 0, 1, 1);
|
||||
|
||||
m_dirty_bind_options = false;
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
|
||||
** 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.0
|
||||
|
||||
Item {
|
||||
width: 200
|
||||
height: 200
|
||||
|
||||
Image {
|
||||
source: "toowide.png"
|
||||
width: 100
|
||||
height: 100
|
||||
}
|
||||
|
||||
Image {
|
||||
x: 100
|
||||
source: "tootall.png"
|
||||
width: 100
|
||||
height: 100
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 238 B |
Binary file not shown.
After Width: | Height: | Size: 217 B |
|
@ -56,6 +56,7 @@
|
|||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QImageReader>
|
||||
#include <QQuickWindow>
|
||||
#include <QQuickView>
|
||||
#include <QQuickImageProvider>
|
||||
|
||||
#include "../../shared/util.h"
|
||||
|
@ -106,6 +107,7 @@ private slots:
|
|||
void sourceSizeChanges();
|
||||
void correctStatus();
|
||||
void highdpi();
|
||||
void hugeImages();
|
||||
|
||||
private:
|
||||
QQmlEngine engine;
|
||||
|
@ -969,6 +971,21 @@ void tst_qquickimage::highdpi()
|
|||
delete obj;
|
||||
}
|
||||
|
||||
void tst_qquickimage::hugeImages()
|
||||
{
|
||||
QQuickView view;
|
||||
view.setSource(testFileUrl("hugeImages.qml"));
|
||||
view.setGeometry(0, 0, 200, 200);
|
||||
view.create();
|
||||
|
||||
QImage contents = view.grabWindow();
|
||||
|
||||
QCOMPARE(contents.pixel(0, 0), qRgba(255, 0, 0, 255));
|
||||
QCOMPARE(contents.pixel(99, 99), qRgba(255, 0, 0, 255));
|
||||
QCOMPARE(contents.pixel(100, 0), qRgba(0, 0, 255, 255));
|
||||
QCOMPARE(contents.pixel(199, 99), qRgba(0, 0, 255, 255));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qquickimage)
|
||||
|
||||
#include "tst_qquickimage.moc"
|
||||
|
|
Loading…
Reference in New Issue