aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEirik Aavitsland <eirik.aavitsland@qt.io>2017-11-27 19:03:16 +0100
committerMichael Brasser <michael.brasser@live.com>2018-01-27 02:42:16 +0000
commitae7c66b8f50103c212789805efccba208a55ea4b (patch)
tree8640661ae688829d03d1f3d77bda3a1fc0888865
parent0f8e0310b7ad874a1fbdb3def4cf8d7da7f943e5 (diff)
Refactor compressed texture file reading
This commit expands on the basic support for compressed texture files that was added in 432e27a. It prepares for adding support for other file types than pkm by declaring a common QSGTextureFileHandler interface, and by factoring out reusable code parts in a new QSGCompressedTexture class. It also adds some more systematic logging and checking for error conditions. Change-Id: Ie5070d0a6df757fee0753f53adbe23a33d51a634 Reviewed-by: Michael Brasser <michael.brasser@live.com>
-rw-r--r--src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp239
-rw-r--r--src/quick/scenegraph/compressedtexture/qsgcompressedtexture_p.h121
-rw-r--r--src/quick/scenegraph/compressedtexture/qsgpkmhandler.cpp170
-rw-r--r--src/quick/scenegraph/compressedtexture/qsgpkmhandler_p.h34
-rw-r--r--src/quick/scenegraph/compressedtexture/qsgtexturefilehandler_p.h82
-rw-r--r--src/quick/scenegraph/scenegraph.pri3
-rw-r--r--src/quick/scenegraph/util/qsgtexturereader.cpp49
-rw-r--r--src/quick/scenegraph/util/qsgtexturereader_p.h18
-rw-r--r--src/quick/util/qquickpixmapcache.cpp17
9 files changed, 545 insertions, 188 deletions
diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
new file mode 100644
index 0000000000..6d51ed9d61
--- /dev/null
+++ b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
@@ -0,0 +1,239 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qsgcompressedtexture_p.h"
+#include <QOpenGLContext>
+#include <QOpenGLTexture>
+#include <QOpenGLFunctions>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(QSG_LOG_TEXTUREIO, "qt.scenegraph.textureio");
+
+bool QSGCompressedTextureData::isValid() const
+{
+ if (data.isNull() || size.isEmpty() || !format)
+ return false;
+ if (dataLength < 0 || dataOffset < 0 || dataOffset >= data.length())
+ return false;
+ if (dataLength > 0 && qint64(dataOffset) + qint64(dataLength) > qint64(data.length()))
+ return false;
+
+ return true;
+}
+
+int QSGCompressedTextureData::sizeInBytes() const
+{
+ if (!isValid())
+ return 0;
+ return dataLength > 0 ? dataLength : data.length() - dataOffset;
+}
+
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QSGCompressedTextureData *d)
+{
+ QDebugStateSaver saver(dbg);
+
+ dbg.nospace() << "QSGCompressedTextureData(";
+ if (d) {
+ dbg << d->logName << ' ';
+ dbg << static_cast<QOpenGLTexture::TextureFormat>(d->format)
+ << "[0x" << hex << d->format << dec << "]";
+ dbg.space() << (d->hasAlpha ? "with" : "no") << "alpha" << d->size
+ << "databuffer" << d->data.size() << "offset" << d->dataOffset << "length";
+ dbg.nospace() << d->dataLength << ")";
+ } else {
+ dbg << "null)";
+ }
+ return dbg;
+}
+
+QSGCompressedTexture::QSGCompressedTexture(const DataPtr& texData)
+ : m_textureData(texData)
+{
+ if (m_textureData) {
+ m_size = m_textureData->size;
+ m_hasAlpha = m_textureData->hasAlpha;
+ }
+}
+
+QSGCompressedTexture::~QSGCompressedTexture()
+{
+#if QT_CONFIG(opengl)
+ if (m_textureId) {
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QOpenGLFunctions *funcs = ctx ? ctx->functions() : nullptr;
+ if (!funcs)
+ return;
+
+ funcs->glDeleteTextures(1, &m_textureId);
+ }
+#endif
+}
+
+int QSGCompressedTexture::textureId() const
+{
+#if QT_CONFIG(opengl)
+ if (!m_textureId) {
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QOpenGLFunctions *funcs = ctx ? ctx->functions() : nullptr;
+ if (!funcs)
+ return 0;
+
+ funcs->glGenTextures(1, &m_textureId);
+ }
+#endif
+ return m_textureId;
+}
+
+QSize QSGCompressedTexture::textureSize() const
+{
+ return m_size;
+}
+
+bool QSGCompressedTexture::hasAlphaChannel() const
+{
+ return m_hasAlpha;
+}
+
+bool QSGCompressedTexture::hasMipmaps() const
+{
+ return false;
+}
+
+void QSGCompressedTexture::bind()
+{
+#if QT_CONFIG(opengl)
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QOpenGLFunctions *funcs = ctx ? ctx->functions() : nullptr;
+ if (!funcs)
+ return;
+
+ if (!textureId())
+ return;
+
+ funcs->glBindTexture(GL_TEXTURE_2D, m_textureId);
+
+ if (m_uploaded)
+ return;
+
+ QByteArray logName(m_textureData ? m_textureData->logName : QByteArrayLiteral("(unset)"));
+
+ if (!m_textureData || !m_textureData->isValid()) {
+ qCDebug(QSG_LOG_TEXTUREIO, "Invalid texture data for %s", logName.constData());
+ funcs->glBindTexture(GL_TEXTURE_2D, 0);
+ return;
+ }
+
+ if (Q_UNLIKELY(QSG_LOG_TEXTUREIO().isDebugEnabled())) {
+ qCDebug(QSG_LOG_TEXTUREIO) << "Uploading texture" << m_textureData.data();
+ while (funcs->glGetError() != GL_NO_ERROR);
+ }
+
+ funcs->glCompressedTexImage2D(GL_TEXTURE_2D, 0, m_textureData->format,
+ m_size.width(), m_size.height(), 0, m_textureData->sizeInBytes(),
+ m_textureData->data.constData() + m_textureData->dataOffset);
+
+ if (Q_UNLIKELY(QSG_LOG_TEXTUREIO().isDebugEnabled())) {
+ GLuint error = funcs->glGetError();
+ if (error != GL_NO_ERROR) {
+ qCDebug(QSG_LOG_TEXTUREIO, "glCompressedTexImage2D failed for %s, error 0x%x", logName.constData(), error);
+ }
+ }
+
+ m_textureData.clear(); // Release this memory, not needed anymore
+
+ updateBindOptions(true);
+ m_uploaded = true;
+#endif // QT_CONFIG(opengl)
+}
+
+bool QSGCompressedTexture::formatIsOpaque(quint32 glTextureFormat)
+{
+ switch (glTextureFormat) {
+ case QOpenGLTexture::RGB_DXT1:
+ case QOpenGLTexture::R_ATI1N_UNorm:
+ case QOpenGLTexture::R_ATI1N_SNorm:
+ case QOpenGLTexture::RG_ATI2N_UNorm:
+ case QOpenGLTexture::RG_ATI2N_SNorm:
+ case QOpenGLTexture::RGB_BP_UNSIGNED_FLOAT:
+ case QOpenGLTexture::RGB_BP_SIGNED_FLOAT:
+ case QOpenGLTexture::R11_EAC_UNorm:
+ case QOpenGLTexture::R11_EAC_SNorm:
+ case QOpenGLTexture::RG11_EAC_UNorm:
+ case QOpenGLTexture::RG11_EAC_SNorm:
+ case QOpenGLTexture::RGB8_ETC2:
+ case QOpenGLTexture::SRGB8_ETC2:
+ case QOpenGLTexture::RGB8_ETC1:
+ case QOpenGLTexture::SRGB_DXT1:
+ return true;
+ break;
+ default:
+ return false;
+ }
+}
+
+QSGCompressedTextureFactory::QSGCompressedTextureFactory(const QSGCompressedTexture::DataPtr &texData)
+ : m_textureData(texData)
+{
+}
+
+QSGTexture *QSGCompressedTextureFactory::createTexture(QQuickWindow *) const
+{
+ if (!m_textureData || !m_textureData->isValid())
+ return nullptr;
+
+ return new QSGCompressedTexture(m_textureData);
+}
+
+int QSGCompressedTextureFactory::textureByteCount() const
+{
+ return m_textureData ? m_textureData->sizeInBytes() : 0;
+}
+
+
+QSize QSGCompressedTextureFactory::textureSize() const
+{
+ if (m_textureData && m_textureData->isValid())
+ return m_textureData->size;
+ return QSize();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture_p.h b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture_p.h
new file mode 100644
index 0000000000..dfedac5558
--- /dev/null
+++ b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture_p.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCOMPRESSEDTEXTURE_P_H
+#define QSGCOMPRESSEDTEXTURE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QSGTexture>
+#include <QtQuick/private/qsgcontext_p.h>
+#include <QQuickTextureFactory>
+#include <QOpenGLFunctions>
+
+QT_BEGIN_NAMESPACE
+
+struct Q_QUICK_PRIVATE_EXPORT QSGCompressedTextureData
+{
+ QByteArray logName;
+ QByteArray data;
+ QSize size;
+ uint format = 0;
+ int dataOffset = 0;
+ int dataLength = 0;
+ bool hasAlpha = false;
+
+ bool isValid() const;
+ int sizeInBytes() const;
+};
+
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug, const QSGCompressedTextureData *);
+
+
+class Q_QUICK_PRIVATE_EXPORT QSGCompressedTexture : public QSGTexture
+{
+ Q_OBJECT
+public:
+ typedef QSharedPointer<QSGCompressedTextureData> DataPtr;
+
+ QSGCompressedTexture(const DataPtr& texData);
+ virtual ~QSGCompressedTexture();
+
+ int textureId() const override;
+ QSize textureSize() const override;
+ bool hasAlphaChannel() const override;
+ bool hasMipmaps() const override;
+
+ void bind() override;
+
+ const QSGCompressedTextureData *textureData();
+
+ static bool formatIsOpaque(quint32 glTextureFormat);
+
+protected:
+ DataPtr m_textureData;
+ QSize m_size;
+ mutable uint m_textureId = 0;
+ bool m_hasAlpha = false;
+ bool m_uploaded = false;
+};
+
+
+class Q_QUICK_PRIVATE_EXPORT QSGCompressedTextureFactory : public QQuickTextureFactory
+{
+public:
+ QSGCompressedTextureFactory(const QSGCompressedTexture::DataPtr& texData);
+ QSGTexture *createTexture(QQuickWindow *) const override;
+ int textureByteCount() const override;
+ QSize textureSize() const override;
+
+protected:
+ QSGCompressedTexture::DataPtr m_textureData;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGCOMPRESSEDTEXTURE_P_H
diff --git a/src/quick/scenegraph/compressedtexture/qsgpkmhandler.cpp b/src/quick/scenegraph/compressedtexture/qsgpkmhandler.cpp
index bb8fce046d..daec23d478 100644
--- a/src/quick/scenegraph/compressedtexture/qsgpkmhandler.cpp
+++ b/src/quick/scenegraph/compressedtexture/qsgpkmhandler.cpp
@@ -38,172 +38,82 @@
****************************************************************************/
#include "qsgpkmhandler_p.h"
+#include "qsgcompressedtexture_p.h"
#include <QFile>
#include <QDebug>
#include <qendian.h>
#include <qopenglfunctions.h>
#include <qqmlfile.h>
+#include <QOpenGLTexture>
//#define ETC_DEBUG
-#ifndef GL_ETC1_RGB8_OES
- #define GL_ETC1_RGB8_OES 0x8d64
-#endif
-
-#ifndef GL_COMPRESSED_RGB8_ETC2
- #define GL_COMPRESSED_RGB8_ETC2 0x9274
-#endif
-
-#ifndef GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
- #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
-#endif
-
-#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC
- #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
-#endif
-
QT_BEGIN_NAMESPACE
static const int headerSize = 16;
static unsigned int typeMap[5] = {
- GL_ETC1_RGB8_OES,
- GL_COMPRESSED_RGB8_ETC2,
- 0, // unused
- GL_COMPRESSED_RGBA8_ETC2_EAC,
- GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
+ QOpenGLTexture::RGB8_ETC1, // GL_ETC1_RGB8_OES,
+ QOpenGLTexture::RGB8_ETC2, // GL_COMPRESSED_RGB8_ETC2,
+ 0, // unused (obsolete)
+ QOpenGLTexture::RGBA8_ETC2_EAC, // GL_COMPRESSED_RGBA8_ETC2_EAC,
+ QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2 // GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
};
-QEtcTexture::QEtcTexture()
- : m_texture_id(0), m_uploaded(false)
-{
- initializeOpenGLFunctions();
-}
-
-QEtcTexture::~QEtcTexture()
-{
- if (m_texture_id)
- glDeleteTextures(1, &m_texture_id);
-}
-
-int QEtcTexture::textureId() const
-{
- if (m_texture_id == 0) {
- QEtcTexture *texture = const_cast<QEtcTexture*>(this);
- texture->glGenTextures(1, &texture->m_texture_id);
- }
- return m_texture_id;
-}
-
-bool QEtcTexture::hasAlphaChannel() const
-{
- return m_type == GL_COMPRESSED_RGBA8_ETC2_EAC ||
- m_type == GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
-}
-
-
-void QEtcTexture::bind()
+bool QSGPkmHandler::canRead(const QByteArray &suffix, const QByteArray &block)
{
- if (m_uploaded && m_texture_id) {
- glBindTexture(GL_TEXTURE_2D, m_texture_id);
- return;
- }
-
- if (m_texture_id == 0)
- glGenTextures(1, &m_texture_id);
- glBindTexture(GL_TEXTURE_2D, m_texture_id);
-
-#ifdef ETC_DEBUG
- qDebug() << "glCompressedTexImage2D, width: " << m_size.width() << "height" << m_size.height() <<
- "paddedWidth: " << m_paddedSize.width() << "paddedHeight: " << m_paddedSize.height();
-#endif
+ Q_UNUSED(suffix)
-#ifndef QT_NO_DEBUG
- while (glGetError() != GL_NO_ERROR) { }
-#endif
-
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- Q_ASSERT(ctx != 0);
- ctx->functions()->glCompressedTexImage2D(GL_TEXTURE_2D, 0, m_type,
- m_size.width(), m_size.height(), 0,
- (m_paddedSize.width() * m_paddedSize.height()) / 2,
- m_data.data() + headerSize);
-
-#ifndef QT_NO_DEBUG
- // Gracefully fail in case of an error...
- GLuint error = glGetError();
- if (error != GL_NO_ERROR) {
- qDebug () << "glCompressedTexImage2D for compressed texture failed, error: " << error;
- glBindTexture(GL_TEXTURE_2D, 0);
- glDeleteTextures(1, &m_texture_id);
- m_texture_id = 0;
- return;
- }
-#endif
-
- m_uploaded = true;
- updateBindOptions(true);
+ return block.startsWith("PKM ");
}
-class QEtcTextureFactory : public QQuickTextureFactory
-{
-public:
- QByteArray m_data;
- QSize m_size;
- QSize m_paddedSize;
- unsigned int m_type;
-
- QSize textureSize() const { return m_size; }
- int textureByteCount() const { return m_data.size(); }
-
- QSGTexture *createTexture(QQuickWindow *) const {
- QEtcTexture *texture = new QEtcTexture;
- texture->m_data = m_data;
- texture->m_size = m_size;
- texture->m_paddedSize = m_paddedSize;
- texture->m_type = m_type;
- return texture;
- }
-};
-
-QQuickTextureFactory *QSGPkmHandler::read(QIODevice *device)
+QQuickTextureFactory *QSGPkmHandler::read()
{
- QScopedPointer<QEtcTextureFactory> ret(new QEtcTextureFactory);
- ret->m_data = device->readAll();
- if (ret->m_data.isEmpty() || ret->m_data.size() < headerSize)
+ if (!device())
return nullptr;
- const char *rawData = ret->m_data.constData();
+ QSGCompressedTexture::DataPtr texData(QSGCompressedTexture::DataPtr::create());
- // magic number
- if (qstrncmp(rawData, "PKM ", 4) != 0)
+ texData->data = device()->readAll();
+ if (texData->data.size() < headerSize || !canRead(QByteArray(), texData->data)) {
+ qCDebug(QSG_LOG_TEXTUREIO, "Invalid PKM file %s", logName().constData());
return nullptr;
+ }
+
+ const char *rawData = texData->data.constData();
- // currently ignore version (rawData + 4)
+ // ignore version (rawData + 4 & 5)
// texture type
quint16 type = qFromBigEndian<quint16>(rawData + 6);
- static int typeCount = sizeof(typeMap)/sizeof(typeMap[0]);
- if (type >= typeCount)
+ if (type > sizeof(typeMap)/sizeof(typeMap[0])) {
+ qCDebug(QSG_LOG_TEXTUREIO, "Unknown compression format in PKM file %s", logName().constData());
return nullptr;
- ret->m_type = typeMap[type];
+ }
+ texData->format = typeMap[type];
+ texData->hasAlpha = !QSGCompressedTexture::formatIsOpaque(texData->format);
// texture size
- ret->m_paddedSize.setWidth(qFromBigEndian<quint16>(rawData + 8));
- ret->m_paddedSize.setHeight(qFromBigEndian<quint16>(rawData + 10));
- if ((ret->m_paddedSize.width() * ret->m_paddedSize.height()) / 2 > ret->m_data.size() - headerSize)
- return nullptr;
- ret->m_size.setWidth(qFromBigEndian<quint16>(rawData + 12));
- ret->m_size.setHeight(qFromBigEndian<quint16>(rawData + 14));
- if (ret->m_size.isEmpty())
+ /* Actual data length depends on format; for now just use 0, i.e. rest-of-file
+ QSize paddedSize(qFromBigEndian<quint16>(rawData + 8), qFromBigEndian<quint16>(rawData + 10));
+ texData->dataLength = (paddedSize.width() / 4) * (paddedSize.height() / 4) * 8;
+ */
+ QSize texSize(qFromBigEndian<quint16>(rawData + 12), qFromBigEndian<quint16>(rawData + 14));
+ texData->size = texSize;
+
+ texData->dataOffset = headerSize;
+
+ if (!texData->isValid()) {
+ qCDebug(QSG_LOG_TEXTUREIO, "Invalid values in header of PKM file %s", logName().constData());
return nullptr;
+ }
+ texData->logName = logName();
#ifdef ETC_DEBUG
- qDebug() << "requestTexture returning: " << ret->m_data.length() << "bytes; width: " << ret->m_size.width() << ", height: " << ret->m_size.height();
+ qDebug() << "PKM file handler read" << texData.data();
#endif
-
- return ret.take();
+ return new QSGCompressedTextureFactory(texData);
}
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/compressedtexture/qsgpkmhandler_p.h b/src/quick/scenegraph/compressedtexture/qsgpkmhandler_p.h
index eb6b2e46c0..6154c51b84 100644
--- a/src/quick/scenegraph/compressedtexture/qsgpkmhandler_p.h
+++ b/src/quick/scenegraph/compressedtexture/qsgpkmhandler_p.h
@@ -51,42 +51,18 @@
// We mean it.
//
-#include <QOpenGLFunctions>
-#include <QQuickImageProvider>
-#include <QtQuick/QSGTexture>
-#include <QUrl>
+#include "qsgtexturefilehandler_p.h"
QT_BEGIN_NAMESPACE
-class QSGPkmHandler
+class QSGPkmHandler : public QSGTextureFileHandler
{
public:
- QSGPkmHandler() {}
+ using QSGTextureFileHandler::QSGTextureFileHandler;
- QQuickTextureFactory *read(QIODevice *device);
-};
-
-class QEtcTexture : public QSGTexture, protected QOpenGLFunctions
-{
- Q_OBJECT
-public:
- QEtcTexture();
- ~QEtcTexture();
-
- void bind();
-
- QSize textureSize() const { return m_size; }
- int textureId() const;
-
- bool hasAlphaChannel() const;
- bool hasMipmaps() const { return false; }
+ static bool canRead(const QByteArray &suffix, const QByteArray &block);
- QByteArray m_data;
- QSize m_size;
- QSize m_paddedSize;
- GLuint m_texture_id;
- GLenum m_type;
- bool m_uploaded;
+ QQuickTextureFactory *read() override;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/compressedtexture/qsgtexturefilehandler_p.h b/src/quick/scenegraph/compressedtexture/qsgtexturefilehandler_p.h
new file mode 100644
index 0000000000..43358b2846
--- /dev/null
+++ b/src/quick/scenegraph/compressedtexture/qsgtexturefilehandler_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTUREFILEHANDLER_P_H
+#define QSGTEXTUREFILEHANDLER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TEXTUREIO)
+
+class QQuickTextureFactory;
+
+class QSGTextureFileHandler
+{
+public:
+ QSGTextureFileHandler(QIODevice *device, const QByteArray &logName = QByteArray())
+ : m_device(device)
+ {
+ m_logName = !logName.isEmpty() ? logName : QByteArrayLiteral("(unknown)");
+ }
+
+ virtual QQuickTextureFactory *read() = 0;
+ QIODevice *device() const { return m_device; }
+ QByteArray logName() const { return m_logName; }
+
+private:
+ QIODevice *m_device = nullptr;
+ QByteArray m_logName;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTEXTUREFILEHANDLER_P_H
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index b5c72f521c..377a4647da 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -230,8 +230,11 @@ SOURCES += \
qtConfig(opengl(es1|es2)?) {
HEADERS += \
+ $$PWD/compressedtexture/qsgcompressedtexture_p.h \
+ $$PWD/compressedtexture/qsgtexturefilehandler_p.h \
$$PWD/compressedtexture/qsgpkmhandler_p.h
SOURCES += \
+ $$PWD/compressedtexture/qsgcompressedtexture.cpp \
$$PWD/compressedtexture/qsgpkmhandler.cpp
}
diff --git a/src/quick/scenegraph/util/qsgtexturereader.cpp b/src/quick/scenegraph/util/qsgtexturereader.cpp
index 61729ada18..cf4edf29b8 100644
--- a/src/quick/scenegraph/util/qsgtexturereader.cpp
+++ b/src/quick/scenegraph/util/qsgtexturereader.cpp
@@ -45,38 +45,55 @@
#include <private/qsgpkmhandler_p.h>
#endif
+#include <QFileInfo>
+
QT_BEGIN_NAMESPACE
-QSGTextureReader::QSGTextureReader()
+QSGTextureReader::QSGTextureReader(QIODevice *device, const QString &fileName)
+ : m_device(device), m_fileInfo(fileName)
{
-
}
-QQuickTextureFactory *QSGTextureReader::read(QIODevice *device, const QByteArray &format)
+QQuickTextureFactory *QSGTextureReader::read()
{
#if QT_CONFIG(opengl)
- if (format == QByteArrayLiteral("pkm")) {
- QSGPkmHandler handler;
- return handler.read(device);
- }
+ if (!isTexture())
+ return nullptr;
+ return m_handler->read();
#else
- Q_UNUSED(device)
- Q_UNUSED(format)
-#endif
return nullptr;
+#endif
}
-bool QSGTextureReader::isTexture(QIODevice *device, const QByteArray &format)
+bool QSGTextureReader::isTexture()
{
#if QT_CONFIG(opengl)
- if (format == QByteArrayLiteral("pkm")) {
- return device->peek(4) == QByteArrayLiteral("PKM ");
+ if (!checked) {
+ checked = true;
+ if (!init())
+ return false;
+
+ QByteArray headerBlock = m_device->peek(64);
+ QByteArray suffix = m_fileInfo.suffix().toLower().toLatin1();
+ QByteArray logName = m_fileInfo.fileName().toUtf8();
+
+ // Currently the handlers are hardcoded; later maybe a list of plugins
+ if (QSGPkmHandler::canRead(suffix, headerBlock)) {
+ m_handler = new QSGPkmHandler(m_device, logName);
+ }
+ // else if OtherHandler::canRead() ...etc.
}
+ return (m_handler != nullptr);
#else
- Q_UNUSED(device)
- Q_UNUSED(format)
-#endif
return false;
+#endif
+}
+
+bool QSGTextureReader::init()
+{
+ if (!m_device)
+ return false;
+ return m_device->isReadable();
}
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgtexturereader_p.h b/src/quick/scenegraph/util/qsgtexturereader_p.h
index 7d2fc314a6..8251e4c696 100644
--- a/src/quick/scenegraph/util/qsgtexturereader_p.h
+++ b/src/quick/scenegraph/util/qsgtexturereader_p.h
@@ -52,19 +52,31 @@
//
#include <QString>
+#include <QFileInfo>
QT_BEGIN_NAMESPACE
class QIODevice;
class QQuickTextureFactory;
+class QSGTextureFileHandler;
class QSGTextureReader
{
public:
- QSGTextureReader();
+ QSGTextureReader(QIODevice *device, const QString &fileName = QString());
- static QQuickTextureFactory *read(QIODevice *device, const QByteArray &format);
- static bool isTexture(QIODevice *device, const QByteArray &format);
+ QQuickTextureFactory *read();
+ bool isTexture();
+
+ // TBD access function to params
+ // TBD ask for identified fmt
+
+private:
+ bool init();
+ QIODevice *m_device = nullptr;
+ QFileInfo m_fileInfo;
+ QSGTextureFileHandler *m_handler = nullptr;
+ bool checked = false;
};
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index e218b84fff..6712b01476 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -772,11 +772,9 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
QFile f(localFile);
QSize readSize;
if (f.open(QIODevice::ReadOnly)) {
-
- // for now, purely use suffix information to determine whether we are working with a compressed texture
- QByteArray suffix = QFileInfo(f).suffix().toLower().toLatin1();
- if (QSGTextureReader::isTexture(&f, suffix)) {
- QQuickTextureFactory *factory = QSGTextureReader::read(&f, suffix);
+ QSGTextureReader texReader(&f, localFile);
+ if (texReader.isTexture()) {
+ QQuickTextureFactory *factory = texReader.read();
if (factory) {
readSize = factory->textureSize();
} else {
@@ -1252,13 +1250,12 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
QString errorString;
if (f.open(QIODevice::ReadOnly)) {
- // for now, purely use suffix information to determine whether we are working with a compressed texture
- QByteArray suffix = QFileInfo(f).suffix().toLower().toLatin1();
- if (QSGTextureReader::isTexture(&f, suffix)) {
- QQuickTextureFactory *factory = QSGTextureReader::read(&f, suffix);
+ QSGTextureReader texReader(&f, localFile);
+ if (texReader.isTexture()) {
+ QQuickTextureFactory *factory = texReader.read();
if (factory) {
*ok = true;
- return new QQuickPixmapData(declarativePixmap, factory);
+ return new QQuickPixmapData(declarativePixmap, url, factory, factory->textureSize(), requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
} else {
errorString = QQuickPixmap::tr("Error decoding: %1").arg(url.toString());
}