diff --git a/libs/gltfio/include/gltfio/TextureProvider.h b/libs/gltfio/include/gltfio/TextureProvider.h index 2cabe1e3d4..3adc5765ce 100644 --- a/libs/gltfio/include/gltfio/TextureProvider.h +++ b/libs/gltfio/include/gltfio/TextureProvider.h @@ -21,6 +21,7 @@ #include #include +#include namespace filament { class Engine; @@ -71,9 +72,9 @@ namespace filament::gltfio { class UTILS_PUBLIC TextureProvider { public: using Texture = filament::Texture; - using FlagBits = uint64_t; - enum class Flags { + enum class TextureFlags : uint64_t { + NONE = 0, sRGB = 1 << 0, }; @@ -86,7 +87,7 @@ public: * Texture object, but it is only safe to do so after it has been popped from the queue. */ virtual Texture* pushTexture(const uint8_t* data, size_t byteCount, - const char* mimeType, FlagBits flags) = 0; + const char* mimeType, TextureFlags flags) = 0; /** * Checks if any texture is ready to be removed from the asynchronous decoding queue, and if so @@ -177,4 +178,7 @@ TextureProvider* createKtx2Provider(filament::Engine* engine); } // namespace filament::gltfio +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; + #endif // GLTFIO_TEXTUREPROVIDER_H diff --git a/libs/gltfio/src/AssetLoader.cpp b/libs/gltfio/src/AssetLoader.cpp index b430c1fcfc..cd250c6eb9 100644 --- a/libs/gltfio/src/AssetLoader.cpp +++ b/libs/gltfio/src/AssetLoader.cpp @@ -1317,8 +1317,11 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse mi->setParameter("glossinessFactor", sgConfig.glossiness_factor); } + const TextureProvider::TextureFlags sRGB = TextureProvider::TextureFlags::sRGB; + const TextureProvider::TextureFlags LINEAR = TextureProvider::TextureFlags::NONE; + if (matkey.hasBaseColorTexture) { - mAsset->addTextureBinding(mi, "baseColorMap", baseColorTexture.texture, true); + mAsset->addTextureBinding(mi, "baseColorMap", baseColorTexture.texture, sRGB); if (matkey.hasTextureTransforms) { const cgltf_texture_transform& uvt = baseColorTexture.transform; auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale); @@ -1331,7 +1334,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse // enabled. Note that KHR_materials_pbrSpecularGlossiness specifies that diffuseTexture and // specularGlossinessTexture are both sRGB, whereas the core glTF spec stipulates that // metallicRoughness is not sRGB. - bool srgb = inputMat->has_pbr_specular_glossiness; + TextureProvider::TextureFlags srgb = inputMat->has_pbr_specular_glossiness ? sRGB : LINEAR; mAsset->addTextureBinding(mi, "metallicRoughnessMap", metallicRoughnessTexture.texture, srgb); if (matkey.hasTextureTransforms) { const cgltf_texture_transform& uvt = metallicRoughnessTexture.transform; @@ -1341,7 +1344,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse } if (matkey.hasNormalTexture) { - mAsset->addTextureBinding(mi, "normalMap", inputMat->normal_texture.texture, false); + mAsset->addTextureBinding(mi, "normalMap", inputMat->normal_texture.texture, LINEAR); if (matkey.hasTextureTransforms) { const cgltf_texture_transform& uvt = inputMat->normal_texture.transform; auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale); @@ -1353,7 +1356,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse } if (matkey.hasOcclusionTexture) { - mAsset->addTextureBinding(mi, "occlusionMap", inputMat->occlusion_texture.texture, false); + mAsset->addTextureBinding(mi, "occlusionMap", inputMat->occlusion_texture.texture, LINEAR); if (matkey.hasTextureTransforms) { const cgltf_texture_transform& uvt = inputMat->occlusion_texture.transform; auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale); @@ -1365,7 +1368,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse } if (matkey.hasEmissiveTexture) { - mAsset->addTextureBinding(mi, "emissiveMap", inputMat->emissive_texture.texture, true); + mAsset->addTextureBinding(mi, "emissiveMap", inputMat->emissive_texture.texture, sRGB); if (matkey.hasTextureTransforms) { const cgltf_texture_transform& uvt = inputMat->emissive_texture.transform; auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale); @@ -1379,7 +1382,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse if (matkey.hasClearCoatTexture) { mAsset->addTextureBinding(mi, "clearCoatMap", ccConfig.clearcoat_texture.texture, - false); + LINEAR); if (matkey.hasTextureTransforms) { const cgltf_texture_transform& uvt = ccConfig.clearcoat_texture.transform; auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale); @@ -1388,7 +1391,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse } if (matkey.hasClearCoatRoughnessTexture) { mAsset->addTextureBinding(mi, "clearCoatRoughnessMap", - ccConfig.clearcoat_roughness_texture.texture, false); + ccConfig.clearcoat_roughness_texture.texture, LINEAR); if (matkey.hasTextureTransforms) { const cgltf_texture_transform& uvt = ccConfig.clearcoat_roughness_texture.transform; auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale); @@ -1397,7 +1400,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse } if (matkey.hasClearCoatNormalTexture) { mAsset->addTextureBinding(mi, "clearCoatNormalMap", - ccConfig.clearcoat_normal_texture.texture, false); + ccConfig.clearcoat_normal_texture.texture, LINEAR); if (matkey.hasTextureTransforms) { const cgltf_texture_transform& uvt = ccConfig.clearcoat_normal_texture.transform; auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale); @@ -1414,7 +1417,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse if (matkey.hasSheenColorTexture) { mAsset->addTextureBinding(mi, "sheenColorMap", shConfig.sheen_color_texture.texture, - true); + sRGB); if (matkey.hasTextureTransforms) { const cgltf_texture_transform& uvt = shConfig.sheen_color_texture.transform; auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale); @@ -1423,7 +1426,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse } if (matkey.hasSheenRoughnessTexture) { mAsset->addTextureBinding(mi, "sheenRoughnessMap", - shConfig.sheen_roughness_texture.texture, false); + shConfig.sheen_roughness_texture.texture, LINEAR); if (matkey.hasTextureTransforms) { const cgltf_texture_transform& uvt = shConfig.sheen_roughness_texture.transform; auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale); @@ -1444,7 +1447,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse if (matkey.hasVolumeThicknessTexture) { mAsset->addTextureBinding(mi, "volumeThicknessMap", vlConfig.thickness_texture.texture, - false); + LINEAR); if (matkey.hasTextureTransforms) { const cgltf_texture_transform& uvt = vlConfig.thickness_texture.transform; auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale); @@ -1457,7 +1460,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse mi->setParameter("transmissionFactor", trConfig.transmission_factor); if (matkey.hasTransmissionTexture) { mAsset->addTextureBinding(mi, "transmissionMap", trConfig.transmission_texture.texture, - false); + LINEAR); if (matkey.hasTextureTransforms) { const cgltf_texture_transform& uvt = trConfig.transmission_texture.transform; auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale); diff --git a/libs/gltfio/src/DependencyGraph.h b/libs/gltfio/src/DependencyGraph.h index 7ecd40edca..f060021119 100644 --- a/libs/gltfio/src/DependencyGraph.h +++ b/libs/gltfio/src/DependencyGraph.h @@ -79,12 +79,6 @@ public: // Marks the given texture as being fully decoded, with all miplevels initialized. void markAsReady(Texture* texture); - // Marks the material as ready, but due to an error. - // - // This should be called when it known that at least one of the material's texture - // dependencies will never become available. - void markAsError(Material* material) { markAsReady(material); } - private: struct TextureNode { Texture* texture; diff --git a/libs/gltfio/src/FFilamentAsset.h b/libs/gltfio/src/FFilamentAsset.h index 25b7a18643..2ceb8452d9 100644 --- a/libs/gltfio/src/FFilamentAsset.h +++ b/libs/gltfio/src/FFilamentAsset.h @@ -30,6 +30,7 @@ #include #include +#include #include @@ -249,7 +250,7 @@ struct FFilamentAsset : public FilamentAsset { // If a Filament Texture for the given args already exists, calls setParameter() and returns // early. If the Texture doesn't exist yet, stashes binding information for later. void addTextureBinding(MaterialInstance* materialInstance, const char* parameterName, - const cgltf_texture* srcTexture, bool srgb); + const cgltf_texture* srcTexture, TextureProvider::TextureFlags flags); // Calls mi->setParameter() for the given texture slot and optionally adds an edge // to the dependency graph used for gradual reveal of entities. @@ -315,7 +316,7 @@ struct FFilamentAsset : public FilamentAsset { struct TextureInfo { std::vector bindings; Texture* texture; - bool srgb; + TextureProvider::TextureFlags flags; }; // Mapping from cgltf_texture to Texture* is required when creating new instances. diff --git a/libs/gltfio/src/FilamentAsset.cpp b/libs/gltfio/src/FilamentAsset.cpp index 6040b6762a..20afabcb39 100644 --- a/libs/gltfio/src/FilamentAsset.cpp +++ b/libs/gltfio/src/FilamentAsset.cpp @@ -99,7 +99,8 @@ const char* FFilamentAsset::getExtras(utils::Entity entity) const noexcept { } void FFilamentAsset::addTextureBinding(MaterialInstance* materialInstance, - const char* parameterName, const cgltf_texture* srcTexture, bool srgb) { + const char* parameterName, const cgltf_texture* srcTexture, + TextureProvider::TextureFlags flags) { if (!srcTexture->image && !srcTexture->basisu_image) { #ifndef NDEBUG slog.w << "Texture is missing image (" << srcTexture->name << ")." << io::endl; @@ -111,8 +112,8 @@ void FFilamentAsset::addTextureBinding(MaterialInstance* materialInstance, TextureInfo& info = mTextures[textureIndex]; // All bindings for a particular glTF texture must have the same transform function. - assert_invariant(info.bindings.size() == 0 || info.srgb == srgb); - info.srgb = srgb; + assert_invariant(info.bindings.size() == 0 || info.flags == flags); + info.flags = flags; const TextureSlot slot = { materialInstance, parameterName }; if (info.texture) { diff --git a/libs/gltfio/src/Ktx2Provider.cpp b/libs/gltfio/src/Ktx2Provider.cpp index adcd96f030..52e80ade32 100644 --- a/libs/gltfio/src/Ktx2Provider.cpp +++ b/libs/gltfio/src/Ktx2Provider.cpp @@ -41,7 +41,7 @@ public: ~Ktx2Provider(); Texture* pushTexture(const uint8_t* data, size_t byteCount, - const char* mimeType, uint64_t flags) final; + const char* mimeType, TextureFlags flags) final; Texture* popTexture() final; void updateQueue() final; @@ -87,12 +87,12 @@ private: }; Texture* Ktx2Provider::pushTexture(const uint8_t* data, size_t byteCount, - const char* mimeType, FlagBits flags) { + const char* mimeType, TextureProvider::TextureFlags flags) { using TransferFunction = ktxreader::Ktx2Reader::TransferFunction; - const FlagBits sRGB = FlagBits(Flags::sRGB); auto async = mKtxReader->asyncCreate(data, byteCount, - (flags & sRGB) ? TransferFunction::sRGB : TransferFunction::LINEAR); + any(flags & TextureProvider::TextureFlags::sRGB) ? + TransferFunction::sRGB : TransferFunction::LINEAR); if (async == nullptr) { mRecentPushMessage = "Unable to build Texture object."; diff --git a/libs/gltfio/src/ResourceLoader.cpp b/libs/gltfio/src/ResourceLoader.cpp index 0fd9973e59..8de25e6ac1 100644 --- a/libs/gltfio/src/ResourceLoader.cpp +++ b/libs/gltfio/src/ResourceLoader.cpp @@ -91,7 +91,8 @@ struct ResourceLoader::Impl { void computeTangents(FFilamentAsset* asset); void createTextures(FFilamentAsset* asset, bool async); void cancelTextureDecoding(); - Texture* getOrCreateTexture(FFilamentAsset* asset, size_t textureIndex, const TextureSlot& tb); + Texture* getOrCreateTexture(FFilamentAsset* asset, size_t textureIndex, + TextureProvider::TextureFlags flags); ~Impl(); }; @@ -555,18 +556,14 @@ void ResourceLoader::asyncUpdateLoad() { } Texture* ResourceLoader::Impl::getOrCreateTexture(FFilamentAsset* asset, size_t textureIndex, - const TextureSlot& tb) { + TextureProvider::TextureFlags flags) { const cgltf_texture& srcTexture = asset->mSourceAsset->hierarchy->textures[textureIndex]; const cgltf_image* image = srcTexture.basisu_image ? srcTexture.basisu_image : srcTexture.image; const cgltf_buffer_view* bv = image->buffer_view; const char* uri = image->uri; - TextureProvider::FlagBits flags = {}; FFilamentAsset::TextureInfo& info = asset->mTextures[textureIndex]; - if (info.srgb) { - flags |= int(TextureProvider::Flags::sRGB); - } std::string mime = image->mime_type ? image->mime_type : ""; size_t dataUriSize; @@ -581,7 +578,6 @@ Texture* ResourceLoader::Impl::getOrCreateTexture(FFilamentAsset* asset, size_t TextureProvider* provider = mTextureProviders[mime]; if (!provider) { slog.e << "Missing texture provider for " << mime << io::endl; - asset->mDependencyGraph.markAsError(tb.materialInstance); return nullptr; } @@ -634,7 +630,6 @@ Texture* ResourceLoader::Impl::getOrCreateTexture(FFilamentAsset* asset, size_t Path fullpath = Path(mGltfPath).getParent() + uri; if (!fullpath.exists()) { slog.e << "Unable to open " << fullpath << io::endl; - asset->mDependencyGraph.markAsError(tb.materialInstance); return nullptr; } using namespace std; @@ -659,7 +654,6 @@ Texture* ResourceLoader::Impl::getOrCreateTexture(FFilamentAsset* asset, size_t const char* name = srcTexture.name ? srcTexture.name : uri; slog.e << "Unable to create texture " << name << ": " << provider->getPushMessage() << io::endl; - asset->mDependencyGraph.markAsError(tb.materialInstance); } else { info.texture = texture; } @@ -679,10 +673,14 @@ void ResourceLoader::Impl::createTextures(FFilamentAsset* asset, bool async) { mRemainingTextureDownloads = 0; size_t textureIndex = 0; for (FFilamentAsset::TextureInfo& info : asset->mTextures) { - for (const TextureSlot& slot : info.bindings) { + // There might be no bindings yet (e.g. if the user is preloading a zero-instance asset) + // in which case we still need to trigger texture creation. + getOrCreateTexture(asset, textureIndex, info.flags); - // Returns null if the user has not yet called addResourceData for the texture. - if (Texture* texture = getOrCreateTexture(asset, textureIndex, slot)) { + // For each binding to a material instance, check if the texture exists yet; if so, + // call setParameter(...) on the material. + for (const TextureSlot& slot : info.bindings) { + if (Texture* texture = getOrCreateTexture(asset, textureIndex, info.flags)) { asset->applyTextureBinding(textureIndex, slot); } } diff --git a/libs/gltfio/src/StbProvider.cpp b/libs/gltfio/src/StbProvider.cpp index 876dd255da..4c5f811b31 100644 --- a/libs/gltfio/src/StbProvider.cpp +++ b/libs/gltfio/src/StbProvider.cpp @@ -42,7 +42,7 @@ public: ~StbProvider(); Texture* pushTexture(const uint8_t* data, size_t byteCount, - const char* mimeType, uint64_t flags) final; + const char* mimeType, TextureFlags flags) final; Texture* popTexture() final; void updateQueue() final; @@ -87,7 +87,7 @@ private: }; Texture* StbProvider::pushTexture(const uint8_t* data, size_t byteCount, - const char* mimeType, FlagBits flags) { + const char* mimeType, TextureFlags flags) { int width, height, numComponents; if (!stbi_info_from_memory(data, byteCount, &width, &height, &numComponents)) { mRecentPushMessage = std::string("Unable to parse texture: ") + stbi_failure_reason(); @@ -95,13 +95,12 @@ Texture* StbProvider::pushTexture(const uint8_t* data, size_t byteCount, } using InternalFormat = Texture::InternalFormat; - const FlagBits sRGB = FlagBits(Flags::sRGB); Texture* texture = Texture::Builder() .width(width) .height(height) .levels(0xff) - .format((flags & sRGB) ? InternalFormat::SRGB8_A8 : InternalFormat::RGBA8) + .format(any(flags & TextureFlags::sRGB) ? InternalFormat::SRGB8_A8 : InternalFormat::RGBA8) .build(*mEngine); if (texture == nullptr) {