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; }; // ------------------------------------------------------------------------------------------------