From d740378277599a2ef082d5fcb604ea72d4b578e4 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 4 Mar 2021 00:59:42 -0800 Subject: [PATCH] More code size optimizations and bvecn fixes MaterialInstance: generate versions of setParameter() methods that are templated on the parameter sizeof(), which allows us to coalesce implementations, e.g. vec4 and vec4 are now the same. We make the compiler generate non-inline version of all these methods, the typed version just call through, taking advantage of the tail-call optimization in clang. MaterialParser: improve code to avoid calling multiple methods that all did more or less the same thing and were inlined. PostProcessManager: use a loop to initialize the materials ToneMapping: de-dup ACES implementation And other more minor optimizations. Fix alignment issues with setting booleans in UBOs --- filament/CMakeLists.txt | 1 + filament/include/filament/MaterialInstance.h | 15 +- filament/src/MaterialInstance.cpp | 304 +++++++++++------- filament/src/MaterialParser.cpp | 12 +- filament/src/PostProcessManager.cpp | 55 ++-- filament/src/ToneMapping.cpp | 252 +++++++++++++++ filament/src/ToneMapping.h | 225 +------------ filament/src/UniformBuffer.cpp | 71 ++++ filament/src/UniformBuffer.h | 92 +++--- filament/src/details/MaterialInstance.h | 50 +-- filament/src/fg2/DependencyGraph.cpp | 18 +- filament/src/fg2/details/DependencyGraph.h | 6 +- .../include/filaflat/ChunkContainer.h | 17 +- .../filaflat/include/filaflat/MaterialChunk.h | 1 + libs/filaflat/src/ChunkContainer.cpp | 2 + libs/filaflat/src/MaterialChunk.cpp | 2 + libs/utils/include/utils/Allocator.h | 9 +- 17 files changed, 656 insertions(+), 476 deletions(-) create mode 100644 filament/src/ToneMapping.cpp diff --git a/filament/CMakeLists.txt b/filament/CMakeLists.txt index 7b580611c4..25fb9f52f4 100644 --- a/filament/CMakeLists.txt +++ b/filament/CMakeLists.txt @@ -76,6 +76,7 @@ set(SRCS src/Stream.cpp src/SwapChain.cpp src/Texture.cpp + src/ToneMapping.cpp src/UniformBuffer.cpp src/VertexBuffer.cpp src/View.cpp diff --git a/filament/include/filament/MaterialInstance.h b/filament/include/filament/MaterialInstance.h index 2749f81e1f..addbd0b54d 100644 --- a/filament/include/filament/MaterialInstance.h +++ b/filament/include/filament/MaterialInstance.h @@ -40,13 +40,9 @@ public: template using is_supported_parameter_t = typename std::enable_if< - std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || @@ -56,8 +52,13 @@ public: std::is_same::value || std::is_same::value || std::is_same::value || - std::is_same::value || - std::is_same::value + std::is_same::value || + // these types are slower as they need a layout conversion + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value >::type; /** @@ -78,7 +79,7 @@ public: * @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled. */ template> - void setParameter(const char* name, T value) noexcept; + void setParameter(const char* name, T const& value) noexcept; /** * Set a uniform array by name diff --git a/filament/src/MaterialInstance.cpp b/filament/src/MaterialInstance.cpp index a5c402dfff..71f94d0d0c 100644 --- a/filament/src/MaterialInstance.cpp +++ b/filament/src/MaterialInstance.cpp @@ -28,8 +28,6 @@ #include -#include - using namespace filament::math; using namespace utils; @@ -37,6 +35,146 @@ namespace filament { using namespace backend; +// ------------------------------------------------------------------------------------------------ + +// This is the untyped/sized version of the setParameter: we end up here for e.g. vec4 and +// vec4. This must not be inlined (this is the whole point). +template +UTILS_NOINLINE +void FMaterialInstance::setParameterUntypedImpl(const char* name, const void* value) noexcept { + ssize_t offset = mMaterial->getUniformInterfaceBlock().getUniformOffset(name, 0); + if (UTILS_LIKELY(offset >= 0)) { + mUniforms.setUniformUntyped(size_t(offset), value); // handles specialization for mat3f + } +} + +// ------------------------------------------------------------------------------------------------ + +// this converts typed calls into the untyped-sized call. +template +UTILS_ALWAYS_INLINE +inline void FMaterialInstance::setParameterImpl(const char* name, T const& value) noexcept { + static_assert(!std::is_same_v); + setParameterUntypedImpl(name, &value); +} + +// specialization for mat3f +template<> +inline void FMaterialInstance::setParameterImpl(const char* name, mat3f const& value) noexcept { + ssize_t offset = mMaterial->getUniformInterfaceBlock().getUniformOffset(name, 0); + if (UTILS_LIKELY(offset >= 0)) { + mUniforms.setUniform(size_t(offset), value); + } +} + +// ------------------------------------------------------------------------------------------------ + +template +void MaterialInstance::setParameter(const char* name, T const& value) noexcept { + upcast(this)->setParameterImpl(name, value); +} + +template<> +UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, bool const& v) noexcept { + // this kills tail-call optimization + MaterialInstance::setParameter(name, (uint32_t)v); +} + +template<> +UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, bool2 const& v) noexcept { + // this kills tail-call optimization + MaterialInstance::setParameter(name, uint2(v)); +} + +template<> +UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, bool3 const& v) noexcept { + // this kills tail-call optimization + MaterialInstance::setParameter(name, uint3(v)); +} + +template<> +UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, bool4 const& v) noexcept { + // this kills tail-call optimization + MaterialInstance::setParameter(name, uint4(v)); +} + +// explicit template instantiation of our supported types +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, float const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, int32_t const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, uint32_t const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, int2 const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, int3 const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, int4 const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, uint2 const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, uint3 const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, uint4 const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, float2 const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, float3 const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, float4 const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, mat3f const& v) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, mat4f const& v) noexcept; + +// ------------------------------------------------------------------------------------------------ + +template +void MaterialInstance::setParameter(const char* name, const T* value, size_t count) noexcept { + upcast(this)->setParameterImpl(name, value, count); +} + +template<> +UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, const bool* v, size_t c) noexcept { + auto* p = new uint32_t[c]; + std::copy_n(v, c, p); + MaterialInstance::setParameter(name, p, c); + delete [] p; +} + +template<> +UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, const bool2* v, size_t c) noexcept { + auto* p = new uint2[c]; + std::copy_n(v, c, p); + MaterialInstance::setParameter(name, p, c); + delete [] p; +} + +template<> +UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, const bool3* v, size_t c) noexcept { + auto* p = new uint3[c]; + std::copy_n(v, c, p); + MaterialInstance::setParameter(name, p, c); + delete [] p; +} + +template<> +UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, const bool4* v, size_t c) noexcept { + auto* p = new uint4[c]; + std::copy_n(v, c, p); + MaterialInstance::setParameter(name, p, c); + delete [] p; +} + +template<> +UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, const mat3f* v, size_t c) noexcept { + // pretend each mat3 is an array of 3 float3 + MaterialInstance::setParameter(name, reinterpret_cast(v), c * 3); +} + +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const float *v, size_t c) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const int32_t *v, size_t c) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, const uint32_t *v, size_t c) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const int2 *v, size_t c) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const int3 *v, size_t c) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const int4 *v, size_t c) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const uint2 *v, size_t c) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const uint3 *v, size_t c) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const uint4 *v, size_t c) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const float2 *v, size_t c) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const float3 *v, size_t c) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const float4 *v, size_t c) noexcept; +template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const mat4f *v, size_t c) noexcept; + +// ------------------------------------------------------------------------------------------------ + FMaterialInstance::FMaterialInstance() noexcept = default; FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material, const char* name) : @@ -81,6 +219,7 @@ void FMaterialInstance::terminate(FEngine& engine) { driver.destroySamplerGroup(mSbHandle); } +UTILS_NOINLINE void FMaterialInstance::initialize(FMaterial const* material) { mMaterial = material; @@ -98,20 +237,16 @@ void FMaterialInstance::initialize(FMaterial const* material) { material->getId(), material->generateMaterialInstanceId()); if (material->getBlendingMode() == BlendingMode::MASKED) { - static_cast(this)->setParameter( - "_maskThreshold", material->getMaskThreshold()); + setMaskThreshold(material->getMaskThreshold()); } if (material->hasDoubleSidedCapability()) { - static_cast(this)->setParameter( - "_doubleSided", material->isDoubleSided()); + setDoubleSided(material->isDoubleSided()); } if (material->hasSpecularAntiAliasing()) { - static_cast(this)->setParameter( - "_specularAntiAliasingVariance", material->getSpecularAntiAliasingVariance()); - static_cast(this)->setParameter( - "_specularAntiAliasingThreshold", material->getSpecularAntiAliasingThreshold()); + setSpecularAntiAliasingVariance(material->getSpecularAntiAliasingVariance()); + setSpecularAntiAliasingThreshold(material->getSpecularAntiAliasingThreshold()); } } @@ -125,26 +260,25 @@ void FMaterialInstance::commitSlow(DriverApi& driver) const { } } -template -inline void FMaterialInstance::setParameter(const char* name, T value) noexcept { +// ------------------------------------------------------------------------------------------------ + +template +UTILS_NOINLINE +void FMaterialInstance::setParameterUntypedImpl(const char* name, const void* value, size_t count) noexcept { ssize_t offset = mMaterial->getUniformInterfaceBlock().getUniformOffset(name, 0); - if (offset >= 0) { - mUniforms.setUniform(size_t(offset), value); // handles specialization for mat3f + if (UTILS_LIKELY(offset >= 0)) { + mUniforms.setUniformArrayUntyped(size_t(offset), value, count); } } -template -inline void FMaterialInstance::setParameter(const char* name, const T* value, size_t count) noexcept { - ssize_t offset = mMaterial->getUniformInterfaceBlock().getUniformOffset(name, 0); - if (offset >= 0) { - mUniforms.setUniformArray(size_t(offset), value, count); - } +template +UTILS_ALWAYS_INLINE +inline void FMaterialInstance::setParameterImpl(const char* name, const T* value, size_t count) noexcept { + static_assert(!std::is_same_v); + setParameterUntypedImpl(name, value, count); } -void FMaterialInstance::setParameter(const char* name, - Texture const* texture, TextureSampler const& sampler) noexcept { - setParameter(name, upcast(texture)->getHwHandle(), sampler.getSamplerParams()); -} +// ------------------------------------------------------------------------------------------------ void FMaterialInstance::setParameter(const char* name, backend::Handle texture, backend::SamplerParams params) noexcept { @@ -152,8 +286,25 @@ void FMaterialInstance::setParameter(const char* name, mSamplers.setSampler(index, { texture, params }); } +void FMaterialInstance::setParameterImpl(const char* name, + Texture const* texture, TextureSampler const& sampler) noexcept { + setParameter(name, upcast(texture)->getHwHandle(), sampler.getSamplerParams()); +} + +void FMaterialInstance::setMaskThreshold(float threshold) noexcept { + setParameter("_maskThreshold", math::saturate(threshold)); +} + +void FMaterialInstance::setSpecularAntiAliasingVariance(float variance) noexcept { + setParameter("_specularAntiAliasingVariance", math::saturate(variance)); +} + +void FMaterialInstance::setSpecularAntiAliasingThreshold(float threshold) noexcept { + setParameter("_specularAntiAliasingThreshold", math::saturate(threshold * threshold)); +} + void FMaterialInstance::setDoubleSided(bool doubleSided) noexcept { - if (!mMaterial->hasDoubleSidedCapability()) { + if (UTILS_UNLIKELY(!mMaterial->hasDoubleSidedCapability())) { slog.w << "Parent material does not have double-sided capability." << io::endl; return; } @@ -163,18 +314,6 @@ void FMaterialInstance::setDoubleSided(bool doubleSided) noexcept { } } -void FMaterialInstance::setCullingMode(CullingMode culling) noexcept { - mCulling = culling; -} - -void FMaterialInstance::setColorWrite(bool enable) noexcept { - mColorWrite = enable; -} - -void FMaterialInstance::setDepthWrite(bool enable) noexcept { - mDepthWrite = enable; -} - void FMaterialInstance::setDepthCulling(bool enable) noexcept { mDepthFunc = enable ? RasterState::DepthFunc::GE : RasterState::DepthFunc::A; } @@ -189,44 +328,6 @@ const char* FMaterialInstance::getName() const noexcept { return mName.c_str(); } -// explicit template instantiation of our supported types -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, bool v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, float v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, int32_t v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter(const char* name, uint32_t v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, bool2 v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, bool3 v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, bool4 v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, int2 v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, int3 v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, int4 v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, uint2 v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, uint3 v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, uint4 v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, float2 v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, float3 v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, float4 v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, mat3f v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, mat4f v) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const bool *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const float *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const int32_t *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter(const char* name, const uint32_t *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const bool2 *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const bool3 *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const bool4 *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const int2 *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const int3 *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const int4 *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const uint2 *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const uint3 *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const uint4 *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const float2 *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const float3 *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const float4 *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const mat3f *v, size_t c) noexcept; -template UTILS_NOINLINE void FMaterialInstance::setParameter (const char* name, const mat4f *v, size_t c) noexcept; - Material const* MaterialInstance::getMaterial() const noexcept { return upcast(this)->getMaterial(); } @@ -235,65 +336,20 @@ const char* MaterialInstance::getName() const noexcept { return upcast(this)->getName(); } -template -void MaterialInstance::setParameter(const char* name, T value) noexcept { - upcast(this)->setParameter(name, value); -} +// ------------------------------------------------------------------------------------------------ -template -void MaterialInstance::setParameter(const char* name, const T* value, size_t count) noexcept { - upcast(this)->setParameter(name, value, count); -} - -// explicit template instantiation of our supported types -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, bool v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, float v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, int32_t v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, uint32_t v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, bool2 v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, bool3 v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, bool4 v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, int2 v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, int3 v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, int4 v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, uint2 v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, uint3 v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, uint4 v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, float2 v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, float3 v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, float4 v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, mat3f v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, mat4f v) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const bool *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const float *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const int32_t *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, const uint32_t *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const bool2 *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const bool3 *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const bool4 *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const int2 *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const int3 *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const int4 *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const uint2 *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const uint3 *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const uint4 *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const float2 *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const float3 *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const float4 *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const mat3f *v, size_t c) noexcept; -template UTILS_PUBLIC void MaterialInstance::setParameter (const char* name, const mat4f *v, size_t c) noexcept; void MaterialInstance::setParameter(const char* name, Texture const* texture, TextureSampler const& sampler) noexcept { - return upcast(this)->setParameter(name, texture, sampler); + return upcast(this)->setParameterImpl(name, texture, sampler); } void MaterialInstance::setParameter(const char* name, RgbType type, float3 color) noexcept { - upcast(this)->setParameter(name, Color::toLinear(type, color)); + upcast(this)->setParameterImpl(name, Color::toLinear(type, color)); } void MaterialInstance::setParameter(const char* name, RgbaType type, float4 color) noexcept { - upcast(this)->setParameter(name, Color::toLinear(type, color)); + upcast(this)->setParameterImpl(name, Color::toLinear(type, color)); } void MaterialInstance::setScissor(uint32_t left, uint32_t bottom, uint32_t width, diff --git a/filament/src/MaterialParser.cpp b/filament/src/MaterialParser.cpp index 15e24fe262..3339e19d80 100644 --- a/filament/src/MaterialParser.cpp +++ b/filament/src/MaterialParser.cpp @@ -69,11 +69,13 @@ MaterialParser::MaterialParserDetails::MaterialParserDetails(Backend backend, co } template -bool MaterialParser::MaterialParserDetails::getFromSimpleChunk(filamat::ChunkType type, T* value) const noexcept { - if (mChunkContainer.hasChunk(type)) { - Unflattener unflattener( - mChunkContainer.getChunkStart(type), - mChunkContainer.getChunkEnd(type)); +UTILS_NOINLINE +bool MaterialParser::MaterialParserDetails::getFromSimpleChunk( + filamat::ChunkType type, T* value) const noexcept { + ChunkContainer const& chunkContainer = mChunkContainer; + ChunkContainer::ChunkDesc const* pChunkDesc; + if (chunkContainer.hasChunk(type, &pChunkDesc)) { + Unflattener unflattener(pChunkDesc->start, pChunkDesc->start + pChunkDesc->size); return unflattener.read(value); } return false; diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index 334b69165c..0579a52e66 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -187,32 +187,45 @@ PostProcessManager::PostProcessMaterial& PostProcessManager::getPostProcessMater #define MATERIAL(n) MATERIALS_ ## n ## _DATA, MATERIALS_ ## n ## _SIZE +struct MaterialInfo { + utils::StaticString name; + uint8_t const* data; + int size; +}; + +static const MaterialInfo sMaterialList[] = { + { "sao", MATERIAL(SAO) }, + { "mipmapDepth", MATERIAL(MIPMAPDEPTH) }, + { "vsmMipmap", MATERIAL(VSMMIPMAP) }, + { "bilateralBlur", MATERIAL(BILATERALBLUR) }, + { "separableGaussianBlur", MATERIAL(SEPARABLEGAUSSIANBLUR) }, + { "bloomDownsample", MATERIAL(BLOOMDOWNSAMPLE) }, + { "bloomUpsample", MATERIAL(BLOOMUPSAMPLE) }, + { "blitLow", MATERIAL(BLITLOW) }, + { "blitMedium", MATERIAL(BLITMEDIUM) }, + { "blitHigh", MATERIAL(BLITHIGH) }, + { "colorGrading", MATERIAL(COLORGRADING) }, + { "colorGradingAsSubpass", MATERIAL(COLORGRADINGASSUBPASS) }, + { "fxaa", MATERIAL(FXAA) }, + { "taa", MATERIAL(TAA) }, + { "dofDownsample", MATERIAL(DOFDOWNSAMPLE) }, + { "dofMipmap", MATERIAL(DOFMIPMAP) }, + { "dofTiles", MATERIAL(DOFTILES) }, + { "dofDilate", MATERIAL(DOFDILATE) }, + { "dof", MATERIAL(DOF) }, + { "dofMedian", MATERIAL(DOFMEDIAN) }, + { "dofCombine", MATERIAL(DOFCOMBINE) }, +}; + void PostProcessManager::init() noexcept { auto& engine = mEngine; DriverApi& driver = engine.getDriverApi(); mDisableFeedbackLoops = !driver.areFeedbackLoopsSupported(); - registerPostProcessMaterial("sao", MATERIAL(SAO)); - registerPostProcessMaterial("mipmapDepth", MATERIAL(MIPMAPDEPTH)); - registerPostProcessMaterial("vsmMipmap", MATERIAL(VSMMIPMAP)); - registerPostProcessMaterial("bilateralBlur", MATERIAL(BILATERALBLUR)); - registerPostProcessMaterial("separableGaussianBlur", MATERIAL(SEPARABLEGAUSSIANBLUR)); - registerPostProcessMaterial("bloomDownsample", MATERIAL(BLOOMDOWNSAMPLE)); - registerPostProcessMaterial("bloomUpsample", MATERIAL(BLOOMUPSAMPLE)); - registerPostProcessMaterial("blitLow", MATERIAL(BLITLOW)); - registerPostProcessMaterial("blitMedium", MATERIAL(BLITMEDIUM)); - registerPostProcessMaterial("blitHigh", MATERIAL(BLITHIGH)); - registerPostProcessMaterial("colorGrading", MATERIAL(COLORGRADING)); - registerPostProcessMaterial("colorGradingAsSubpass", MATERIAL(COLORGRADINGASSUBPASS)); - registerPostProcessMaterial("fxaa", MATERIAL(FXAA)); - registerPostProcessMaterial("taa", MATERIAL(TAA)); - registerPostProcessMaterial("dofDownsample", MATERIAL(DOFDOWNSAMPLE)); - registerPostProcessMaterial("dofMipmap", MATERIAL(DOFMIPMAP)); - registerPostProcessMaterial("dofTiles", MATERIAL(DOFTILES)); - registerPostProcessMaterial("dofDilate", MATERIAL(DOFDILATE)); - registerPostProcessMaterial("dof", MATERIAL(DOF)); - registerPostProcessMaterial("dofMedian", MATERIAL(DOFMEDIAN)); - registerPostProcessMaterial("dofCombine", MATERIAL(DOFCOMBINE)); + #pragma nounroll + for (auto const& info : sMaterialList) { + registerPostProcessMaterial(info.name, info.data, info.size); + } // UBO storage size. // The effective kernel size is (kMaxPositiveKernelSize - 1) * 4 + 1. diff --git a/filament/src/ToneMapping.cpp b/filament/src/ToneMapping.cpp new file mode 100644 index 0000000000..d248b546af --- /dev/null +++ b/filament/src/ToneMapping.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ToneMapping.h" + +namespace filament { +namespace aces { + +inline float rgb_2_saturation(float3 rgb) { + // Input: ACES + // Output: OCES + constexpr float TINY = 1e-5f; + float mi = min(rgb); + float ma = max(rgb); + return (max(ma, TINY) - max(mi, TINY)) / max(ma, 1e-2f); +} + +inline float rgb_2_yc(float3 rgb) { + constexpr float ycRadiusWeight = 1.75f; + + // Converts RGB to a luminance proxy, here called YC + // YC is ~ Y + K * Chroma + // Constant YC is a cone-shaped surface in RGB space, with the tip on the + // neutral axis, towards white. + // YC is normalized: RGB 1 1 1 maps to YC = 1 + // + // ycRadiusWeight defaults to 1.75, although can be overridden in function + // call to rgb_2_yc + // ycRadiusWeight = 1 -> YC for pure cyan, magenta, yellow == YC for neutral + // of same value + // ycRadiusWeight = 2 -> YC for pure red, green, blue == YC for neutral of + // same value. + + float r = rgb.r; + float g = rgb.g; + float b = rgb.b; + + float chroma = std::sqrt(b * (b - g) + g * (g - r) + r * (r - b)); + + return (b + g + r + ycRadiusWeight * chroma) / 3.0f; +} + +inline float sigmoid_shaper(float x) { + // Sigmoid function in the range 0 to 1 spanning -2 to +2. + float t = max(1.0f - std::abs(x / 2.0f), 0.0f); + float y = 1.0f + sign(x) * (1.0f - t * t); + return y / 2.0f; +} + +inline float glow_fwd(float ycIn, float glowGainIn, float glowMid) { + float glowGainOut; + + if (ycIn <= 2.0f / 3.0f * glowMid) { + glowGainOut = glowGainIn; + } else if ( ycIn >= 2.0f * glowMid) { + glowGainOut = 0.0f; + } else { + glowGainOut = glowGainIn * (glowMid / ycIn - 1.0f / 2.0f); + } + + return glowGainOut; +} + +inline float rgb_2_hue(float3 rgb) { + // Returns a geometric hue angle in degrees (0-360) based on RGB values. + // For neutral colors, hue is undefined and the function will return a quiet NaN value. + float hue = 0.0f; + // RGB triplets where RGB are equal have an undefined hue + if (!(rgb.x == rgb.y && rgb.y == rgb.z)) { + hue = f::RAD_TO_DEG * std::atan2( + std::sqrt(3.0f) * (rgb.y - rgb.z), + 2.0f * rgb.x - rgb.y - rgb.z); + } + return (hue < 0.0f) ? hue + 360.0f : hue; +} + +inline float center_hue(float hue, float centerH) { + float hueCentered = hue - centerH; + if (hueCentered < -180.0f) { + hueCentered = hueCentered + 360.0f; + } else if (hueCentered > 180.0f) { + hueCentered = hueCentered - 360.0f; + } + return hueCentered; +} + +inline float3 darkSurround_to_dimSurround(float3 linearCV) { + constexpr float DIM_SURROUND_GAMMA = 0.9811f; + + float3 XYZ = AP1_to_XYZ * linearCV; + float3 xyY = XYZ_to_xyY(XYZ); + + xyY.z = clamp(xyY.z, 0.0f, (float)std::numeric_limits::max()); + xyY.z = std::pow(xyY.z, DIM_SURROUND_GAMMA); + + XYZ = xyY_to_XYZ(xyY); + return XYZ_to_AP1 * XYZ; +} + +float3 ACES(float3 color, float brightness) noexcept { + // Some bits were removed to adapt to our desired output + // Input: ACEScg (AP1) + // Output: ACEScg (AP1) + + // "Glow" module constants + constexpr float RRT_GLOW_GAIN = 0.05f; + constexpr float RRT_GLOW_MID = 0.08f; + + // Red modifier constants + constexpr float RRT_RED_SCALE = 0.82f; + constexpr float RRT_RED_PIVOT = 0.03f; + constexpr float RRT_RED_HUE = 0.0f; + constexpr float RRT_RED_WIDTH = 135.0f; + + // Desaturation constants + constexpr float RRT_SAT_FACTOR = 0.96f; + constexpr float ODT_SAT_FACTOR = 0.93f; + + float3 ap0 = AP1_to_AP0 * color; + + // Glow module + float saturation = rgb_2_saturation(ap0); + float ycIn = rgb_2_yc(ap0); + float s = sigmoid_shaper((saturation - 0.4f) / 0.2f); + float addedGlow = 1.0f + glow_fwd(ycIn, RRT_GLOW_GAIN * s, RRT_GLOW_MID); + ap0 *= addedGlow; + + // Red modifier + float hue = rgb_2_hue(ap0); + float centeredHue = center_hue(hue, RRT_RED_HUE); + float hueWeight = smoothstep(0.0f, 1.0f, 1.0f - std::abs(2.0f * centeredHue / RRT_RED_WIDTH)); + hueWeight *= hueWeight; + + ap0.r += hueWeight * saturation * (RRT_RED_PIVOT - ap0.r) * (1.0f - RRT_RED_SCALE); + + // ACES to RGB rendering space + float3 ap1 = clamp(AP0_to_AP1 * ap0, 0.0f, (float) std::numeric_limits::max()); + + // Global desaturation + ap1 = mix(float3(dot(ap1, LUMA_AP1)), ap1, RRT_SAT_FACTOR); + + // NOTE: This is specific to Filament and added only to match ACES to our legacy tone mapper + // which was a fit of ACES in Rec.709 but with a brightness boost. + ap1 *= brightness; + + // Fitting of RRT + ODT (RGB monitor 100 nits dim) from: + // https://github.com/colour-science/colour-unity/blob/master/Assets/Colour/Notebooks/CIECAM02_Unity.ipynb + constexpr float a = 2.785085f; + constexpr float b = 0.107772f; + constexpr float c = 2.936045f; + constexpr float d = 0.887122f; + constexpr float e = 0.806889f; + float3 rgbPost = (ap1 * (a * ap1 + b)) / (ap1 * (c * ap1 + d) + e); + + // Apply gamma adjustment to compensate for dim surround + float3 linearCV = darkSurround_to_dimSurround(rgbPost); + + // Apply desaturation to compensate for luminance difference + linearCV = mix(float3(dot(linearCV, LUMA_AP1)), linearCV, ODT_SAT_FACTOR); + + return linearCV; +} + +} // namespace aces + + +namespace tonemap { + +float3 ACES(float3 x) noexcept { + return aces::ACES(x, 1.0f); +} + +float3 ACES_Legacy(float3 x) noexcept { + return aces::ACES(x, 1.0f / 0.6f); +} + +float3 Uchimura(float3 x) noexcept { + // Uchimura 2017, "HDR theory and practice" + // Math: https://www.desmos.com/calculator/gslcdxvipg + // Source: https://www.slideshare.net/nikuque/hdr-theory-and-practicce-jp + + constexpr float P = 1.0; // max display brightness + constexpr float a = 1.0; // contrast + constexpr float m = 0.22; // linear section start + constexpr float l = 0.4; // linear section length + constexpr float c = 1.33; // black + constexpr float b = 0.0; // pedestal + + constexpr float l0 = ((P - m) * l) / a; + constexpr float S0 = m + l0; + constexpr float S1 = m + a * l0; + constexpr float C2 = (a * P) / (P - S1); + constexpr float CP = -C2 / P; + + float3 w0 = 1.0f - smoothstep(0.0f, m, x); + float3 w2 = step(m + l0, x); + float3 w1 = 1.0f - w0 - w2; + + float3 T = m * pow(x / m, c) + b; + float3 S = P - (P - S1) * exp(CP * (x - S0)); + float3 L = m + a * (x - m); + + return T * w0 + L * w1 + S * w2; +} + +float3 DisplayRange(float3 x) noexcept { + // 16 debug colors + 1 duplicated at the end for easy indexing + + constexpr float3 debugColors[17] = { + {0.0, 0.0, 0.0}, // black + {0.0, 0.0, 0.1647}, // darkest blue + {0.0, 0.0, 0.3647}, // darker blue + {0.0, 0.0, 0.6647}, // dark blue + {0.0, 0.0, 0.9647}, // blue + {0.0, 0.9255, 0.9255}, // cyan + {0.0, 0.5647, 0.0}, // dark green + {0.0, 0.7843, 0.0}, // green + {1.0, 1.0, 0.0}, // yellow + {0.90588, 0.75294, 0.0}, // yellow-orange + {1.0, 0.5647, 0.0}, // orange + {1.0, 0.0, 0.0}, // bright red + {0.8392, 0.0, 0.0}, // red + {1.0, 0.0, 1.0}, // magenta + {0.6, 0.3333, 0.7882}, // purple + {1.0, 1.0, 1.0}, // white + {1.0, 1.0, 1.0} // white + }; + + // The 5th color in the array (cyan) represents middle gray (18%) + // Every stop above or below middle gray causes a color shift + float v = log2(dot(x, LUMA_REC709) / 0.18f); + v = clamp(v + 5.0f, 0.0f, 15.0f); + + size_t index = size_t(v); + return mix(debugColors[index], debugColors[index + 1], saturate(v - float(index))); +} + +} // namespace tonemap +} // namespace filament diff --git a/filament/src/ToneMapping.h b/filament/src/ToneMapping.h index a66fa920e1..ffe653f6f9 100644 --- a/filament/src/ToneMapping.h +++ b/filament/src/ToneMapping.h @@ -35,161 +35,7 @@ using namespace math; namespace aces { -inline float rgb_2_saturation(float3 rgb) { - // Input: ACES - // Output: OCES - constexpr float TINY = 1e-5f; - float mi = min(rgb); - float ma = max(rgb); - return (max(ma, TINY) - max(mi, TINY)) / max(ma, 1e-2f); -} - -inline float rgb_2_yc(float3 rgb) { - constexpr float ycRadiusWeight = 1.75f; - - // Converts RGB to a luminance proxy, here called YC - // YC is ~ Y + K * Chroma - // Constant YC is a cone-shaped surface in RGB space, with the tip on the - // neutral axis, towards white. - // YC is normalized: RGB 1 1 1 maps to YC = 1 - // - // ycRadiusWeight defaults to 1.75, although can be overridden in function - // call to rgb_2_yc - // ycRadiusWeight = 1 -> YC for pure cyan, magenta, yellow == YC for neutral - // of same value - // ycRadiusWeight = 2 -> YC for pure red, green, blue == YC for neutral of - // same value. - - float r = rgb.r; - float g = rgb.g; - float b = rgb.b; - - float chroma = std::sqrt(b * (b - g) + g * (g - r) + r * (r - b)); - - return (b + g + r + ycRadiusWeight * chroma) / 3.0f; -} - -inline float sigmoid_shaper(float x) { - // Sigmoid function in the range 0 to 1 spanning -2 to +2. - float t = max(1.0f - std::abs(x / 2.0f), 0.0f); - float y = 1.0f + sign(x) * (1.0f - t * t); - return y / 2.0f; -} - -inline float glow_fwd(float ycIn, float glowGainIn, float glowMid) { - float glowGainOut; - - if (ycIn <= 2.0f / 3.0f * glowMid) { - glowGainOut = glowGainIn; - } else if ( ycIn >= 2.0f * glowMid) { - glowGainOut = 0.0f; - } else { - glowGainOut = glowGainIn * (glowMid / ycIn - 1.0f / 2.0f); - } - - return glowGainOut; -} - -inline float rgb_2_hue(float3 rgb) { - // Returns a geometric hue angle in degrees (0-360) based on RGB values. - // For neutral colors, hue is undefined and the function will return a quiet NaN value. - float hue = 0.0f; - // RGB triplets where RGB are equal have an undefined hue - if (!(rgb.x == rgb.y && rgb.y == rgb.z)) { - hue = f::RAD_TO_DEG * std::atan2( - std::sqrt(3.0f) * (rgb.y - rgb.z), - 2.0f * rgb.x - rgb.y - rgb.z); - } - return (hue < 0.0f) ? hue + 360.0f : hue; -} - -inline float center_hue(float hue, float centerH) { - float hueCentered = hue - centerH; - if (hueCentered < -180.0f) { - hueCentered = hueCentered + 360.0f; - } else if (hueCentered > 180.0f) { - hueCentered = hueCentered - 360.0f; - } - return hueCentered; -} - -inline float3 darkSurround_to_dimSurround(float3 linearCV) { - constexpr float DIM_SURROUND_GAMMA = 0.9811f; - - float3 XYZ = AP1_to_XYZ * linearCV; - float3 xyY = XYZ_to_xyY(XYZ); - - xyY.z = clamp(xyY.z, 0.0f, (float)std::numeric_limits::max()); - xyY.z = std::pow(xyY.z, DIM_SURROUND_GAMMA); - - XYZ = xyY_to_XYZ(xyY); - return XYZ_to_AP1 * XYZ; -} - -UTILS_ALWAYS_INLINE -inline float3 ACES(float3 color, float brightness) { - // Some bits were removed to adapt to our desired output - // Input: ACEScg (AP1) - // Output: ACEScg (AP1) - - // "Glow" module constants - constexpr float RRT_GLOW_GAIN = 0.05f; - constexpr float RRT_GLOW_MID = 0.08f; - - // Red modifier constants - constexpr float RRT_RED_SCALE = 0.82f; - constexpr float RRT_RED_PIVOT = 0.03f; - constexpr float RRT_RED_HUE = 0.0f; - constexpr float RRT_RED_WIDTH = 135.0f; - - // Desaturation constants - constexpr float RRT_SAT_FACTOR = 0.96f; - constexpr float ODT_SAT_FACTOR = 0.93f; - - float3 ap0 = AP1_to_AP0 * color; - - // Glow module - float saturation = rgb_2_saturation(ap0); - float ycIn = rgb_2_yc(ap0); - float s = sigmoid_shaper((saturation - 0.4f) / 0.2f); - float addedGlow = 1.0f + glow_fwd(ycIn, RRT_GLOW_GAIN * s, RRT_GLOW_MID); - ap0 *= addedGlow; - - // Red modifier - float hue = rgb_2_hue(ap0); - float centeredHue = center_hue(hue, RRT_RED_HUE); - float hueWeight = smoothstep(0.0f, 1.0f, 1.0f - std::abs(2.0f * centeredHue / RRT_RED_WIDTH)); - hueWeight *= hueWeight; - - ap0.r += hueWeight * saturation * (RRT_RED_PIVOT - ap0.r) * (1.0f - RRT_RED_SCALE); - - // ACES to RGB rendering space - float3 ap1 = clamp(AP0_to_AP1 * ap0, 0.0f, (float) std::numeric_limits::max()); - - // Global desaturation - ap1 = mix(float3(dot(ap1, LUMA_AP1)), ap1, RRT_SAT_FACTOR); - - // NOTE: This is specific to Filament and added only to match ACES to our legacy tone mapper - // which was a fit of ACES in Rec.709 but with a brightness boost. - ap1 *= brightness; - - // Fitting of RRT + ODT (RGB monitor 100 nits dim) from: - // https://github.com/colour-science/colour-unity/blob/master/Assets/Colour/Notebooks/CIECAM02_Unity.ipynb - constexpr float a = 2.785085f; - constexpr float b = 0.107772f; - constexpr float c = 2.936045f; - constexpr float d = 0.887122f; - constexpr float e = 0.806889f; - float3 rgbPost = (ap1 * (a * ap1 + b)) / (ap1 * (c * ap1 + d) + e); - - // Apply gamma adjustment to compensate for dim surround - float3 linearCV = darkSurround_to_dimSurround(rgbPost); - - // Apply desaturation to compensate for luminance difference - linearCV = mix(float3(dot(linearCV, LUMA_AP1)), linearCV, ODT_SAT_FACTOR); - - return linearCV; -} +float3 ACES(float3 color, float brightness) noexcept; } // namespace aces @@ -217,42 +63,11 @@ constexpr float3 Filmic(float3 x) noexcept { return (x * (a * x + b)) / (x * (c * x + d) + e); } -float3 ACES(float3 x) noexcept { - return aces::ACES(x, 1.0f); -} +float3 ACES(float3 x) noexcept; -float3 ACES_Legacy(float3 x) noexcept { - return aces::ACES(x, 1.0f / 0.6f); -} +float3 ACES_Legacy(float3 x) noexcept; -float3 Uchimura(float3 x) { - // Uchimura 2017, "HDR theory and practice" - // Math: https://www.desmos.com/calculator/gslcdxvipg - // Source: https://www.slideshare.net/nikuque/hdr-theory-and-practicce-jp - - constexpr float P = 1.0; // max display brightness - constexpr float a = 1.0; // contrast - constexpr float m = 0.22; // linear section start - constexpr float l = 0.4; // linear section length - constexpr float c = 1.33; // black - constexpr float b = 0.0; // pedestal - - constexpr float l0 = ((P - m) * l) / a; - constexpr float S0 = m + l0; - constexpr float S1 = m + a * l0; - constexpr float C2 = (a * P) / (P - S1); - constexpr float CP = -C2 / P; - - float3 w0 = 1.0f - smoothstep(0.0f, m, x); - float3 w2 = step(m + l0, x); - float3 w1 = 1.0f - w0 - w2; - - float3 T = m * pow(x / m, c) + b; - float3 S = P - (P - S1) * exp(CP * (x - S0)); - float3 L = m + a * (x - m); - - return T * w0 + L * w1 + S * w2; -} +float3 Uchimura(float3 x) noexcept; /** * Converts the input HDR RGB color into one of 16 debug colors that represent @@ -279,37 +94,7 @@ float3 Uchimura(float3 x) { * +9EV - purple * +10EV - white */ -float3 DisplayRange(float3 x) noexcept { - // 16 debug colors + 1 duplicated at the end for easy indexing - - constexpr float3 debugColors[17] = { - {0.0, 0.0, 0.0}, // black - {0.0, 0.0, 0.1647}, // darkest blue - {0.0, 0.0, 0.3647}, // darker blue - {0.0, 0.0, 0.6647}, // dark blue - {0.0, 0.0, 0.9647}, // blue - {0.0, 0.9255, 0.9255}, // cyan - {0.0, 0.5647, 0.0}, // dark green - {0.0, 0.7843, 0.0}, // green - {1.0, 1.0, 0.0}, // yellow - {0.90588, 0.75294, 0.0}, // yellow-orange - {1.0, 0.5647, 0.0}, // orange - {1.0, 0.0, 0.0}, // bright red - {0.8392, 0.0, 0.0}, // red - {1.0, 0.0, 1.0}, // magenta - {0.6, 0.3333, 0.7882}, // purple - {1.0, 1.0, 1.0}, // white - {1.0, 1.0, 1.0} // white - }; - - // The 5th color in the array (cyan) represents middle gray (18%) - // Every stop above or below middle gray causes a color shift - float v = log2(dot(x, LUMA_REC709) / 0.18f); - v = clamp(v + 5.0f, 0.0f, 15.0f); - - size_t index = size_t(v); - return mix(debugColors[index], debugColors[index + 1], saturate(v - float(index))); -} +float3 DisplayRange(float3 x) noexcept; } // namespace tonemap diff --git a/filament/src/UniformBuffer.cpp b/filament/src/UniformBuffer.cpp index 94c86117c1..acbce78bf0 100644 --- a/filament/src/UniformBuffer.cpp +++ b/filament/src/UniformBuffer.cpp @@ -90,6 +90,77 @@ void UniformBuffer::free(void* addr, size_t) noexcept { ::free(addr); } +// ------------------------------------------------------------------------------------------------ + +template +void UniformBuffer::setUniformUntyped(size_t offset, void const* UTILS_RESTRICT v) noexcept{ + setUniformUntyped(invalidateUniforms(offset, Size), 0ul, v); +} + +template +void UniformBuffer::setUniformUntyped<4ul>(size_t offset, void const* UTILS_RESTRICT v) noexcept; +template +void UniformBuffer::setUniformUntyped<8ul>(size_t offset, void const* UTILS_RESTRICT v) noexcept; +template +void UniformBuffer::setUniformUntyped<12ul>(size_t offset, void const* UTILS_RESTRICT v) noexcept; +template +void UniformBuffer::setUniformUntyped<16ul>(size_t offset, void const* UTILS_RESTRICT v) noexcept; +template +void UniformBuffer::setUniformUntyped<64ul>(size_t offset, void const* UTILS_RESTRICT v) noexcept; + +template +void UniformBuffer::setUniformArrayUntyped(size_t offset, void const* UTILS_RESTRICT begin, size_t count) noexcept { + constexpr size_t stride = (Size + 0xFu) & ~0xFu; + size_t arraySize = stride * count - stride + Size; + void* UTILS_RESTRICT p = invalidateUniforms(offset, arraySize); + for (size_t i = 0; i < count; i++) { + setUniformUntyped(p, 0ul, static_cast(begin) + i * Size); + p = utils::pointermath::add(p, stride); + } +} + +template +void UniformBuffer::setUniformArrayUntyped<4ul>(size_t offset, void const* UTILS_RESTRICT begin, size_t count) noexcept; +template +void UniformBuffer::setUniformArrayUntyped<8ul>(size_t offset, void const* UTILS_RESTRICT begin, size_t count) noexcept; +template +void UniformBuffer::setUniformArrayUntyped<12ul>(size_t offset, void const* UTILS_RESTRICT begin, size_t count) noexcept; +template +void UniformBuffer::setUniformArrayUntyped<16ul>(size_t offset, void const* UTILS_RESTRICT begin, size_t count) noexcept; +template +void UniformBuffer::setUniformArrayUntyped<64ul>(size_t offset, void const* UTILS_RESTRICT begin, size_t count) noexcept; + +// specialization for mat3f (which has a different alignment, see std140 layout rules) +template<> +UTILS_NOINLINE +void UniformBuffer::setUniform(void* addr, size_t offset, const math::mat3f& v) noexcept { + struct mat43 { + float v[3][4]; + }; + + addr = static_cast(addr) + offset; + mat43& temp = *static_cast(addr); + + temp.v[0][0] = v[0][0]; + temp.v[0][1] = v[0][1]; + temp.v[0][2] = v[0][2]; + + temp.v[1][0] = v[1][0]; + temp.v[1][1] = v[1][1]; + temp.v[1][2] = v[1][2]; + + temp.v[2][0] = v[2][0]; + temp.v[2][1] = v[2][1]; + temp.v[2][2] = v[2][2]; + + // don't store anything in temp.v[][3] because there could be uniforms packed there +} + +template<> +void UniformBuffer::setUniform(size_t offset, const math::mat3f& v) noexcept { + setUniform(invalidateUniforms(offset, sizeof(v)), 0, v); +} + #if !defined(NDEBUG) utils::io::ostream& operator<<(utils::io::ostream& out, const UniformBuffer& rhs) { diff --git a/filament/src/UniformBuffer.h b/filament/src/UniformBuffer.h index 3e057cd0ad..f13311ba65 100644 --- a/filament/src/UniformBuffer.h +++ b/filament/src/UniformBuffer.h @@ -32,6 +32,7 @@ #include #include +#include namespace filament { @@ -94,17 +95,15 @@ public: * ----------------------------------------------- */ + // Note: we purposedly not include types that require conversion here + // (e.g. bool and bool vectors) template struct is_supported_type { using type = typename std::enable_if< - std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || @@ -132,34 +131,32 @@ public: // a x x x b x x x c // // The "x" symbols represent dummy words. - template ::type> + template::type> + UTILS_ALWAYS_INLINE void setUniformArray(size_t offset, T const* UTILS_RESTRICT begin, size_t count) noexcept { - constexpr size_t stride = (sizeof(T) + 0xFu) & ~0xFu; - size_t arraySize = stride * count - stride + sizeof(T); - T* UTILS_RESTRICT p = static_cast(invalidateUniforms(offset, arraySize)); - for (size_t i = 0; i < count; i++) { - *p = begin[i]; - p = utils::pointermath::add(p, stride); - } + static_assert(!std::is_same_v); + setUniformArrayUntyped(offset, begin, count); } // (see specialization for mat3f below) - template ::type> - static void setUniform(void* addr, size_t offset, const T& v) noexcept { - addr = static_cast(addr) + offset; - T* p = static_cast(addr); - *p = v; + template::type> + UTILS_ALWAYS_INLINE + static inline void setUniform(void* addr, size_t offset, const T& v) noexcept { + static_assert(!std::is_same_v); + setUniformUntyped(addr, offset, &v); } - // set uniform of known types to the proper offset (e.g.: use offsetof()) - template ::type> - void setUniform(size_t offset, const T& v) noexcept { - setUniform(invalidateUniforms(offset, sizeof(T)), 0, v); + template::type> + UTILS_ALWAYS_INLINE + inline void setUniform(size_t offset, const T& v) noexcept { + static_assert(!std::is_same_v); + setUniformUntyped(offset, &v); } // get uniform of known types from the proper offset (e.g.: use offsetof()) template::type> T getUniform(size_t offset) const noexcept { + static_assert(!std::is_same_v); return *reinterpret_cast(static_cast(mBuffer) + offset); } @@ -175,11 +172,18 @@ public: backend::BufferDescriptor p; p.size = size; p.buffer = driver.allocate(p.size); // TODO: use out-of-line buffer if too large - memcpy(p.buffer, static_cast(getBuffer()) + offset, p.size); + memcpy(p.buffer, static_cast(getBuffer()) + offset, p.size); // inlined clean(); return p; } + // set uniform of known types to the proper offset (e.g.: use offsetof()) + template + void setUniformUntyped(size_t offset, void const* UTILS_RESTRICT v) noexcept; + + template + void setUniformArrayUntyped(size_t offset, void const* UTILS_RESTRICT begin, size_t count) noexcept; + private: #if !defined(NDEBUG) friend utils::io::ostream& operator<<(utils::io::ostream& out, const UniformBuffer& rhs); @@ -187,9 +191,16 @@ private: static void* alloc(size_t size) noexcept; static void free(void* addr, size_t size) noexcept; + template = true> + UTILS_ALWAYS_INLINE + static void setUniformUntyped(void* addr, size_t offset, void const* v) noexcept { + memcpy(static_cast(addr) + offset, v, Size); // inlined + } + inline bool isLocalStorage() const noexcept { return mBuffer == mStorage; } - // TODO: we need a better to calculate this local storage. + // TODO: we need a better way to calculate this local storage. // Probably the better thing to do would be to use a special allocator. // Local storage is limited by the total size of a handle (128 byte for GL) char mStorage[96]; @@ -200,28 +211,16 @@ private: // specialization for mat3f (which has a different alignment, see std140 layout rules) template<> -inline void UniformBuffer::setUniform(void* addr, size_t offset, const math::mat3f& v) noexcept { - struct mat43 { - float v[3][4]; - }; +void UniformBuffer::setUniform(void* addr, size_t offset, const math::mat3f& v) noexcept; - addr = static_cast(addr) + offset; - mat43& temp = *static_cast(addr); +template<> +void UniformBuffer::setUniform(size_t offset, const math::mat3f& v) noexcept; - temp.v[0][0] = v[0][0]; - temp.v[0][1] = v[0][1]; - temp.v[0][2] = v[0][2]; - temp.v[0][3] = 0; // not needed, but doesn't cost anything - - temp.v[1][0] = v[1][0]; - temp.v[1][1] = v[1][1]; - temp.v[1][2] = v[1][2]; - temp.v[1][3] = 0; // not needed, but doesn't cost anything - - temp.v[2][0] = v[2][0]; - temp.v[2][1] = v[2][1]; - temp.v[2][2] = v[2][2]; - temp.v[2][3] = 0; // not needed, but doesn't cost anything +template<> +inline void UniformBuffer::setUniformArray( + size_t offset, math::mat3f const* UTILS_RESTRICT begin, size_t count) noexcept { + // pretend each mat3 is an array of 3 float3 + setUniformArray(offset, reinterpret_cast(begin), count * 3); } template<> @@ -231,13 +230,6 @@ inline math::mat3f UniformBuffer::getUniform(size_t offset) const noexcept { return { p[0].xyz, p[1].xyz, p[2].xyz }; } -template<> -inline void UniformBuffer::setUniformArray( - size_t offset, math::mat3f const* UTILS_RESTRICT begin, size_t count) noexcept { - // pretend each mat3 is an array of 3 float3 - setUniformArray(offset, reinterpret_cast(begin), count * 3); -} - } // namespace filament #endif // TNT_FILAMENT_DRIVER_UNIFORMBUFFER_H diff --git a/filament/src/details/MaterialInstance.h b/filament/src/details/MaterialInstance.h index e2ce38bbf2..617ec94b02 100644 --- a/filament/src/details/MaterialInstance.h +++ b/filament/src/details/MaterialInstance.h @@ -60,18 +60,6 @@ public: } } - template > - void setParameter(const char* name, T value) noexcept; - - template > - void setParameter(const char* name, const T* value, size_t count) noexcept; - - void setParameter(const char* name, - Texture const* texture, TextureSampler const& sampler) noexcept; - - void setParameter(const char* name, - backend::Handle texture, backend::SamplerParams params) noexcept; - FMaterial const* getMaterial() const noexcept { return mMaterial; } uint64_t getSortingKey() const noexcept { return mMaterialSortingKey; } @@ -110,34 +98,48 @@ public: backend::PolygonOffset getPolygonOffset() const noexcept { return mPolygonOffset; } - void setMaskThreshold(float threshold) noexcept { - setParameter("_maskThreshold", math::saturate(threshold)); - } + void setMaskThreshold(float threshold) noexcept; - void setSpecularAntiAliasingVariance(float variance) noexcept { - setParameter("_specularAntiAliasingVariance", math::saturate(variance)); - } + void setSpecularAntiAliasingVariance(float variance) noexcept; - void setSpecularAntiAliasingThreshold(float threshold) noexcept { - setParameter("_specularAntiAliasingThreshold", math::saturate(threshold * threshold)); - } + void setSpecularAntiAliasingThreshold(float threshold) noexcept; void setDoubleSided(bool doubleSided) noexcept; - void setCullingMode(CullingMode culling) noexcept; + void setCullingMode(CullingMode culling) noexcept { mCulling = culling; } - void setColorWrite(bool enable) noexcept; + void setColorWrite(bool enable) noexcept { mColorWrite = enable; } - void setDepthWrite(bool enable) noexcept; + void setDepthWrite(bool enable) noexcept { mDepthWrite = enable; } void setDepthCulling(bool enable) noexcept; const char* getName() const noexcept; + void setParameter(const char* name, + backend::Handle texture, backend::SamplerParams params) noexcept; + + using MaterialInstance::setParameter; + private: friend class FMaterial; friend class MaterialInstance; + template + void setParameterUntypedImpl(const char* name, const void* value) noexcept; + + template + void setParameterUntypedImpl(const char* name, const void* value, size_t count) noexcept; + + template + void setParameterImpl(const char* name, T const& value) noexcept; + + template + void setParameterImpl(const char* name, const T* value, size_t count) noexcept; + + void setParameterImpl(const char* name, + Texture const* texture, TextureSampler const& sampler) noexcept; + FMaterialInstance() noexcept; void initDefaultInstance(FEngine& engine, FMaterial const* material); void initialize(FMaterial const* material); diff --git a/filament/src/fg2/DependencyGraph.cpp b/filament/src/fg2/DependencyGraph.cpp index 012664d9d5..66f3cc0c1e 100644 --- a/filament/src/fg2/DependencyGraph.cpp +++ b/filament/src/fg2/DependencyGraph.cpp @@ -63,8 +63,9 @@ DependencyGraph::EdgeContainer DependencyGraph::getIncomingEdges( // TODO: we might need something more efficient EdgeContainer result; result.reserve(mEdges.size()); + NodeID const nodeId = node->getId(); for (auto* edge : mEdges) { - if (edge->to == node->getId()) { + if (edge->to == nodeId) { result.push_back(edge); } } @@ -76,8 +77,9 @@ DependencyGraph::EdgeContainer DependencyGraph::getOutgoingEdges( // TODO: we might need something more efficient EdgeContainer result; result.reserve(mEdges.size()); + NodeID const nodeId = node->getId(); for (auto* edge : mEdges) { - if (edge->from == node->getId()) { + if (edge->from == nodeId) { result.push_back(edge); } } @@ -235,23 +237,11 @@ uint32_t DependencyGraph::Node::getRefCount() const noexcept { return (mRefCount & TARGET) ? 1u : mRefCount; } -uint32_t DependencyGraph::Node::getId() const noexcept { - return mId; -} - -bool DependencyGraph::Node::isCulled() const noexcept { - return mRefCount == 0; -} - void DependencyGraph::Node::makeTarget() noexcept { assert_invariant(mRefCount == 0 || mRefCount == TARGET); mRefCount = TARGET; } -bool DependencyGraph::Node::isTarget() const noexcept { - return mRefCount >= TARGET; -} - char const* DependencyGraph::Node::getName() const noexcept { return "unknown"; } diff --git a/filament/src/fg2/details/DependencyGraph.h b/filament/src/fg2/details/DependencyGraph.h index 742230d110..8aa0f58f41 100644 --- a/filament/src/fg2/details/DependencyGraph.h +++ b/filament/src/fg2/details/DependencyGraph.h @@ -86,20 +86,20 @@ public: virtual ~Node() noexcept = default; //! returns a unique id for this node - NodeID getId() const noexcept; + NodeID getId() const noexcept { return mId; } /** Prevents this node from being culled. Must be called before culling. */ void makeTarget() noexcept; /** Returns true if this Node is a target */ - bool isTarget() const noexcept; + bool isTarget() const noexcept { return mRefCount >= TARGET; } /** * Returns whether this node was culled. * This is only valid after DependencyGraph::cull() has been called. * @return true if the node has been culled, false otherwise. */ - bool isCulled() const noexcept; + bool isCulled() const noexcept { return mRefCount == 0; } /** * return the reference count of this node. That is how many other nodes have links to us. diff --git a/libs/filaflat/include/filaflat/ChunkContainer.h b/libs/filaflat/include/filaflat/ChunkContainer.h index f0f6d39d25..93a0020b14 100644 --- a/libs/filaflat/include/filaflat/ChunkContainer.h +++ b/libs/filaflat/include/filaflat/ChunkContainer.h @@ -35,7 +35,7 @@ public: ChunkContainer(void const* data, size_t size) : mData(data), mSize(size) {} - ~ChunkContainer() = default; + ~ChunkContainer() noexcept; // Must be called before trying to access any of the chunk. Fails and return false ONLY if // an incomplete chunk is found or if a chunk with bogus size is found. @@ -66,11 +66,20 @@ public: } const uint8_t* getChunkEnd(Type type) const noexcept { - return mChunks.at(type).start + mChunks.at(type).size; + ChunkDesc const& chunkDesc = mChunks.at(type); + return chunkDesc.start + chunkDesc.size; } - bool hasChunk(Type type) const noexcept { - return mChunks.find(type) != mChunks.end(); + bool hasChunk(Type type, ChunkDesc const** pChunkDesc = nullptr) const noexcept { + auto& chunks = mChunks; + auto pos = chunks.find(type); + if (pos != chunks.end()) { + if (pChunkDesc) { + *pChunkDesc = &pos.value(); + } + return true; + } + return false; } void const* getData() const { return mData; } diff --git a/libs/filaflat/include/filaflat/MaterialChunk.h b/libs/filaflat/include/filaflat/MaterialChunk.h index 8f6e01e182..b42491fbf3 100644 --- a/libs/filaflat/include/filaflat/MaterialChunk.h +++ b/libs/filaflat/include/filaflat/MaterialChunk.h @@ -33,6 +33,7 @@ class ShaderBuilder; class MaterialChunk { public: explicit MaterialChunk(ChunkContainer const& container); + ~MaterialChunk() noexcept; // call this once after container.parse() has been called bool readIndex(filamat::ChunkType materialTag); diff --git a/libs/filaflat/src/ChunkContainer.cpp b/libs/filaflat/src/ChunkContainer.cpp index 78a6f6c209..5419c91b8a 100644 --- a/libs/filaflat/src/ChunkContainer.cpp +++ b/libs/filaflat/src/ChunkContainer.cpp @@ -20,6 +20,8 @@ namespace filaflat { +ChunkContainer::~ChunkContainer() noexcept = default; + bool ChunkContainer::parseChunk(Unflattener& unflattener) { uint64_t type; if (!unflattener.read(&type)) { diff --git a/libs/filaflat/src/MaterialChunk.cpp b/libs/filaflat/src/MaterialChunk.cpp index 801d3f670d..5eed1a6cf4 100644 --- a/libs/filaflat/src/MaterialChunk.cpp +++ b/libs/filaflat/src/MaterialChunk.cpp @@ -31,6 +31,8 @@ MaterialChunk::MaterialChunk(ChunkContainer const& container) : mContainer(container) { } +MaterialChunk::~MaterialChunk() noexcept = default; + bool MaterialChunk::readIndex(filamat::ChunkType materialTag) { if (mBase != nullptr) { diff --git a/libs/utils/include/utils/Allocator.h b/libs/utils/include/utils/Allocator.h index 520d902c52..8b72db5dab 100644 --- a/libs/utils/include/utils/Allocator.h +++ b/libs/utils/include/utils/Allocator.h @@ -537,10 +537,10 @@ public: // construct an arena with a name and forward argument to its allocator template Arena(const char* name, size_t size, ARGS&& ... args) - : mArea(size), + : mArenaName(name), + mArea(size), mAllocator(mArea, std::forward(args) ... ), - mListener(name, mArea.data(), size), - mArenaName(name) { + mListener(name, mArea.data(), size) { } // allocate memory from arena with given size and alignment @@ -647,11 +647,12 @@ public: } private: + char const* mArenaName = nullptr; HeapArea mArea; // We might want to make that a template parameter too eventually. + // note: we should use something like compressed_pair for the members below AllocatorPolicy mAllocator; LockingPolicy mLock; TrackingPolicy mListener; - char const* mArenaName = nullptr; }; // ------------------------------------------------------------------------------------------------