gltfio: use BitmaskFlags for sRGB

This PR also contains a small change in ResourceLoader::createTextures
that will permit zero-instance assets (an upcoming gltfio feature).
This commit is contained in:
Philip Rideout
2022-09-12 12:27:01 -07:00
parent f772c92eed
commit 85fb4be37e
8 changed files with 46 additions and 46 deletions
+7 -3
View File
@@ -21,6 +21,7 @@
#include <stdint.h>
#include <utils/compiler.h>
#include <utils/BitmaskEnum.h>
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<filament::gltfio::TextureProvider::TextureFlags>
: public std::true_type {};
#endif // GLTFIO_TEXTUREPROVIDER_H
+15 -12
View File
@@ -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);
-6
View File
@@ -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;
+3 -2
View File
@@ -30,6 +30,7 @@
#include <filament/VertexBuffer.h>
#include <gltfio/MaterialProvider.h>
#include <gltfio/TextureProvider.h>
#include <math/mat4.h>
@@ -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<TextureSlot> bindings;
Texture* texture;
bool srgb;
TextureProvider::TextureFlags flags;
};
// Mapping from cgltf_texture to Texture* is required when creating new instances.
+4 -3
View File
@@ -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) {
+4 -4
View File
@@ -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.";
+10 -12
View File
@@ -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);
}
}
+3 -4
View File
@@ -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) {