summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntti Määttä <antti.maatta@qt.io>2020-09-16 15:36:47 +0300
committerAntti Määttä <antti.maatta@qt.io>2020-09-24 16:07:19 +0300
commite551c9d27febae3a874cfd4c54ff9811abce0fc7 (patch)
tree3a11a4646219208ec3d649f4af17d0502f6b79c4
parent2cfefb01ed23dcff486014aba72d0d8208bcbc9a (diff)
Unify source path usage in runtime
There are several fixes done to source paths before their usage, but they are done in different places. Put these all into function and call this function before using the source paths. Task-number: QT3DS-4162 Change-Id: I0d3e3fd2db0cb11c6e9cb28fb3054568884059db Reviewed-by: Kaj Grönholm <kaj.gronholm@qt.io> Reviewed-by: Janne Koskinen <janne.p.koskinen@qt.io>
-rw-r--r--src/engine/Qt3DSRenderRuntimeBinding.cpp57
-rw-r--r--src/runtime/Qt3DSApplication.cpp26
-rw-r--r--src/runtimerender/Qt3DSRenderInputStreamFactory.cpp9
-rw-r--r--src/runtimerender/Qt3DSRenderInputStreamFactory.h1
-rw-r--r--src/runtimerender/graphobjects/Qt3DSRenderImage.cpp18
-rw-r--r--src/runtimerender/graphobjects/Qt3DSRenderImage.h4
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp8
-rw-r--r--src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp255
-rw-r--r--src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h12
-rw-r--r--src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.cpp20
-rw-r--r--src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.h2
-rw-r--r--src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp74
-rw-r--r--src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h1
13 files changed, 336 insertions, 151 deletions
diff --git a/src/engine/Qt3DSRenderRuntimeBinding.cpp b/src/engine/Qt3DSRenderRuntimeBinding.cpp
index 2a6cbde..50ef3df 100644
--- a/src/engine/Qt3DSRenderRuntimeBinding.cpp
+++ b/src/engine/Qt3DSRenderRuntimeBinding.cpp
@@ -703,7 +703,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene
nvvector<SGraphObject *>::iterator end = vec.end();
while (it != end) {
if ((*it)->m_Type == type)
- callable(static_cast<T*>(*it));
+ callable(static_cast<T*>(*it), preferKtx());
++it;
}
}
@@ -711,12 +711,14 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene
void PostLoadStep()
{
IBufferManager &mgr = m_Context->GetBufferManager();
- forAllObjects<SImage>(m_GraphObjectList, GraphObjectTypes::Image, [&mgr](SImage *image){
+ forAllObjects<SImage>(m_GraphObjectList, GraphObjectTypes::Image,
+ [&mgr](SImage *image, bool preferKtx){
if (image->m_ImagePath.IsValid() && qt3ds::runtime::isImagePath(
image->m_ImagePath.c_str())) {
const bool ibl = image->m_MappingMode == ImageMappingModes::LightProbe;
- image->m_LoadedTextureData = mgr.CreateReloadableImage(image->m_ImagePath,
- false, ibl);
+ const auto unified = IBufferManager::resolveImagePath(
+ QString::fromLatin1(image->m_ImagePath.c_str()), preferKtx);
+ image->m_LoadedTextureData = mgr.CreateReloadableImage(unified, false, ibl);
image->m_LoadedTextureData->m_callbacks.push_back(image);
}
});
@@ -930,8 +932,8 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager,
const QVector<QString> slideSourcePaths = inParser->GetSlideSourcePaths();
IBufferManager &theManager(m_Context->m_Context->GetBufferManager());
// List of image paths to be loaded in parallel at the end.
- eastl::vector<CRegisteredString> theSourcePathList;
- eastl::vector<CRegisteredString> iblList;
+ QVector<CRegisteredString> theSourcePathList;
+ QVector<CRegisteredString> iblList;
for (QT3DSU32 idx = 0, end = theSourcePathData.size(); idx < end; ++idx) {
const eastl::string &theValue = theSourcePathData[idx];
CRegisteredString theSourcePath =
@@ -962,23 +964,25 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager,
}
}
}
-
+ const auto preferKtx = theScene->m_Presentation->m_preferKTX;
+ const auto flipCompressed = theScene->m_Presentation->m_flipCompressedTextures;
+ const auto contextType = m_Context->m_Context->GetRenderContext().GetRenderContextType();
// Fire off parallel loading of the source paths
- QT3DSU64 imageBatchId = m_Context->m_Context->GetImageBatchLoader().LoadImageBatch(
+ auto &batchLoader = m_Context->m_Context->GetImageBatchLoader();
+ theSourcePathList = IBufferManager::resolveSourcePaths(*m_Context->m_StringTable,
+ theSourcePathList, preferKtx);
+ iblList = IBufferManager::resolveSourcePaths(*m_Context->m_StringTable, iblList,
+ preferKtx);
+
+ QT3DSU64 imageBatchId = batchLoader.LoadImageBatch(
toConstDataRef(theSourcePathList.data(), theSourcePathList.size()),
- CRegisteredString(), nullptr, m_Context->m_Context->GetRenderContext()
- .GetRenderContextType(),
- theScene->m_Presentation->m_preferKTX, false,
- theScene->m_Presentation->m_flipCompressedTextures);
- QT3DSU64 iblImageBatchId = m_Context->m_Context->GetImageBatchLoader().LoadImageBatch(
+ CRegisteredString(), nullptr, contextType, false, flipCompressed);
+ QT3DSU64 iblImageBatchId = batchLoader.LoadImageBatch(
toConstDataRef(iblList.data(), iblList.size()),
- CRegisteredString(), nullptr, m_Context->m_Context->GetRenderContext()
- .GetRenderContextType(),
- theScene->m_Presentation->m_preferKTX, true,
- theScene->m_Presentation->m_flipCompressedTextures);
- m_Context->m_Context->GetImageBatchLoader().BlockUntilLoaded(
+ CRegisteredString(), nullptr, contextType, true, flipCompressed);
+ batchLoader.BlockUntilLoaded(
static_cast<TImageBatchId>(imageBatchId));
- m_Context->m_Context->GetImageBatchLoader().BlockUntilLoaded(
+ batchLoader.BlockUntilLoaded(
static_cast<TImageBatchId>(iblImageBatchId));
theIScene = QT3DS_NEW(m_Context->GetAllocator(),
@@ -1123,10 +1127,8 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager,
// this means graphics have been initialized
eastl::string theSourcePathStr;
IBufferManager &theManager(m_Context->m_Context->GetBufferManager());
- nvvector<CRegisteredString> imagePathList(m_Context->GetAllocator(),
- "imagePathList");
- nvvector<CRegisteredString> iblImagePathList(m_Context->GetAllocator(),
- "iblImagePathList");
+ QVector<CRegisteredString> imagePathList;
+ QVector<CRegisteredString> iblImagePathList;
for (QT3DSU32 idx = 0, end = m_SourcePaths.size(); idx < end; ++idx) {
theSourcePathStr.assign(m_SourcePaths[idx].first);
bool hasTransparency = m_SourcePaths[idx].second.first;
@@ -1159,12 +1161,17 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager,
{
QT3DS_PERF_SCOPED_TIMER(m_Context->m_CoreContext->GetPerfTimer(),
"Binding: Initial Batch Image Load")
+ auto &batchLoader = m_Context->m_Context->GetImageBatchLoader();
+ imagePathList = IBufferManager::resolveSourcePaths(*m_Context->m_StringTable,
+ imagePathList, pktx);
+ iblImagePathList = IBufferManager::resolveSourcePaths(*m_Context->m_StringTable,
+ iblImagePathList, pktx);
- m_Context->m_Context->GetImageBatchLoader().LoadImageBatch(
+ batchLoader.LoadImageBatch(
toConstDataRef(imagePathList.data(), imagePathList.size()),
CRegisteredString(), nullptr, m_Context->m_Context->GetRenderContext()
.GetRenderContextType(), pktx, false);
- m_Context->m_Context->GetImageBatchLoader().LoadImageBatch(
+ batchLoader.LoadImageBatch(
toConstDataRef(iblImagePathList.data(), iblImagePathList.size()),
CRegisteredString(), nullptr, m_Context->m_Context->GetRenderContext()
.GetRenderContextType(), pktx, true);
diff --git a/src/runtime/Qt3DSApplication.cpp b/src/runtime/Qt3DSApplication.cpp
index 6bc7b1b..5c6dbb7 100644
--- a/src/runtime/Qt3DSApplication.cpp
+++ b/src/runtime/Qt3DSApplication.cpp
@@ -350,11 +350,12 @@ struct STextureUploadRenderTask : public IRenderTask, public IImageLoadListener
if (!m_deleteSet.isEmpty())
m_bufferManager.unloadSet(m_deleteSet);
if (!m_uploadSet.isEmpty()) {
- nvvector<CRegisteredString> sourcePaths(m_bufferManager.GetStringTable().GetAllocator(),
- "TempSourcePathList");
+ QVector<CRegisteredString> sourcePaths;
for (auto &s : qAsConst(m_uploadSet))
sourcePaths.push_back(m_bufferManager.GetStringTable().RegisterStr(s));
- QT3DSU32 id = m_batchLoader.LoadImageBatch(sourcePaths, CRegisteredString(),
+ QT3DSU32 id = m_batchLoader.LoadImageBatch(toConstDataRef(sourcePaths.data(),
+ sourcePaths.size()),
+ CRegisteredString(),
this, m_type, m_preferKtx, false);
if (id) {
m_batches[id] = m_uploadSet;
@@ -362,11 +363,12 @@ struct STextureUploadRenderTask : public IRenderTask, public IImageLoadListener
}
}
if (!m_uploadWaitSet.isEmpty()) {
- nvvector<CRegisteredString> sourcePaths(m_bufferManager.GetStringTable().GetAllocator(),
- "TempSourcePathList");
+ QVector<CRegisteredString> sourcePaths;
for (auto &s : qAsConst(m_uploadWaitSet))
sourcePaths.push_back(m_bufferManager.GetStringTable().RegisterStr(s));
- QT3DSU32 id = m_batchLoader.LoadImageBatch(sourcePaths, CRegisteredString(),
+ QT3DSU32 id = m_batchLoader.LoadImageBatch(toConstDataRef(sourcePaths.data(),
+ sourcePaths.size()),
+ CRegisteredString(),
this, m_type, m_preferKtx, false);
if (id) {
m_batchLoader.BlockUntilLoaded(id);
@@ -382,14 +384,16 @@ struct STextureUploadRenderTask : public IRenderTask, public IImageLoadListener
m_uploadWaitSet.unite(set);
else
m_uploadSet.unite(set);
- m_deleteSet.subtract(set);
+ const auto unified = IBufferManager::resolveImageSet(set, m_preferKtx);
+ m_deleteSet.subtract(unified);
}
void remove(const QSet<QString> &set)
{
+ const auto unified = IBufferManager::resolveImageSet(set, m_preferKtx);
QMutexLocker loc(&m_updateMutex);
- m_uploadSet.subtract(set);
- m_uploadWaitSet.subtract(set);
- m_deleteSet.unite(set);
+ m_uploadSet.subtract(unified);
+ m_uploadWaitSet.subtract(unified);
+ m_deleteSet.unite(unified);
}
bool persistent() const override
{
@@ -402,7 +406,7 @@ struct STextureUploadRenderTask : public IRenderTask, public IImageLoadListener
}
void OnImageBatchComplete(QT3DSU64 inBatch) override
{
- m_bufferManager.loadSet(m_batches[inBatch]);
+ m_bufferManager.loadSet(m_batches[inBatch], m_flipCompressedTextures);
}
};
diff --git a/src/runtimerender/Qt3DSRenderInputStreamFactory.cpp b/src/runtimerender/Qt3DSRenderInputStreamFactory.cpp
index 1a418b1..5b02164 100644
--- a/src/runtimerender/Qt3DSRenderInputStreamFactory.cpp
+++ b/src/runtimerender/Qt3DSRenderInputStreamFactory.cpp
@@ -205,6 +205,15 @@ struct SFactory : public IInputStreamFactory
}
return false;
}
+ bool GetPathForStream(IRefCountedInputStream *stream, QString &outFile) override
+ {
+ if (stream) {
+ SInputStream *theRealStream = static_cast<SInputStream *>(stream);
+ outFile = theRealStream->m_Path;
+ return true;
+ }
+ return false;
+ }
};
}
diff --git a/src/runtimerender/Qt3DSRenderInputStreamFactory.h b/src/runtimerender/Qt3DSRenderInputStreamFactory.h
index e82134b..fdc9e75 100644
--- a/src/runtimerender/Qt3DSRenderInputStreamFactory.h
+++ b/src/runtimerender/Qt3DSRenderInputStreamFactory.h
@@ -57,6 +57,7 @@ namespace render {
// else returns false
virtual bool GetPathForFile(const QString &inFilename, QString &outFile,
bool inQuiet = false) = 0;
+ virtual bool GetPathForStream(IRefCountedInputStream *stream, QString &outFile) = 0;
// Create an input stream factory using this foundation and an platform-optional app
// directory
diff --git a/src/runtimerender/graphobjects/Qt3DSRenderImage.cpp b/src/runtimerender/graphobjects/Qt3DSRenderImage.cpp
index 44e7f12..458f3bf 100644
--- a/src/runtimerender/graphobjects/Qt3DSRenderImage.cpp
+++ b/src/runtimerender/graphobjects/Qt3DSRenderImage.cpp
@@ -67,7 +67,8 @@ static void HandleOffscreenResult(SImage &theImage, SImageTextureData &newImage,
}
bool SImage::ClearDirty(IBufferManager &inBufferManager, IOffscreenRenderManager &inRenderManager,
- IRenderPluginManager &inPluginManager, bool forIbl, bool flipCompressed)
+ IRenderPluginManager &inPluginManager, bool preferKtx, bool forIbl,
+ bool flipCompressed)
{
bool wasDirty = m_Flags.IsDirty();
@@ -93,17 +94,22 @@ bool SImage::ClearDirty(IBufferManager &inBufferManager, IOffscreenRenderManager
}
}
+ // Do not recheck image path if we are not dirty and we already have a texture
+ if (!wasDirty)
+ newImage.m_Texture = m_TextureData.m_Texture;
+
if (newImage.m_Texture == nullptr) {
m_LastFrameOffscreenRenderer = nullptr;
if (m_ImagePath.IsValid() && !m_OffscreenRendererId.IsValid()
&& !inRenderManager.HasOffscreenRenderer(m_ImagePath)) {
// Image has sourcepath set
- if (!m_LoadedTextureData
- || m_LoadedTextureData->m_path != QString::fromUtf8(m_ImagePath.c_str())) {
+ const QString unifiedPath = IBufferManager::resolveImagePath(
+ QString::fromUtf8(m_ImagePath.c_str()), preferKtx);
+ if (!m_LoadedTextureData || m_LoadedTextureData->m_path != unifiedPath) {
if (m_LoadedTextureData)
m_LoadedTextureData->m_callbacks.removeOne(this);
forIbl = forIbl || m_MappingMode == ImageMappingModes::LightProbe;
- m_LoadedTextureData = inBufferManager.CreateReloadableImage(m_ImagePath, false,
+ m_LoadedTextureData = inBufferManager.CreateReloadableImage(unifiedPath, false,
forIbl, flipCompressed);
m_LoadedTextureData->m_callbacks.push_back(this);
}
@@ -114,8 +120,8 @@ bool SImage::ClearDirty(IBufferManager &inBufferManager, IOffscreenRenderManager
newImage.m_BSDFMipMap = m_LoadedTextureData->m_BSDFMipMap;
} else if (m_Flags.IsForceLoad()) {
QSet<QString> ls;
- ls.insert(QString(m_ImagePath));
- inBufferManager.loadSet(ls);
+ ls.insert(unifiedPath);
+ inBufferManager.loadSet(ls, flipCompressed);
newImage.m_Texture = m_LoadedTextureData->m_Texture;
newImage.m_TextureFlags = m_LoadedTextureData->m_TextureFlags;
newImage.m_BSDFMipMap = m_LoadedTextureData->m_BSDFMipMap;
diff --git a/src/runtimerender/graphobjects/Qt3DSRenderImage.h b/src/runtimerender/graphobjects/Qt3DSRenderImage.h
index 26b4377..04d890f 100644
--- a/src/runtimerender/graphobjects/Qt3DSRenderImage.h
+++ b/src/runtimerender/graphobjects/Qt3DSRenderImage.h
@@ -89,8 +89,8 @@ namespace render {
// Or finds the image.
// and sets up the texture transform
bool ClearDirty(IBufferManager &inBufferManager, IOffscreenRenderManager &inRenderManager,
- IRenderPluginManager &pluginManager, bool forIbl = false,
- bool flipCompressed = false);
+ IRenderPluginManager &pluginManager, bool preferKtx, bool forIbl,
+ bool flipCompressed);
void CalculateTextureTransform();
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp
index 26d2c71..677440e 100644
--- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp
@@ -641,7 +641,9 @@ namespace render {
qt3dsContext.GetOffscreenRenderManager());
IRenderPluginManager &theRenderPluginManager(qt3dsContext.GetRenderPluginManager());
if (inImage.ClearDirty(bufferManager, theOffscreenRenderManager, theRenderPluginManager,
- false, m_Layer.m_Scene->m_Presentation->m_flipCompressedTextures))
+ m_Layer.m_Scene->m_Presentation->m_preferKTX,
+ inImage.m_MappingMode == ImageMappingModes::LightProbe,
+ m_Layer.m_Scene->m_Presentation->m_flipCompressedTextures))
ioFlags |= RenderPreparationResultFlagValues::Dirty;
// All objects with offscreen renderers are pickable so we can pass the pick through to the
@@ -1180,7 +1182,9 @@ namespace render {
IQt3DSRenderContext &theContext(m_Renderer.GetQt3DSContext());
return inLightProbe.ClearDirty(theContext.GetBufferManager(),
theContext.GetOffscreenRenderManager(),
- theContext.GetRenderPluginManager(), true);
+ theContext.GetRenderPluginManager(),
+ m_Layer.m_Scene->m_Presentation->m_preferKTX, true,
+ m_Layer.m_Scene->m_Presentation->m_flipCompressedTextures);
}
struct SLightNodeMarker
diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp b/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp
index 43f7541..87fe54c 100644
--- a/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp
+++ b/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp
@@ -54,6 +54,207 @@
using namespace qt3ds::render;
+namespace qt3ds {
+namespace render {
+
+static const QString QT3DSTUDIO_TAG = QStringLiteral("qt3dstudio");
+
+static QFileInfo matchCaseInsensitiveFile(const QString& file)
+{
+ const auto searchFromPaths = [](QString file) -> QFileInfo {
+ QFileInfo fileInfo(file);
+ if (fileInfo.exists())
+ return fileInfo;
+
+ const QStringList searchDirectories = QDir::searchPaths(QT3DSTUDIO_TAG);
+ for (const auto &directoryPath : searchDirectories) {
+ auto path = QDir::cleanPath(directoryPath + '/' + file);
+ QFileInfo info(path);
+ if (info.exists())
+ return info;
+ }
+ return fileInfo;
+ };
+
+ QFileInfo info = searchFromPaths(file);
+ if (info.exists())
+ return info;
+
+ QString searchPath = file;
+
+ // Trying relative to search directories.
+ // First remove any ../ and ./ from the path
+ if (searchPath.startsWith(QLatin1String("../")))
+ searchPath = searchPath.right(searchPath.length() - 3);
+ else if (searchPath.startsWith(QLatin1String("./")))
+ searchPath = searchPath.right(searchPath.length() - 2);
+
+ int loops = 0;
+ while (++loops <= 4) {
+ info = searchFromPaths(searchPath);
+ if (info.exists())
+ return info;
+ searchPath.prepend(QLatin1String("../"));
+ }
+
+ return info;
+}
+
+static bool checkFileExists(const QString &tryFile, bool relative, QString &outFile)
+{
+ QFileInfo info;
+ if (relative)
+ info = matchCaseInsensitiveFile(tryFile);
+ else
+ info.setFile(tryFile);
+ if (info.exists()) {
+ outFile = info.filePath();
+ return true;
+ }
+ if (!relative) {
+ // Some textures, for example environment maps for custom materials,
+ // have absolute path at this point. It points to the wrong place with
+ // the new project structure, so we need to split it up and construct
+ // the new absolute path here.
+ QString wholePath = tryFile;
+ QStringList splitPath = wholePath.split(QLatin1String("../"));
+ if (splitPath.size() > 1) {
+ QString searchPath = splitPath.first() + splitPath.last();
+ int loops = 0;
+ while (++loops <= 3) {
+ info.setFile(searchPath);
+ if (info.exists()) {
+ outFile = info.filePath();
+ return true;
+ }
+ searchPath = splitPath.at(0);
+ for (int i = 0; i < loops; i++)
+ searchPath.append(QLatin1String("../"));
+ searchPath.append(splitPath.last());
+ }
+ }
+ }
+ return false;
+}
+
+// Locate existing file by adding a supported suffix to localFile.
+static bool existingImageFileForPath(const QString &localFile, bool relative, bool preferKTX,
+ QString &outPath)
+{
+ // Do nothing if given filepath exists without suffix
+ QFileInfo fi(localFile);
+ if (fi.exists()) {
+ outPath = localFile;
+ return true;
+ }
+
+ // Lists of supported image formats in preferred-first order.
+ const QStringList compressedFormats {"ktx", "astc", "dds"};
+ const QStringList nonCompressedFormats {"hdr", "png", "jpg", "jpeg", "gif"};
+
+ // Depending on preferKTX, check compressed formats before or after non-compressed ones.
+ QStringList supportedFormats = preferKTX ? compressedFormats + nonCompressedFormats
+ : nonCompressedFormats + compressedFormats;
+
+ // Check first if file exists from resources as that
+ // is common and optimal for integrity case.
+ for (const QString &suffix : supportedFormats) {
+ QString tryFile = ":/" + localFile + "." + suffix;
+ if (checkFileExists(tryFile, relative, outPath))
+ return true;
+ }
+ // If not found, check still file path as-is
+ for (const QString &suffix : supportedFormats) {
+ QString tryFile = localFile + "." + suffix;
+ if (checkFileExists(tryFile, relative, outPath))
+ return true;
+ }
+
+ outPath = localFile;
+ return false;
+}
+
+// Return resolved image path for unresolved source path.
+// Handle preferKtx, search paths, empty suffixes, schemas etc.
+QString IBufferManager::resolveImagePath(const QString &sourcePath, bool preferKtx)
+{
+ QString path = sourcePath;
+ QUrl urlPath(path);
+
+ // Do nothing for image providers
+ if (urlPath.scheme() == QLatin1String("image"))
+ return sourcePath;
+
+ // Normalize the path
+ path = CFileTools::NormalizePathForQtUsage(path);
+ urlPath.setUrl(path);
+
+ const bool hasSuffix = urlPath.fileName().contains(QLatin1Char('.'));
+ const bool relative = urlPath.isRelative();
+
+ // Find an image file corresponding to only filename without suffix
+ if (!hasSuffix) {
+ QString outPath;
+ if (!existingImageFileForPath(path, relative, preferKtx, outPath)) {
+ qCWarning(WARNING, "Failed to resolve path %s", qPrintable(sourcePath));
+ return {};
+ }
+ return outPath;
+ }
+
+ // First check ktx files if preferKtx is set
+ if (preferKtx) {
+ QString ktxSource = path;
+ const bool originalIsKtx = path.endsWith(QLatin1String("ktx"), Qt::CaseInsensitive);
+ if (!originalIsKtx) {
+ const int index = ktxSource.lastIndexOf(QLatin1Char('.'));
+ ktxSource = ktxSource.left(index);
+ ktxSource.append(QLatin1String(".ktx"));
+ }
+ QString result;
+ if (checkFileExists(ktxSource, relative, result))
+ return result;
+ if (originalIsKtx) {
+ qCWarning(WARNING, "Failed to resolve path %s", qPrintable(sourcePath));
+ return {};
+ }
+ }
+
+ QString result;
+ if (checkFileExists(path, relative, result))
+ return result;
+
+ qCWarning(WARNING, "Failed to resolve path %s", qPrintable(sourcePath));
+ return {};
+}
+
+QSet<QString> IBufferManager::resolveImageSet(const QSet<QString> &set, bool preferKtx)
+{
+ QSet<QString> ret;
+ for (auto &sourcePath : set) {
+ auto unified = resolveImagePath(sourcePath, preferKtx);
+ if (!unified.isEmpty())
+ ret.insert(unified);
+ }
+ return ret;
+}
+
+QVector<CRegisteredString> IBufferManager::resolveSourcePaths(
+ IStringTable &strTable, const QVector<CRegisteredString> &sourcePaths, bool preferKtx)
+{
+ QVector<CRegisteredString> ret;
+ for (int i = 0; i < sourcePaths.size(); i++) {
+ QString path = QString::fromLatin1(sourcePaths[i].c_str());
+ auto unified = strTable.RegisterStr(IBufferManager::resolveImagePath(path, preferKtx));
+ if (unified.IsValid())
+ ret.append(unified);
+ }
+ return ret;
+}
+
+}
+}
+
namespace {
using eastl::hash;
@@ -122,6 +323,7 @@ struct SBufferManager : public IBufferManager
QHash<QString, QSharedPointer<QQmlImageProviderBase> > m_imageProviders;
QHash<QString, ReloadableTexturePtr> m_reloadableTextures;
+ ReloadableTexturePtr m_nullTexture;
static const char8_t *GetPrimitivesDirectory() { return "res//primitives"; }
@@ -296,24 +498,25 @@ struct SBufferManager : public IBufferManager
void loadSet(const QSet<QString> &imageSet, bool flipCompressed) override
{
- for (const auto &x : imageSet) {
- if (!m_reloadableTextures.contains(x)) {
- auto img = CreateReloadableImage(m_StrTable->RegisterStr(qPrintable(x)), false,
- false, flipCompressed);
- img->m_initialized = false;
- loadTextureImage(*m_reloadableTextures[x]);
- } else if (!m_reloadableTextures[x]->m_loaded) {
- loadTextureImage(*m_reloadableTextures[x]);
+ for (const auto &sourcePath : imageSet) {
+ if (!m_reloadableTextures.contains(sourcePath)) {
+ auto img = CreateReloadableImage(sourcePath, false, false, flipCompressed);
+ if (img != m_nullTexture) {
+ img->m_initialized = false;
+ loadTextureImage(*m_reloadableTextures[sourcePath]);
+ }
+ } else if (!m_reloadableTextures[sourcePath]->m_loaded) {
+ loadTextureImage(*m_reloadableTextures[sourcePath]);
}
}
}
void unloadSet(const QSet<QString> &imageSet) override
{
- for (const auto &x : imageSet) {
- if (m_reloadableTextures.contains(x)) {
- if (m_reloadableTextures[x]->m_loaded)
- unloadTextureImage(*m_reloadableTextures[x]);
+ for (const auto &sourcePath : imageSet) {
+ if (m_reloadableTextures.contains(sourcePath)) {
+ if (m_reloadableTextures[sourcePath]->m_loaded)
+ unloadTextureImage(*m_reloadableTextures[sourcePath]);
}
}
}
@@ -328,18 +531,20 @@ struct SBufferManager : public IBufferManager
}
}
- virtual ReloadableTexturePtr CreateReloadableImage(CRegisteredString inSourcePath,
+ virtual ReloadableTexturePtr CreateReloadableImage(const QString &inSourcePath,
bool inForceScanForTransparency,
bool inBsdfMipmaps,
bool flipCompressed) override
{
- // Remove schema and root from keys. To prevent loading twice file "qrc:///foo" and "foo"
- QString path = QString::fromLatin1(inSourcePath.c_str());
- path = QUrl(path).path();
- if (path.startsWith(QLatin1String("/")))
- path = path.right(path.length() - 1);
-
+ const auto path = inSourcePath;
const bool inserted = m_reloadableTextures.contains(path);
+ if (path.isNull()) {
+ if (m_nullTexture.isNull()) {
+ m_nullTexture = ReloadableTexturePtr::create();
+ m_nullTexture->m_initialized = true;
+ }
+ return m_nullTexture;
+ }
if (!inserted || (inserted && m_reloadableTextures[path]->m_initialized == false)) {
if (!inserted)
m_reloadableTextures.insert(path, ReloadableTexturePtr::create());
@@ -361,13 +566,13 @@ struct SBufferManager : public IBufferManager
// Failed to look up image from map, perhaps external of UIP/UIA image
// Try with full URI and load from filesystem.
if (theIter == m_ImageMap.end())
- theIter = m_ImageMap.find(getImagePath(QString::fromLatin1(inSourcePath.c_str())));
+ theIter = m_ImageMap.find(getImagePath(inSourcePath));
if (theIter == m_ImageMap.end()) {
loadTextureImage(*m_reloadableTextures[path], flipCompressed);
imagePath = getImagePath(path);
theIter = m_ImageMap.find(imagePath);
if (theIter == m_ImageMap.end())
- theIter = m_ImageMap.find(getImagePath(QString::fromLatin1(inSourcePath.c_str())));
+ theIter = m_ImageMap.find(getImagePath(inSourcePath));
}
#endif
if (theIter != m_ImageMap.end()) {
@@ -390,7 +595,7 @@ struct SBufferManager : public IBufferManager
QT3DS_PERF_SCOPED_TIMER(m_PerfTimer, "BufferManager: Image Decompression")
theLoadedImage = SLoadedTexture::Load(
inImagePath.c_str(), m_Context->GetFoundation(), *m_InputStreamFactory,
- true, inFlipCompressed, m_Context->GetRenderContextType(), false, this);
+ true, inFlipCompressed, m_Context->GetRenderContextType(), this);
// Hackish solution to custom materials not finding their textures if they are used
// in sub-presentations.
if (!theLoadedImage) {
@@ -403,7 +608,7 @@ struct SBufferManager : public IBufferManager
theLoadedImage = SLoadedTexture::Load(
searchPathRel.toUtf8(), m_Context->GetFoundation(),
*m_InputStreamFactory, true, false,
- m_Context->GetRenderContextType(), false, this);
+ m_Context->GetRenderContextType(), this);
}
if (!theLoadedImage) {
@@ -415,7 +620,7 @@ struct SBufferManager : public IBufferManager
theLoadedImage = SLoadedTexture::Load(
searchPath.toUtf8(), m_Context->GetFoundation(),
*m_InputStreamFactory, true, false,
- m_Context->GetRenderContextType(), false, this);
+ m_Context->GetRenderContextType(), this);
searchPath.prepend(QLatin1String("../"));
}
}
@@ -435,7 +640,7 @@ struct SBufferManager : public IBufferManager
theLoadedImage = SLoadedTexture::Load(
searchPath.toUtf8(), m_Context->GetFoundation(),
*m_InputStreamFactory, true, false,
- m_Context->GetRenderContextType(), false, this);
+ m_Context->GetRenderContextType(), this);
searchPath = splitPath.at(0);
for (int i = 0; i < loops; i++)
searchPath.append(QLatin1String("../"));
diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h b/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h
index 0debd9c..159e02b 100644
--- a/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h
+++ b/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h
@@ -79,6 +79,12 @@ namespace render {
bool inIgnoreIfLoaded) = 0;
virtual void UnaliasImagePath(CRegisteredString inSourcePath) = 0;
+ // Return resolved imagepaths from unresolved sourcepaths
+ static QString resolveImagePath(const QString &sourcePath, bool preferKtx);
+ static QSet<QString> resolveImageSet(const QSet<QString> &set, bool preferKtx);
+ static QVector<CRegisteredString> resolveSourcePaths(IStringTable &strTable,
+ const QVector<CRegisteredString> &sourcePaths, bool preferKtx);
+
// Returns the given source path unless the source path is aliased; in which case returns
// the aliased path.
virtual CRegisteredString GetImagePath(CRegisteredString inSourcePath) = 0;
@@ -93,15 +99,15 @@ namespace render {
bool inForceScanForTransparency = false,
bool inBsdfMipmaps = false) = 0;
- virtual ReloadableTexturePtr CreateReloadableImage(CRegisteredString inSourcePath,
+ virtual ReloadableTexturePtr CreateReloadableImage(const QString &inSourcePath,
bool inForceScanForTransparency = false,
bool inBsdfMipmaps = false,
bool flipCompressed = false) = 0;
virtual void enableReloadableResources(bool enable) = 0;
virtual bool isReloadableResourcesEnabled() const = 0;
- virtual void loadSet(const QSet<QString> &imageSet, bool flipCompressed = false) = 0;
- virtual void unloadSet(const QSet<QString> &imageSet) = 0;
+ virtual void loadSet(const QSet<QString> &unifiedImageSet, bool flipCompressed) = 0;
+ virtual void unloadSet(const QSet<QString> &unifiedImageSet) = 0;
virtual void reloadAll(bool flipCompressed) = 0;
virtual void loadCustomMesh(const QString &name, qt3dsimp::Mesh *mesh) = 0;
diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.cpp b/src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.cpp
index 28e0e4a..01ec9d4 100644
--- a/src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.cpp
+++ b/src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.cpp
@@ -108,7 +108,6 @@ struct SImageLoaderBatch
QT3DSU32 m_FinalizedImageCount;
QT3DSU32 m_NumImages;
NVRenderContextType m_contextType;
- bool m_preferKTX;
bool m_flipCompressedTextures;
bool m_ibl;
@@ -118,14 +117,14 @@ struct SImageLoaderBatch
CRegisteredString inImageTillLoaded,
IImageLoadListener *inListener,
NVRenderContextType contextType,
- bool preferKTX, bool iblImage,
+ bool iblImage,
bool flipCompressedTextures);
// Called from main thread
SImageLoaderBatch(SBatchLoader &inLoader, IImageLoadListener *inLoadListener,
const TLoadingImageList &inImageList, TImageBatchId inBatchId,
- QT3DSU32 inImageCount, NVRenderContextType contextType,
- bool preferKTX, bool ibl, bool flipCompressedTextures);
+ QT3DSU32 inImageCount, NVRenderContextType contextType, bool ibl,
+ bool flipCompressedTextures);
// Called from main thread
~SImageLoaderBatch();
@@ -265,7 +264,7 @@ struct SBatchLoader : public IImageBatchLoader
CRegisteredString inImageTillLoaded,
IImageLoadListener *inListener,
NVRenderContextType contextType,
- bool preferKTX, bool iblImages,
+ bool iblImages,
bool flipCompressedTextures) override
{
if (inSourcePaths.size() == 0)
@@ -282,7 +281,7 @@ struct SBatchLoader : public IImageBatchLoader
SImageLoaderBatch *theBatch(SImageLoaderBatch::CreateLoaderBatch(
*this, theBatchId, inSourcePaths, inImageTillLoaded, inListener, contextType,
- preferKTX, iblImages, flipCompressedTextures));
+ iblImages, flipCompressedTextures));
if (theBatch) {
m_Batches.insert(eastl::make_pair(theBatchId, theBatch));
return theBatchId;
@@ -394,7 +393,6 @@ void SLoadingImage::LoadImage(void *inImg)
theThis->m_Batch->m_Loader.m_InputStreamFactory, true,
theThis->m_Batch->m_flipCompressedTextures,
theThis->m_Batch->m_contextType,
- theThis->m_Batch->m_preferKTX,
&theThis->m_Batch->m_Loader.m_BufferManager);
// if ( theTexture )
// theTexture->EnsureMultiplerOfFour( theThis->m_Batch->m_Loader.m_Foundation,
@@ -437,8 +435,7 @@ SImageLoaderBatch::CreateLoaderBatch(SBatchLoader &inLoader, TImageBatchId inBat
NVConstDataRef<CRegisteredString> inSourcePaths,
CRegisteredString inImageTillLoaded,
IImageLoadListener *inListener,
- NVRenderContextType contextType,
- bool preferKTX, bool iblImages,
+ NVRenderContextType contextType, bool iblImages,
bool flipCompressedTextures)
{
TLoadingImageList theImages;
@@ -477,7 +474,7 @@ SImageLoaderBatch::CreateLoaderBatch(SBatchLoader &inLoader, TImageBatchId inBat
(SImageLoaderBatch *)inLoader.m_BatchPool.allocate(__FILE__, __LINE__);
new (theBatch)
SImageLoaderBatch(inLoader, inListener, theImages, inBatchId, theLoadingImageCount,
- contextType, preferKTX, iblImages, flipCompressedTextures);
+ contextType, iblImages, flipCompressedTextures);
return theBatch;
}
return NULL;
@@ -486,7 +483,7 @@ SImageLoaderBatch::CreateLoaderBatch(SBatchLoader &inLoader, TImageBatchId inBat
SImageLoaderBatch::SImageLoaderBatch(SBatchLoader &inLoader, IImageLoadListener *inLoadListener,
const TLoadingImageList &inImageList, TImageBatchId inBatchId,
QT3DSU32 inImageCount, NVRenderContextType contextType,
- bool preferKTX, bool ibl, bool flipCompressedTextures)
+ bool ibl, bool flipCompressedTextures)
: m_Loader(inLoader)
, m_LoadListener(inLoadListener)
, m_LoadEvent(inLoader.m_Foundation.getAllocator())
@@ -497,7 +494,6 @@ SImageLoaderBatch::SImageLoaderBatch(SBatchLoader &inLoader, IImageLoadListener
, m_FinalizedImageCount(0)
, m_NumImages(inImageCount)
, m_contextType(contextType)
- , m_preferKTX(preferKTX)
, m_ibl(ibl)
, m_flipCompressedTextures(flipCompressedTextures)
{
diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.h b/src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.h
index 64caa21..03b5599 100644
--- a/src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.h
+++ b/src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.h
@@ -73,7 +73,7 @@ namespace render {
CRegisteredString inImageTillLoaded,
IImageLoadListener *inListener,
NVRenderContextType type,
- bool preferKTX, bool iblImages,
+ bool iblImages,
bool flipCompressedTextures = false) = 0;
// Blocks if any of the images in the batch are in flight
virtual void CancelImageBatchLoading(TImageBatchId inBatchId) = 0;
diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp b/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp
index 8046a10..634e3c0 100644
--- a/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp
+++ b/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp
@@ -908,78 +908,26 @@ void SLoadedTexture::ReleaseDecompressedTexture(STextureData inImage)
m_Allocator.deallocate(inImage.data);
}
-// Locate existing file by adding a supported suffix to localFile.
-// If localFile already contains suffix or exiting file isn't found
-// returns localFile unchanged.
-static QString existingImageFileForPath(const QString &localFile, bool preferKTX)
-{
- // Do nothing if given filepath exists or already has a suffix
- QFileInfo fi(localFile);
- if (!fi.suffix().isEmpty() || fi.exists())
- return localFile;
-
- // Lists of supported image formats in preferred-first order.
- const QStringList compressedFormats {"ktx", "astc", "dds"};
- const QStringList nonCompressedFormats {"hdr", "png", "jpg", "jpeg", "gif"};
-
- // Depending on preferKTX, check compressed formats before or after non-compressed ones.
- QStringList supportedFormats = preferKTX ? compressedFormats + nonCompressedFormats
- : nonCompressedFormats + compressedFormats;
-
- // Check first if file exists from resources as that
- // is common and optimal for integrity case.
- for (const QString &suffix : supportedFormats) {
- QString tryFile = ":/" + localFile + "." + suffix;
- if (QFileInfo::exists(tryFile))
- return tryFile;
- }
- // If not found, check still file path as-is
- for (const QString &suffix : supportedFormats) {
- QString tryFile = localFile + "." + suffix;
- if (QFileInfo::exists(tryFile))
- return tryFile;
- }
-
- return localFile;
-}
-
-SLoadedTexture *SLoadedTexture::Load(const QString &inPath, NVFoundationBase &inFoundation,
+SLoadedTexture *SLoadedTexture::Load(const QString &path, NVFoundationBase &inFoundation,
IInputStreamFactory &inFactory, bool inFlipY,
bool inFlipCompressed,
- NVRenderContextType renderContextType, bool preferKTX,
+ NVRenderContextType renderContextType,
IBufferManager *bufferManager)
{
- if (inPath.isEmpty())
+ if (path.isEmpty())
return nullptr;
- if (QUrl(inPath).scheme() == QLatin1String("image"))
- return LoadQImage(inPath, inFlipY, inFoundation, renderContextType, bufferManager);
+ if (QUrl(path).scheme() == QLatin1String("image"))
+ return LoadQImage(path, inFlipY, inFoundation, renderContextType, bufferManager);
- // If inPath doesn't have suffix, try to find most optimal existing one
- QString path = existingImageFileForPath(inPath, preferKTX);
+ SLoadedTexture *theLoadedImage = nullptr;
+ NVScopedRefCounted<IRefCountedInputStream> theStream(inFactory.GetStreamForFile(path, true));
- // If preferKTX is true, always check KTX path first
- QString ktxSource = path;
- if (preferKTX) {
- ktxSource = ktxSource.left(ktxSource.lastIndexOf(QLatin1Char('.')));
- ktxSource.append(QLatin1String(".ktx"));
- }
+ if (!theStream.mPtr)
+ return nullptr;
- SLoadedTexture *theLoadedImage = nullptr;
- // We will get invalid error logs of files not found if we don't force quiet mode
- // If the file is actually missing, it will be logged later (loaded image is null)
- NVScopedRefCounted<IRefCountedInputStream> theStream(
- inFactory.GetStreamForFile(preferKTX ? ktxSource : path, true));
- if (!theStream.mPtr) {
- if (preferKTX)
- theStream = inFactory.GetStreamForFile(path, true);
- else
- return nullptr;
- } else {
- path = ktxSource;
- }
QString fileName;
- inFactory.GetPathForFile(path, fileName, true);
+ inFactory.GetPathForStream(theStream.mPtr, fileName);
if (theStream.mPtr && path.size() > 3) {
if (path.endsWith(QLatin1String("png"), Qt::CaseInsensitive)
|| path.endsWith(QLatin1String("jpg"), Qt::CaseInsensitive)
@@ -1006,7 +954,7 @@ SLoadedTexture *SLoadedTexture::Load(const QString &inPath, NVFoundationBase &in
inFlipCompressed);
theLoadedImage = LoadASTC(fileName, inFlipY, inFoundation, renderContextType);
} else {
- qCWarning(INTERNAL_ERROR, "Unrecognized image extension: %s", qPrintable(inPath));
+ qCWarning(INTERNAL_ERROR, "Unrecognized image extension: %s", qPrintable(path));
}
}
diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h b/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h
index 44d07de..c2aca9e 100644
--- a/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h
+++ b/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h
@@ -157,7 +157,6 @@ namespace render {
bool inFlipCompressed = false,
NVRenderContextType renderContextType
= NVRenderContextValues::NullContext,
- bool preferKTX = false,
IBufferManager *bufferManager = nullptr);
static SLoadedTexture *LoadDDS(IInStream &inStream, QT3DSI32 flipVertical,
NVFoundationBase &fnd,