diff options
-rw-r--r-- | src/gui/util/qktxhandler.cpp | 52 | ||||
-rw-r--r-- | tests/auto/gui/util/qtexturefilereader/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc | 1 | ||||
-rw-r--r-- | tests/auto/gui/util/qtexturefilereader/texturefiles/cubemap_float32_rgba.ktx | bin | 0 -> 32848 bytes | |||
-rw-r--r-- | tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp | 20 |
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 Binary files differnew file mode 100644 index 0000000000..25b48b1370 --- /dev/null +++ b/tests/auto/gui/util/qtexturefilereader/texturefiles/cubemap_float32_rgba.ktx 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)); |