summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/util/qktxhandler.cpp52
-rw-r--r--tests/auto/gui/util/qtexturefilereader/CMakeLists.txt1
-rw-r--r--tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc1
-rw-r--r--tests/auto/gui/util/qtexturefilereader/texturefiles/cubemap_float32_rgba.ktxbin0 -> 32848 bytes
-rw-r--r--tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp20
5 files changed, 58 insertions, 16 deletions
diff --git a/src/gui/util/qktxhandler.cpp b/src/gui/util/qktxhandler.cpp
index 31c572db54..27fb69a348 100644
--- a/src/gui/util/qktxhandler.cpp
+++ b/src/gui/util/qktxhandler.cpp
@@ -104,6 +104,13 @@ struct KTXMipmapLevel {
*/
};
+// Returns the nearest multiple of 'rounding' greater than or equal to 'value'
+constexpr quint32 withPadding(quint32 value, quint32 rounding)
+{
+ Q_ASSERT(rounding > 1);
+ return value + (rounding - 1) - ((value + (rounding - 1)) % rounding);
+}
+
bool QKtxHandler::canRead(const QByteArray &suffix, const QByteArray &block)
{
Q_UNUSED(suffix);
@@ -138,17 +145,25 @@ QTextureFileData QKtxHandler::read()
texData.setGLBaseInternalFormat(decode(header->glBaseInternalFormat));
texData.setNumLevels(decode(header->numberOfMipmapLevels));
- texData.setNumFaces(1);
+ texData.setNumFaces(decode(header->numberOfFaces));
quint32 offset = headerSize + decode(header->bytesOfKeyValueData);
- const int maxLevels = qMin(texData.numLevels(), 32); // Cap iterations in case of corrupt file.
- for (int i = 0; i < maxLevels; i++) {
- if (offset + sizeof(KTXMipmapLevel) > dataSize) // Corrupt file; avoid oob read
+
+ constexpr int MAX_ITERATIONS = 32; // cap iterations in case of corrupt data
+
+ for (int level = 0; level < qMin(texData.numLevels(), MAX_ITERATIONS); level++) {
+ if (offset + sizeof(quint32) > dataSize) // Corrupt file; avoid oob read
break;
- const KTXMipmapLevel *level = reinterpret_cast<const KTXMipmapLevel *>(buf.constData() + offset);
- quint32 levelLen = decode(level->imageSize);
- texData.setDataOffset(offset + sizeof(KTXMipmapLevel::imageSize), i);
- texData.setDataLength(levelLen, i);
- offset += sizeof(KTXMipmapLevel::imageSize) + levelLen + (3 - ((levelLen + 3) % 4));
+
+ const quint32 imageSize = decode(qFromUnaligned<quint32>(buf.constData() + offset));
+ offset += sizeof(quint32);
+
+ for (int face = 0; face < qMin(texData.numFaces(), MAX_ITERATIONS); face++) {
+ texData.setDataOffset(offset, level, face);
+ texData.setDataLength(imageSize, level, face);
+
+ // Add image data and padding to offset
+ offset += withPadding(imageSize, 4);
+ }
}
if (!texData.isValid()) {
@@ -176,9 +191,12 @@ bool QKtxHandler::checkHeader(const KTXHeader &header)
qDebug("Header of %s:", logName().constData());
qDebug(" glType: 0x%x (%s)", decode(header.glType), ptme.valueToKey(decode(header.glType)));
qDebug(" glTypeSize: %u", decode(header.glTypeSize));
- qDebug(" glFormat: 0x%x (%s)", decode(header.glFormat), tfme.valueToKey(decode(header.glFormat)));
- qDebug(" glInternalFormat: 0x%x (%s)", decode(header.glInternalFormat), tfme.valueToKey(decode(header.glInternalFormat)));
- qDebug(" glBaseInternalFormat: 0x%x (%s)", decode(header.glBaseInternalFormat), tfme.valueToKey(decode(header.glBaseInternalFormat)));
+ qDebug(" glFormat: 0x%x (%s)", decode(header.glFormat),
+ tfme.valueToKey(decode(header.glFormat)));
+ qDebug(" glInternalFormat: 0x%x (%s)", decode(header.glInternalFormat),
+ tfme.valueToKey(decode(header.glInternalFormat)));
+ qDebug(" glBaseInternalFormat: 0x%x (%s)", decode(header.glBaseInternalFormat),
+ tfme.valueToKey(decode(header.glBaseInternalFormat)));
qDebug(" pixelWidth: %u", decode(header.pixelWidth));
qDebug(" pixelHeight: %u", decode(header.pixelHeight));
qDebug(" pixelDepth: %u", decode(header.pixelDepth));
@@ -187,10 +205,12 @@ bool QKtxHandler::checkHeader(const KTXHeader &header)
qDebug(" numberOfMipmapLevels: %u", decode(header.numberOfMipmapLevels));
qDebug(" bytesOfKeyValueData: %u", decode(header.bytesOfKeyValueData));
#endif
- return ((decode(header.glType) == 0) &&
- (decode(header.glFormat) == 0) &&
- (decode(header.pixelDepth) == 0) &&
- (decode(header.numberOfFaces) == 1));
+ const bool isCompressedImage = decode(header.glType) == 0 && decode(header.glFormat) == 0
+ && decode(header.pixelDepth) == 0;
+ const bool isCubeMap = decode(header.numberOfFaces) == 6;
+ const bool is2D = decode(header.pixelDepth) == 0 && decode(header.numberOfArrayElements) == 0;
+
+ return is2D && (isCubeMap || isCompressedImage);
}
quint32 QKtxHandler::decode(quint32 val)
diff --git a/tests/auto/gui/util/qtexturefilereader/CMakeLists.txt b/tests/auto/gui/util/qtexturefilereader/CMakeLists.txt
index 91083348f7..e1731a45d5 100644
--- a/tests/auto/gui/util/qtexturefilereader/CMakeLists.txt
+++ b/tests/auto/gui/util/qtexturefilereader/CMakeLists.txt
@@ -16,6 +16,7 @@ qt_internal_add_test(tst_qtexturefilereader
set(qtexturefilereader_resource_files
"texturefiles/car.ktx"
"texturefiles/car_mips.ktx"
+ "texturefiles/cubemap_float32_rgba.ktx"
"texturefiles/newlogo.astc"
"texturefiles/newlogo_srgb.astc"
"texturefiles/pattern.pkm"
diff --git a/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc b/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc
index 8aab86e1ff..a014c0367a 100644
--- a/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc
+++ b/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc
@@ -1,6 +1,7 @@
<RCC>
<qresource prefix="/">
<file>texturefiles/car.ktx</file>
+ <file>texturefiles/cubemap_float32_rgba.ktx</file>
<file>texturefiles/pattern.pkm</file>
<file>texturefiles/car_mips.ktx</file>
<file>texturefiles/newlogo_srgb.astc</file>
diff --git a/tests/auto/gui/util/qtexturefilereader/texturefiles/cubemap_float32_rgba.ktx b/tests/auto/gui/util/qtexturefilereader/texturefiles/cubemap_float32_rgba.ktx
new file mode 100644
index 0000000000..25b48b1370
--- /dev/null
+++ b/tests/auto/gui/util/qtexturefilereader/texturefiles/cubemap_float32_rgba.ktx
Binary files differ
diff --git a/tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp b/tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp
index 6ff3497a74..cd90914bd9 100644
--- a/tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp
+++ b/tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp
@@ -46,6 +46,7 @@ void tst_qtexturefilereader::checkHandlers_data()
QTest::addColumn<quint32>("glInternalFormat");
QTest::addColumn<quint32>("glBaseInternalFormat");
QTest::addColumn<int>("levels");
+ QTest::addColumn<int>("faces");
QTest::addColumn<QList<int>>("dataOffsets");
QTest::addColumn<QList<int>>("dataLengths");
@@ -56,6 +57,7 @@ void tst_qtexturefilereader::checkHandlers_data()
<< quint32(0x8d64)
<< quint32(0x0)
<< 1
+ << 1
<< (QList<int>() << 16)
<< (QList<int>() << 2048);
@@ -66,6 +68,7 @@ void tst_qtexturefilereader::checkHandlers_data()
<< quint32(0x9278)
<< quint32(0x1908)
<< 1
+ << 1
<< (QList<int>() << 68)
<< (QList<int>() << 11840);
@@ -76,9 +79,21 @@ void tst_qtexturefilereader::checkHandlers_data()
<< quint32(0x9274)
<< quint32(0x1907)
<< 8
+ << 1
<< (QList<int>() << 68 << 5992 << 7516 << 7880 << 8004 << 8056 << 8068 << 8080)
<< (QList<int>() << 5920 << 1520 << 360 << 120 << 48 << 8 << 8 << 8);
+ QTest::addRow("cubemap_float32_rgba.ktx")
+ << QStringLiteral(":/texturefiles/cubemap_float32_rgba.ktx")
+ << QSize(16, 16)
+ << quint32(0x1908)
+ << quint32(0x8814)
+ << quint32(0x1908)
+ << 5
+ << 6
+ << (QList<int>() << 96 << 24676 << 30824 << 32364 << 32752)
+ << (QList<int>() << 4096 << 1024 << 256 << 64 << 16);
+
QTest::addRow("newlogo.astc")
<< QStringLiteral(":/texturefiles/newlogo.astc")
<< QSize(111, 78)
@@ -86,6 +101,7 @@ void tst_qtexturefilereader::checkHandlers_data()
<< quint32(0x93b9)
<< quint32(0x0)
<< 1
+ << 1
<< (QList<int>() << 16)
<< (QList<int>() << 2496);
@@ -96,6 +112,7 @@ void tst_qtexturefilereader::checkHandlers_data()
<< quint32(0x93d9)
<< quint32(0x0)
<< 1
+ << 1
<< (QList<int>() << 16)
<< (QList<int>() << 2496);
}
@@ -107,6 +124,7 @@ void tst_qtexturefilereader::checkHandlers()
QFETCH(quint32, glFormat);
QFETCH(quint32, glInternalFormat);
QFETCH(int, levels);
+ QFETCH(int, faces);
QFETCH(QList<int>, dataOffsets);
QFETCH(QList<int>, dataLengths);
@@ -122,6 +140,8 @@ void tst_qtexturefilereader::checkHandlers()
QCOMPARE(tex.glFormat(), glFormat);
QCOMPARE(tex.glInternalFormat(), glInternalFormat);
QCOMPARE(tex.numLevels(), levels);
+ QCOMPARE(tex.numFaces(), faces);
+
for (int i = 0; i < tex.numLevels(); i++) {
QCOMPARE(tex.dataOffset(i), dataOffsets.at(i));
QCOMPARE(tex.dataLength(i), dataLengths.at(i));