diff --git a/filament/src/details/Material.cpp b/filament/src/details/Material.cpp index b4e665a20f..aa6b2cbbe3 100644 --- a/filament/src/details/Material.cpp +++ b/filament/src/details/Material.cpp @@ -290,7 +290,7 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder, processDepthVariants(engine, parser); // we can only initialize the default instance once we're initialized ourselves - mDefaultInstance.initDefaultInstance(engine, this); + new(&mDefaultInstanceStorage) FMaterialInstance(engine, this); #if FILAMENT_ENABLE_MATDBG @@ -303,7 +303,9 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder, #endif } -FMaterial::~FMaterial() noexcept = default; +FMaterial::~FMaterial() noexcept { + std::destroy_at(getDefaultInstance()); +} void FMaterial::invalidate(Variant::type_t variantMask, Variant::type_t variantValue) noexcept { if (mMaterialDomain == MaterialDomain::SURFACE) { @@ -361,7 +363,8 @@ void FMaterial::terminate(FEngine& engine) { #endif destroyPrograms(engine); - mDefaultInstance.terminate(engine); + + getDefaultInstance()->terminate(engine); } void FMaterial::compile(CompilerPriorityQueue priority, @@ -408,7 +411,7 @@ void FMaterial::compile(CompilerPriorityQueue priority, } FMaterialInstance* FMaterial::createInstance(const char* name) const noexcept { - return FMaterialInstance::duplicate(&mDefaultInstance, name); + return FMaterialInstance::duplicate(getDefaultInstance(), name); } bool FMaterial::hasParameter(const char* name) const noexcept { diff --git a/filament/src/details/Material.h b/filament/src/details/Material.h index e0acd13d0c..c64686b9f9 100644 --- a/filament/src/details/Material.h +++ b/filament/src/details/Material.h @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -104,8 +105,13 @@ public: BufferInterfaceBlock::FieldInfo const* reflect(std::string_view name) const noexcept; - FMaterialInstance const* getDefaultInstance() const noexcept { return &mDefaultInstance; } - FMaterialInstance* getDefaultInstance() noexcept { return &mDefaultInstance; } + FMaterialInstance const* getDefaultInstance() const noexcept { + return const_cast(this)->getDefaultInstance(); + } + + FMaterialInstance* getDefaultInstance() noexcept { + return std::launder(reinterpret_cast(&mDefaultInstanceStorage)); + } FEngine& getEngine() const noexcept { return mEngine; } @@ -284,7 +290,10 @@ private: bool mIsDefaultMaterial = false; bool mSpecularAntiAliasing = false; - FMaterialInstance mDefaultInstance; + // reserve some space to construct the default material instance + std::aligned_storage::type mDefaultInstanceStorage; + static_assert(sizeof(mDefaultInstanceStorage) >= sizeof(mDefaultInstanceStorage)); + SamplerInterfaceBlock mSamplerInterfaceBlock; BufferInterfaceBlock mUniformInterfaceBlock; SubpassInfo mSubpassInfo; diff --git a/filament/src/details/MaterialInstance.cpp b/filament/src/details/MaterialInstance.cpp index 9c8a88a30b..4595c7e6c3 100644 --- a/filament/src/details/MaterialInstance.cpp +++ b/filament/src/details/MaterialInstance.cpp @@ -35,14 +35,61 @@ namespace filament { using namespace backend; -FMaterialInstance::FMaterialInstance() noexcept - : mCulling(CullingMode::BACK), +FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material) noexcept + : mMaterial(material), + mCulling(CullingMode::BACK), mDepthFunc(RasterState::DepthFunc::LE), mColorWrite(false), mDepthWrite(false), mHasScissor(false), mIsDoubleSided(false), mTransparencyMode(TransparencyMode::DEFAULT) { + + FEngine::DriverApi& driver = engine.getDriverApi(); + + if (!material->getUniformInterfaceBlock().isEmpty()) { + mUniforms = UniformBuffer(material->getUniformInterfaceBlock().getSize()); + mUbHandle = driver.createBufferObject(mUniforms.getSize(), + BufferObjectBinding::UNIFORM, backend::BufferUsage::STATIC); + } + + if (!material->getSamplerInterfaceBlock().isEmpty()) { + mSamplers = SamplerGroup(material->getSamplerInterfaceBlock().getSize()); + mSbHandle = driver.createSamplerGroup( + mSamplers.getSize(), utils::FixedSizeString<32>(mMaterial->getName().c_str_safe())); + } + + const RasterState& rasterState = material->getRasterState(); + // At the moment, only MaterialInstances have a stencil state, but in the future it should be + // possible to set the stencil state directly on a material (through material definitions, or + // MaterialBuilder). + // TODO: Here is where we'd "inherit" the stencil state from the Material. + // mStencilState = material->getStencilState(); + + // We inherit the resolved culling mode rather than the builder-set culling mode. + // This preserves the property whereby double-sidedness automatically disables culling. + mCulling = rasterState.culling; + mColorWrite = rasterState.colorWrite; + mDepthWrite = rasterState.depthWrite; + mDepthFunc = rasterState.depthFunc; + + mMaterialSortingKey = RenderPass::makeMaterialSortingKey( + material->getId(), material->generateMaterialInstanceId()); + + if (material->getBlendingMode() == BlendingMode::MASKED) { + setMaskThreshold(material->getMaskThreshold()); + } + + if (material->hasDoubleSidedCapability()) { + setDoubleSided(material->isDoubleSided()); + } + + if (material->hasSpecularAntiAliasing()) { + setSpecularAntiAliasingVariance(material->getSpecularAntiAliasingVariance()); + setSpecularAntiAliasingThreshold(material->getSpecularAntiAliasingThreshold()); + } + + setTransparencyMode(material->getTransparencyMode()); } FMaterialInstance::FMaterialInstance(FEngine& engine, @@ -103,56 +150,6 @@ FMaterialInstance* FMaterialInstance::duplicate( return engine.createMaterialInstance(material, other, name); } -void FMaterialInstance::initDefaultInstance(FEngine& engine, FMaterial const* material) { - FEngine::DriverApi& driver = engine.getDriverApi(); - - mMaterial = material; - - if (!material->getUniformInterfaceBlock().isEmpty()) { - mUniforms = UniformBuffer(material->getUniformInterfaceBlock().getSize()); - mUbHandle = driver.createBufferObject(mUniforms.getSize(), - BufferObjectBinding::UNIFORM, backend::BufferUsage::STATIC); - } - - if (!material->getSamplerInterfaceBlock().isEmpty()) { - mSamplers = SamplerGroup(material->getSamplerInterfaceBlock().getSize()); - mSbHandle = driver.createSamplerGroup( - mSamplers.getSize(), utils::FixedSizeString<32>(mMaterial->getName().c_str_safe())); - } - - const RasterState& rasterState = material->getRasterState(); - // At the moment, only MaterialInstances have a stencil state, but in the future it should be - // possible to set the stencil state directly on a material (through material definitions, or - // MaterialBuilder). - // TODO: Here is where we'd "inherit" the stencil state from the Material. - // mStencilState = material->getStencilState(); - - // We inherit the resolved culling mode rather than the builder-set culling mode. - // This preserves the property whereby double-sidedness automatically disables culling. - mCulling = rasterState.culling; - mColorWrite = rasterState.colorWrite; - mDepthWrite = rasterState.depthWrite; - mDepthFunc = rasterState.depthFunc; - - mMaterialSortingKey = RenderPass::makeMaterialSortingKey( - material->getId(), material->generateMaterialInstanceId()); - - if (material->getBlendingMode() == BlendingMode::MASKED) { - setMaskThreshold(material->getMaskThreshold()); - } - - if (material->hasDoubleSidedCapability()) { - setDoubleSided(material->isDoubleSided()); - } - - if (material->hasSpecularAntiAliasing()) { - setSpecularAntiAliasingVariance(material->getSpecularAntiAliasingVariance()); - setSpecularAntiAliasingThreshold(material->getSpecularAntiAliasingThreshold()); - } - - setTransparencyMode(material->getTransparencyMode()); -} - FMaterialInstance::~FMaterialInstance() noexcept = default; void FMaterialInstance::terminate(FEngine& engine) { diff --git a/filament/src/details/MaterialInstance.h b/filament/src/details/MaterialInstance.h index 6be23b7e06..8a574b4b0a 100644 --- a/filament/src/details/MaterialInstance.h +++ b/filament/src/details/MaterialInstance.h @@ -231,8 +231,8 @@ private: void setParameterImpl(std::string_view name, FTexture const* texture, TextureSampler const& sampler); - FMaterialInstance() noexcept; - void initDefaultInstance(FEngine& engine, FMaterial const* material); + // initialize the default instance + FMaterialInstance(FEngine& engine, FMaterial const* material) noexcept; void commitSlow(FEngine::DriverApi& driver) const;