summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAntti Määttä <antti.maatta@qt.io>2019-03-21 16:31:32 +0200
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-03-21 15:01:44 +0000
commit92079605819c10de4d950ed4a5254da8546b140a (patch)
tree59a82e32a3ceea5452b468eb960b992608015ddd /src
parent78488c1aa32d9f61656969de387b0b1d17b781db (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>
Diffstat (limited to 'src')
-rw-r--r--src/runtime/q3dsimagemanager.cpp131
-rw-r--r--src/runtime/q3dsimagemanager_p.h4
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 {