diff options
author | Antti Määttä <antti.maatta@qt.io> | 2019-03-21 16:31:32 +0200 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2019-03-21 15:01:44 +0000 |
commit | 92079605819c10de4d950ed4a5254da8546b140a (patch) | |
tree | 59a82e32a3ceea5452b468eb960b992608015ddd | |
parent | 78488c1aa32d9f61656969de387b0b1d17b781db (diff) |
Fix IBL lighting mipmap calculationv2.3.0-rc2v2.3.0-rc
Change the IBL mipmap calculation to happen in the setSource instead of
load, because the load function might not have the information needed to
enable the calculation.
Task-number: QT3DS-3187
Change-Id: I7a765acc0fc8b02e59b5a2759de593aa29db76c6
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
-rw-r--r-- | src/runtime/q3dsimagemanager.cpp | 131 | ||||
-rw-r--r-- | src/runtime/q3dsimagemanager_p.h | 4 |
2 files changed, 73 insertions, 62 deletions
diff --git a/src/runtime/q3dsimagemanager.cpp b/src/runtime/q3dsimagemanager.cpp index 5168e8a..549f962 100644 --- a/src/runtime/q3dsimagemanager.cpp +++ b/src/runtime/q3dsimagemanager.cpp @@ -146,7 +146,7 @@ void ReloadableTexture::reload() m_texture = Q3DSImageManager::instance().newTextureForImage(m_parent, flags, m_id, m_profiler, m_profileInfo); } - Q3DSImageManager::instance().loadImageData(m_source, true); + Q3DSImageManager::instance().loadImageData(m_source); Q3DSImageManager::instance().setSource(m_texture, m_source); } @@ -219,8 +219,7 @@ private: Qt3DRender::QTextureImageDataGeneratorPtr m_gen; }; -QVector<Qt3DRender::QTextureImageDataPtr> Q3DSImageManager::load(const QUrl &source, - ImageFlags flags) +QVector<Qt3DRender::QTextureImageDataPtr> Q3DSImageManager::load(const QUrl &source) { const QString sourceStr = source.toLocalFile(); s_loadMutex.lock(); @@ -285,58 +284,6 @@ QVector<Qt3DRender::QTextureImageDataPtr> Q3DSImageManager::load(const QUrl &sou if (!result.isEmpty()) { qCDebug(lcPerf, "Image loaded (%d mip levels) in %lld ms", result.count(), t.elapsed()); - - if (flags.testFlag(GenerateMipMapsForIBL) && result.count() == 1) { - // IBL needs special mipmap generation. This could be done - // asynchronously but the we rely on the previous level in each step so - // it's not a good fit unfortunately. So do it all here. Also, - // QTextureGenerator could provide all mipmaps in one go in one blob, - // but there's no public API for that, have to stick with - // QTextureImageDataGenerator. - t.restart(); - Qt3DRender::QTextureImageDataPtr data = result.first(); - int w = data->width(); - int h = data->height(); - const int maxDim = w > h ? w : h; - const int maxMipLevel = int(qLn(maxDim) / qLn(2.0f)); - // silly QTextureImageData does not expose blockSize - const int blockSize = blockSizeForFormat(data->format()); - QByteArray prevLevelData = data->data(); - for (int i = 1; i <= maxMipLevel; ++i) { - int prevW = w; - int prevH = h; - w >>= 1; - h >>= 1; - w = qMax(1, w); - h = qMax(1, h); - - auto mipImageData = Qt3DRender::QTextureImageDataPtr::create(); - mipImageData->setTarget(QOpenGLTexture::Target2D); - mipImageData->setFormat(data->format()); - mipImageData->setWidth(w); - mipImageData->setHeight(h); - mipImageData->setLayers(1); - mipImageData->setDepth(1); - mipImageData->setFaces(1); - // again, make no mistake: not setting 1 does not actually - // allow providing multiple mip level data in one texture image - // due to the bizarre API design of Qt3D. (the behavior is - // logical, technically, but the API over all is not) So - // separate textureimages is the only way to go. - mipImageData->setMipLevels(1); - mipImageData->setPixelFormat(data->pixelFormat()); - mipImageData->setPixelType(data->pixelType()); - - QByteArray mipData = generateIblMip(w, h, prevW, prevH, mipImageData->format(), - blockSize, prevLevelData); - mipImageData->setData(mipData, blockSize, false); - result << mipImageData; - prevLevelData = mipData; - } - m_iblTime += t.elapsed(); - qCDebug(lcPerf, "Generated %d IBL mip levels in %lld ms", maxMipLevel, t.elapsed()); - } - s_loadMutex.lock(); m_cache.insert(sourceStr, result); s_loadMutex.unlock(); @@ -346,6 +293,63 @@ QVector<Qt3DRender::QTextureImageDataPtr> Q3DSImageManager::load(const QUrl &sou return result; } +QVector<Qt3DRender::QTextureImageDataPtr> Q3DSImageManager::generateIblForImageData( + QVector<Qt3DRender::QTextureImageDataPtr> result) +{ + if (result.count() == 1) { + // IBL needs special mipmap generation. This could be done + // asynchronously but the we rely on the previous level in each step so + // it's not a good fit unfortunately. So do it all here. Also, + // QTextureGenerator could provide all mipmaps in one go in one blob, + // but there's no public API for that, have to stick with + // QTextureImageDataGenerator. + QElapsedTimer t; + t.start(); + Qt3DRender::QTextureImageDataPtr data = result.first(); + int w = data->width(); + int h = data->height(); + const int maxDim = w > h ? w : h; + const int maxMipLevel = int(qLn(maxDim) / qLn(2.0f)); + // silly QTextureImageData does not expose blockSize + const int blockSize = blockSizeForFormat(data->format()); + QByteArray prevLevelData = data->data(); + for (int i = 1; i <= maxMipLevel; ++i) { + int prevW = w; + int prevH = h; + w >>= 1; + h >>= 1; + w = qMax(1, w); + h = qMax(1, h); + + auto mipImageData = Qt3DRender::QTextureImageDataPtr::create(); + mipImageData->setTarget(QOpenGLTexture::Target2D); + mipImageData->setFormat(data->format()); + mipImageData->setWidth(w); + mipImageData->setHeight(h); + mipImageData->setLayers(1); + mipImageData->setDepth(1); + mipImageData->setFaces(1); + // again, make no mistake: not setting 1 does not actually + // allow providing multiple mip level data in one texture image + // due to the bizarre API design of Qt3D. (the behavior is + // logical, technically, but the API over all is not) So + // separate textureimages is the only way to go. + mipImageData->setMipLevels(1); + mipImageData->setPixelFormat(data->pixelFormat()); + mipImageData->setPixelType(data->pixelType()); + + QByteArray mipData = generateIblMip(w, h, prevW, prevH, mipImageData->format(), + blockSize, prevLevelData); + mipImageData->setData(mipData, blockSize, false); + result << mipImageData; + prevLevelData = mipData; + } + m_iblTime += t.elapsed(); + qCDebug(lcPerf, "Generated %d IBL mip levels in %lld ms", maxMipLevel, t.elapsed()); + } + return result; +} + void Q3DSImageManager::finishAsyncLoad(bool wait) { QMutexLocker lock(&m_finishAsyncLoadLock); @@ -403,7 +407,7 @@ void Q3DSImageManager::beginImageLoad(const QSet<QUrl> &imageSet) QFileInfo info(url.toLocalFile()); if (info.exists()) { if (!m_loadImageDataAsync.contains(url.toLocalFile())) - loadImageData(url, true); + loadImageData(url); for (int i = 0; i < m_reloadableTextures.size(); ++i) { if (m_reloadableTextures[i]->source() == url) m_reloadableTextures[i]->reload(); @@ -438,12 +442,11 @@ void Q3DSImageManager::beginUnload(const QSet<QUrl> &imageSet) void Q3DSImageManager::loadImageData(const QUrl &source, bool async) { - TextureInfo info; - auto loadImage = [this](const TextureInfo &info, const QUrl &source) { + auto loadImage = [this](const QUrl &source) { QVector<Qt3DRender::QTextureImageDataPtr> imageData; // The generator (invoked from some Qt3D job thread later on) will just return the already // loaded data. - imageData = load(source, info.flags); + imageData = load(source); }; QMutexLocker lock(&s_loadMutex); @@ -457,11 +460,11 @@ void Q3DSImageManager::loadImageData(const QUrl &source, bool async) qCDebug(lcScene, "Load image data async %s", qPrintable(src)); LoadImageDataAsync item; item.source = src; - item.future = QtConcurrent::run(&m_threadPool, loadImage, info, source); + item.future = QtConcurrent::run(&m_threadPool, loadImage, source); m_loadImageDataAsync[src] = item; } } else { - loadImage(info, source); + loadImage(source); } } @@ -493,6 +496,12 @@ void Q3DSImageManager::setSource(Qt3DRender::QAbstractTexture *tex, const QUrl & s_loadMutex.unlock(); auto &imageData = m_cache[src]; + if (info.flags.testFlag(GenerateMipMapsForIBL) && imageData.size() == 1) { + s_loadMutex.lock(); + m_cache[src] = generateIblForImageData(imageData); + s_loadMutex.unlock(); + } + const auto texImages = tex->textureImages(); for (Qt3DRender::QAbstractTextureImage *oldImage : texImages) { diff --git a/src/runtime/q3dsimagemanager_p.h b/src/runtime/q3dsimagemanager_p.h index 6281d63..1c89467 100644 --- a/src/runtime/q3dsimagemanager_p.h +++ b/src/runtime/q3dsimagemanager_p.h @@ -181,11 +181,13 @@ private: void loadImageData(const QUrl &source, bool async = true); void setSource(Qt3DRender::QAbstractTexture *tex, const QUrl &source); void textureLoaded(Qt3DRender::QAbstractTexture *tex, const QUrl &source); - QVector<Qt3DRender::QTextureImageDataPtr> load(const QUrl &source, ImageFlags flags); + QVector<Qt3DRender::QTextureImageDataPtr> load(const QUrl &source); int blockSizeForFormat(QOpenGLTexture::TextureFormat format); QByteArray generateIblMip(int w, int h, int prevW, int prevH, QOpenGLTexture::TextureFormat format, int blockSize, const QByteArray &prevLevelData); + QVector<Qt3DRender::QTextureImageDataPtr> generateIblForImageData( + QVector<Qt3DRender::QTextureImageDataPtr> result); struct TextureInfo { |