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<float> and vec4<int> 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
This commit is contained in:
Mathias Agopian
2021-03-04 00:59:42 -08:00
committed by Mathias Agopian
parent 0815adf722
commit d740378277
17 changed files with 656 additions and 476 deletions

View File

@@ -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

View File

@@ -40,13 +40,9 @@ public:
template<typename T>
using is_supported_parameter_t = typename std::enable_if<
std::is_same<bool, T>::value ||
std::is_same<float, T>::value ||
std::is_same<int32_t, T>::value ||
std::is_same<uint32_t, T>::value ||
std::is_same<math::bool2, T>::value ||
std::is_same<math::bool3, T>::value ||
std::is_same<math::bool4, T>::value ||
std::is_same<math::int2, T>::value ||
std::is_same<math::int3, T>::value ||
std::is_same<math::int4, T>::value ||
@@ -56,8 +52,13 @@ public:
std::is_same<math::float2, T>::value ||
std::is_same<math::float3, T>::value ||
std::is_same<math::float4, T>::value ||
std::is_same<math::mat3f, T>::value ||
std::is_same<math::mat4f, T>::value
std::is_same<math::mat4f, T>::value ||
// these types are slower as they need a layout conversion
std::is_same<bool, T>::value ||
std::is_same<math::bool2, T>::value ||
std::is_same<math::bool3, T>::value ||
std::is_same<math::bool4, T>::value ||
std::is_same<math::mat3f, T>::value
>::type;
/**
@@ -78,7 +79,7 @@ public:
* @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled.
*/
template<typename T, typename = is_supported_parameter_t<T>>
void setParameter(const char* name, T value) noexcept;
void setParameter(const char* name, T const& value) noexcept;
/**
* Set a uniform array by name

View File

@@ -28,8 +28,6 @@
#include <utils/Log.h>
#include <string.h>
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<int> and
// vec4<float>. This must not be inlined (this is the whole point).
template<size_t Size>
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>(size_t(offset), value); // handles specialization for mat3f
}
}
// ------------------------------------------------------------------------------------------------
// this converts typed calls into the untyped-sized call.
template<typename T>
UTILS_ALWAYS_INLINE
inline void FMaterialInstance::setParameterImpl(const char* name, T const& value) noexcept {
static_assert(!std::is_same_v<T, math::mat3f>);
setParameterUntypedImpl<sizeof(T)>(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 <typename T, typename>
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<float> (const char* name, float const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int32_t> (const char* name, int32_t const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint32_t>(const char* name, uint32_t const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int2> (const char* name, int2 const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int3> (const char* name, int3 const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int4> (const char* name, int4 const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint2> (const char* name, uint2 const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint3> (const char* name, uint3 const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint4> (const char* name, uint4 const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float2> (const char* name, float2 const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float3> (const char* name, float3 const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float4> (const char* name, float4 const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<mat3f> (const char* name, mat3f const& v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<mat4f> (const char* name, mat4f const& v) noexcept;
// ------------------------------------------------------------------------------------------------
template <typename T, typename>
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<mat3f>(const char* name, const mat3f* v, size_t c) noexcept {
// pretend each mat3 is an array of 3 float3
MaterialInstance::setParameter(name, reinterpret_cast<math::float3 const*>(v), c * 3);
}
template UTILS_PUBLIC void MaterialInstance::setParameter<float> (const char* name, const float *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int32_t> (const char* name, const int32_t *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint32_t>(const char* name, const uint32_t *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int2> (const char* name, const int2 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int3> (const char* name, const int3 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int4> (const char* name, const int4 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint2> (const char* name, const uint2 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint3> (const char* name, const uint3 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint4> (const char* name, const uint4 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float2> (const char* name, const float2 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float3> (const char* name, const float3 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float4> (const char* name, const float4 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<mat4f> (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<MaterialInstance*>(this)->setParameter(
"_maskThreshold", material->getMaskThreshold());
setMaskThreshold(material->getMaskThreshold());
}
if (material->hasDoubleSidedCapability()) {
static_cast<MaterialInstance*>(this)->setParameter(
"_doubleSided", material->isDoubleSided());
setDoubleSided(material->isDoubleSided());
}
if (material->hasSpecularAntiAliasing()) {
static_cast<MaterialInstance*>(this)->setParameter(
"_specularAntiAliasingVariance", material->getSpecularAntiAliasingVariance());
static_cast<MaterialInstance*>(this)->setParameter(
"_specularAntiAliasingThreshold", material->getSpecularAntiAliasingThreshold());
setSpecularAntiAliasingVariance(material->getSpecularAntiAliasingVariance());
setSpecularAntiAliasingThreshold(material->getSpecularAntiAliasingThreshold());
}
}
@@ -125,26 +260,25 @@ void FMaterialInstance::commitSlow(DriverApi& driver) const {
}
}
template<typename T, typename>
inline void FMaterialInstance::setParameter(const char* name, T value) noexcept {
// ------------------------------------------------------------------------------------------------
template<size_t Size>
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<T>(size_t(offset), value); // handles specialization for mat3f
if (UTILS_LIKELY(offset >= 0)) {
mUniforms.setUniformArrayUntyped<Size>(size_t(offset), value, count);
}
}
template <typename T, typename >
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<T>(size_t(offset), value, count);
}
template<typename T>
UTILS_ALWAYS_INLINE
inline void FMaterialInstance::setParameterImpl(const char* name, const T* value, size_t count) noexcept {
static_assert(!std::is_same_v<T, math::mat3f>);
setParameterUntypedImpl<sizeof(T)>(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<backend::HwTexture> 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<bool> (const char* name, bool v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<float> (const char* name, float v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<int32_t> (const char* name, int32_t v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<uint32_t>(const char* name, uint32_t v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<bool2> (const char* name, bool2 v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<bool3> (const char* name, bool3 v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<bool4> (const char* name, bool4 v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<int2> (const char* name, int2 v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<int3> (const char* name, int3 v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<int4> (const char* name, int4 v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<uint2> (const char* name, uint2 v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<uint3> (const char* name, uint3 v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<uint4> (const char* name, uint4 v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<float2> (const char* name, float2 v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<float3> (const char* name, float3 v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<float4> (const char* name, float4 v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<mat3f> (const char* name, mat3f v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<mat4f> (const char* name, mat4f v) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<bool> (const char* name, const bool *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<float> (const char* name, const float *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<int32_t> (const char* name, const int32_t *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<uint32_t>(const char* name, const uint32_t *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<bool2> (const char* name, const bool2 *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<bool3> (const char* name, const bool3 *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<bool4> (const char* name, const bool4 *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<int2> (const char* name, const int2 *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<int3> (const char* name, const int3 *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<int4> (const char* name, const int4 *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<uint2> (const char* name, const uint2 *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<uint3> (const char* name, const uint3 *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<uint4> (const char* name, const uint4 *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<float2> (const char* name, const float2 *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<float3> (const char* name, const float3 *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<float4> (const char* name, const float4 *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<mat3f> (const char* name, const mat3f *v, size_t c) noexcept;
template UTILS_NOINLINE void FMaterialInstance::setParameter<mat4f> (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 <typename T, typename>
void MaterialInstance::setParameter(const char* name, T value) noexcept {
upcast(this)->setParameter<T>(name, value);
}
// ------------------------------------------------------------------------------------------------
template <typename T, typename>
void MaterialInstance::setParameter(const char* name, const T* value, size_t count) noexcept {
upcast(this)->setParameter<T>(name, value, count);
}
// explicit template instantiation of our supported types
template UTILS_PUBLIC void MaterialInstance::setParameter<bool> (const char* name, bool v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float> (const char* name, float v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int32_t> (const char* name, int32_t v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint32_t>(const char* name, uint32_t v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<bool2> (const char* name, bool2 v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<bool3> (const char* name, bool3 v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<bool4> (const char* name, bool4 v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int2> (const char* name, int2 v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int3> (const char* name, int3 v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int4> (const char* name, int4 v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint2> (const char* name, uint2 v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint3> (const char* name, uint3 v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint4> (const char* name, uint4 v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float2> (const char* name, float2 v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float3> (const char* name, float3 v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float4> (const char* name, float4 v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<mat3f> (const char* name, mat3f v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<mat4f> (const char* name, mat4f v) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<bool> (const char* name, const bool *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float> (const char* name, const float *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int32_t> (const char* name, const int32_t *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint32_t>(const char* name, const uint32_t *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<bool2> (const char* name, const bool2 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<bool3> (const char* name, const bool3 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<bool4> (const char* name, const bool4 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int2> (const char* name, const int2 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int3> (const char* name, const int3 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<int4> (const char* name, const int4 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint2> (const char* name, const uint2 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint3> (const char* name, const uint3 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<uint4> (const char* name, const uint4 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float2> (const char* name, const float2 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float3> (const char* name, const float3 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<float4> (const char* name, const float4 *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<mat3f> (const char* name, const mat3f *v, size_t c) noexcept;
template UTILS_PUBLIC void MaterialInstance::setParameter<mat4f> (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<float3>(name, Color::toLinear(type, color));
upcast(this)->setParameterImpl<float3>(name, Color::toLinear(type, color));
}
void MaterialInstance::setParameter(const char* name, RgbaType type, float4 color) noexcept {
upcast(this)->setParameter<float4>(name, Color::toLinear(type, color));
upcast(this)->setParameterImpl<float4>(name, Color::toLinear(type, color));
}
void MaterialInstance::setScissor(uint32_t left, uint32_t bottom, uint32_t width,

View File

@@ -69,11 +69,13 @@ MaterialParser::MaterialParserDetails::MaterialParserDetails(Backend backend, co
}
template<typename T>
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;

View File

@@ -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.

View File

@@ -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<math::half>::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<math::half>::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

View File

@@ -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<math::half>::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<math::half>::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

View File

@@ -90,6 +90,77 @@ void UniformBuffer::free(void* addr, size_t) noexcept {
::free(addr);
}
// ------------------------------------------------------------------------------------------------
template<size_t Size>
void UniformBuffer::setUniformUntyped(size_t offset, void const* UTILS_RESTRICT v) noexcept{
setUniformUntyped<Size>(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<size_t Size>
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<Size>(p, 0ul, static_cast<const char *>(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<char*>(addr) + offset;
mat43& temp = *static_cast<mat43*>(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) {

View File

@@ -32,6 +32,7 @@
#include <math/mat4.h>
#include <stddef.h>
#include <string.h>
namespace filament {
@@ -94,17 +95,15 @@ public:
* -----------------------------------------------
*/
// Note: we purposedly not include types that require conversion here
// (e.g. bool and bool vectors)
template <typename T>
struct is_supported_type {
using type = typename std::enable_if<
std::is_same<bool, T>::value ||
std::is_same<float, T>::value ||
std::is_same<int32_t, T>::value ||
std::is_same<uint32_t, T>::value ||
std::is_same<math::quatf, T>::value ||
std::is_same<math::bool2, T>::value ||
std::is_same<math::bool3, T>::value ||
std::is_same<math::bool4, T>::value ||
std::is_same<math::int2, T>::value ||
std::is_same<math::int3, T>::value ||
std::is_same<math::int4, T>::value ||
@@ -132,34 +131,32 @@ public:
// a x x x b x x x c
//
// The "x" symbols represent dummy words.
template <typename T, typename = typename is_supported_type<T>::type>
template<typename T, typename = typename is_supported_type<T>::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<T*>(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<T, math::mat3f>);
setUniformArrayUntyped<sizeof(T)>(offset, begin, count);
}
// (see specialization for mat3f below)
template <typename T, typename = typename is_supported_type<T>::type>
static void setUniform(void* addr, size_t offset, const T& v) noexcept {
addr = static_cast<char*>(addr) + offset;
T* p = static_cast<T*>(addr);
*p = v;
template<typename T, typename = typename is_supported_type<T>::type>
UTILS_ALWAYS_INLINE
static inline void setUniform(void* addr, size_t offset, const T& v) noexcept {
static_assert(!std::is_same_v<T, math::mat3f>);
setUniformUntyped<sizeof(T)>(addr, offset, &v);
}
// set uniform of known types to the proper offset (e.g.: use offsetof())
template <typename T, typename = typename is_supported_type<T>::type>
void setUniform(size_t offset, const T& v) noexcept {
setUniform(invalidateUniforms(offset, sizeof(T)), 0, v);
template<typename T, typename = typename is_supported_type<T>::type>
UTILS_ALWAYS_INLINE
inline void setUniform(size_t offset, const T& v) noexcept {
static_assert(!std::is_same_v<T, math::mat3f>);
setUniformUntyped<sizeof(T)>(offset, &v);
}
// get uniform of known types from the proper offset (e.g.: use offsetof())
template<typename T, typename = typename is_supported_type<T>::type>
T getUniform(size_t offset) const noexcept {
static_assert(!std::is_same_v<T, math::mat3f>);
return *reinterpret_cast<T const*>(static_cast<char const*>(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<const char*>(getBuffer()) + offset, p.size);
memcpy(p.buffer, static_cast<const char*>(getBuffer()) + offset, p.size); // inlined
clean();
return p;
}
// set uniform of known types to the proper offset (e.g.: use offsetof())
template<size_t Size>
void setUniformUntyped(size_t offset, void const* UTILS_RESTRICT v) noexcept;
template<size_t Size>
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<size_t Size, std::enable_if_t<
Size == 4 || Size == 8 || Size == 12 || Size == 16 || Size == 64, bool> = true>
UTILS_ALWAYS_INLINE
static void setUniformUntyped(void* addr, size_t offset, void const* v) noexcept {
memcpy(static_cast<char*>(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<char*>(addr) + offset;
mat43& temp = *static_cast<mat43*>(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<math::float3 const*>(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<math::float3 const*>(begin), count * 3);
}
} // namespace filament
#endif // TNT_FILAMENT_DRIVER_UNIFORMBUFFER_H

View File

@@ -60,18 +60,6 @@ public:
}
}
template <typename T, typename = is_supported_parameter_t<T>>
void setParameter(const char* name, T value) noexcept;
template <typename T, typename = is_supported_parameter_t<T>>
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<backend::HwTexture> 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<backend::HwTexture> texture, backend::SamplerParams params) noexcept;
using MaterialInstance::setParameter;
private:
friend class FMaterial;
friend class MaterialInstance;
template<size_t Size>
void setParameterUntypedImpl(const char* name, const void* value) noexcept;
template<size_t Size>
void setParameterUntypedImpl(const char* name, const void* value, size_t count) noexcept;
template<typename T>
void setParameterImpl(const char* name, T const& value) noexcept;
template<typename T>
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);

View File

@@ -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";
}

View File

@@ -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.

View File

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

View File

@@ -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);

View File

@@ -20,6 +20,8 @@
namespace filaflat {
ChunkContainer::~ChunkContainer() noexcept = default;
bool ChunkContainer::parseChunk(Unflattener& unflattener) {
uint64_t type;
if (!unflattener.read(&type)) {

View File

@@ -31,6 +31,8 @@ MaterialChunk::MaterialChunk(ChunkContainer const& container)
: mContainer(container) {
}
MaterialChunk::~MaterialChunk() noexcept = default;
bool MaterialChunk::readIndex(filamat::ChunkType materialTag) {
if (mBase != nullptr) {

View File

@@ -537,10 +537,10 @@ public:
// construct an arena with a name and forward argument to its allocator
template<typename ... ARGS>
Arena(const char* name, size_t size, ARGS&& ... args)
: mArea(size),
: mArenaName(name),
mArea(size),
mAllocator(mArea, std::forward<ARGS>(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;
};
// ------------------------------------------------------------------------------------------------