From ee4c03d0f13371f24b9d119cb9f839232fe0216d Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Thu, 28 Mar 2024 14:15:32 -0700 Subject: [PATCH 01/10] Fix WebGL build with newer Emscripten (#7721) --- web/filament-js/jsbindings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index fed31ce1407..87da0121452 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -369,8 +369,8 @@ using EntityVector = std::vector; register_vector("RegistryKeys"); register_vector("EntityVector"); -register_vector("AssetInstanceVector"); -register_vector("MaterialInstanceVector"); +register_vector>("AssetInstanceVector"); +register_vector>("MaterialInstanceVector"); // CORE FILAMENT CLASSES // --------------------- From 0ec35964409e2cfc1e0fa22f56f25a267f6af862 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 28 Mar 2024 16:35:23 -0700 Subject: [PATCH 02/10] the user can now set a panic handler callback BUGS=[331457244] --- libs/utils/include/utils/Panic.h | 48 +++++++++++++---- libs/utils/src/Panic.cpp | 91 ++++++++++++++++++++++++++++---- 2 files changed, 120 insertions(+), 19 deletions(-) diff --git a/libs/utils/include/utils/Panic.h b/libs/utils/include/utils/Panic.h index b4ec032c81b..c658da4b14f 100644 --- a/libs/utils/include/utils/Panic.h +++ b/libs/utils/include/utils/Panic.h @@ -250,42 +250,71 @@ namespace utils { */ class UTILS_PUBLIC Panic { public: + + using PanicHandlerCallback = void(*)(void* user, Panic const& panic); + + /** + * Sets a user-defined handler for the Panic. If exceptions are enabled, the concrete Panic + * object will be thrown upon return; moreover it is acceptable to throw from the provided + * callback, but it is unsafe to throw the Panic object itself, since it's just an interface. + * It is also acceptable to abort from the callback. If exceptions are not enabled, std::abort() + * will be automatically called upon return. + * + * The PanicHandlerCallback can be called from any thread. + * + * Caveat: this API can misbehave if is used as a static library in multiple translation units, + * some of these translation units might not see the callback. + * + * @param handler pointer to the user defined handler for the Panic + * @param user user pointer given back to the callback + */ + static void setPanicHandler(PanicHandlerCallback handler, void* user) noexcept; + + virtual ~Panic() noexcept; /** - * @return a detailed description of the error + * @return a formatted and detailed description of the error including all available + * information. * @see std::exception */ virtual const char* what() const noexcept = 0; /** - * Get the function name where the panic was detected + * Get the reason string for the panic + * @return a C string containing the reason for the panic + */ + virtual const char* getReason() const noexcept = 0; + + /** + * Get the function name where the panic was detected. On debug build the fully qualified + * function name is returned; on release builds only the function name is. * @return a C string containing the function name where the panic was detected */ virtual const char* getFunction() const noexcept = 0; /** - * Get the file name where the panic was detected + * Get the file name where the panic was detected. Only available on debug builds. * @return a C string containing the file name where the panic was detected */ virtual const char* getFile() const noexcept = 0; /** - * Get the line number in the file where the panic was detected + * Get the line number in the file where the panic was detected. Only available on debug builds. * @return an integer containing the line number in the file where the panic was detected */ virtual int getLine() const noexcept = 0; /** - * Logs this exception to the system-log + * Get the CallStack when the panic was detected if available. + * @return the CallStack when the panic was detected */ - virtual void log() const noexcept = 0; + virtual const CallStack& getCallStack() const noexcept = 0; /** - * Get the CallStack when the panic was detected - * @return the CallStack when the panic was detected + * Logs this exception to the system-log */ - virtual const CallStack& getCallStack() const noexcept = 0; + virtual void log() const noexcept = 0; }; // ----------------------------------------------------------------------------------------------- @@ -305,6 +334,7 @@ class UTILS_PUBLIC TPanic : public Panic { const char* what() const noexcept override; // Panic interface + const char* getReason() const noexcept override; const char* getFunction() const noexcept override; const char* getFile() const noexcept override; int getLine() const noexcept override; diff --git a/libs/utils/src/Panic.cpp b/libs/utils/src/Panic.cpp index 023a79b2477..addec296c10 100644 --- a/libs/utils/src/Panic.cpp +++ b/libs/utils/src/Panic.cpp @@ -14,17 +14,64 @@ * limitations under the License. */ +#include #include +#include +#include -#include -#include #include #include +#include +#include +#include +#include -#include +#include +#include +#include +#include namespace utils { +// ------------------------------------------------------------------------------------------------ + +class UserPanicHandler { + struct CallBack { + Panic::PanicHandlerCallback handler = nullptr; + void* user = nullptr; + void call(Panic const& panic) const noexcept { + if (UTILS_UNLIKELY(handler)) { + handler(user, panic); + } + } + }; + + mutable std::mutex mLock{}; + CallBack mCallBack{}; + + CallBack getCallback() const noexcept { + std::lock_guard const lock(mLock); + return mCallBack; + } + +public: + static UserPanicHandler& get() noexcept { + static UserPanicHandler data; + return data; + } + + void call(Panic const& panic) const noexcept { + getCallback().call(panic); + } + + void set(Panic::PanicHandlerCallback handler, void* user) noexcept { + std::lock_guard const lock(mLock); + mCallBack = { handler, user }; + } +}; + +// ------------------------------------------------------------------------------------------------ + static std::string formatString(const char* format, va_list args) noexcept { std::string reason; @@ -35,10 +82,12 @@ static std::string formatString(const char* format, va_list args) noexcept { if (n >= 0) { ++n; // for the nul-terminating char - char* buf = new char[n]; - vsnprintf(buf, size_t(n), format, args); - reason.assign(buf); - delete [] buf; + char* const buf = new(std::nothrow) char[n]; + if (buf) { + vsnprintf(buf, size_t(n), format, args); + reason.assign(buf); + delete [] buf; + } } return reason; } @@ -63,8 +112,16 @@ static std::string panicString( #endif } +// ------------------------------------------------------------------------------------------------ + Panic::~Panic() noexcept = default; +void Panic::setPanicHandler(PanicHandlerCallback handler, void* user) noexcept { + UserPanicHandler::get().set(handler, user); +} + +// ------------------------------------------------------------------------------------------------ + template TPanic::TPanic(std::string reason) : m_reason(std::move(reason)) { @@ -88,6 +145,11 @@ const char* TPanic::what() const noexcept { return m_msg.c_str(); } +template +const char* TPanic::getReason() const noexcept { + return m_reason.c_str(); +} + template const char* TPanic::getFunction() const noexcept { return m_function; @@ -135,13 +197,22 @@ template void TPanic::panic(char const* function, char const* file, int line, const char* format, ...) { va_list args; va_start(args, format); - std::string reason(formatString(format, args)); + std::string const reason(formatString(format, args)); va_end(args); T e(function, formatFile(file), line, reason); + + // always log the Panic at the point it is detected e.log(); + + // Call the user provided handler + UserPanicHandler::get().call(e); + + // if exceptions are enabled, throw now. #ifdef __EXCEPTIONS - throw e; + throw e; #endif + + // and finally abort if we somehow get here std::abort(); } @@ -152,7 +223,7 @@ namespace details { void panicLog(char const* function, char const* file, int line, const char* format, ...) noexcept { va_list args; va_start(args, format); - std::string reason(formatString(format, args)); + std::string const reason(formatString(format, args)); va_end(args); const std::string msg = panicString("" /* no extra message */, From 8db5e700d7e07ddc4eab769760344c446dc35926 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 29 Mar 2024 14:19:45 -0700 Subject: [PATCH 03/10] GL backend should only allocate renderbuffers when possible There was several cases where the the gl backend would wrongly use a renderbuffer instead of a texture. BUGS=[329491941] --- filament/backend/src/opengl/OpenGLDriver.cpp | 18 +++++++------ filament/src/PostProcessManager.cpp | 5 +--- filament/src/RendererUtils.cpp | 27 ++++++++++++++------ 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 196d1bd2e66..81cc54fb830 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -724,10 +724,19 @@ void OpenGLDriver::createTextureR(Handle th, SamplerType target, uint GLenum internalFormat = getInternalFormat(format); assert_invariant(internalFormat); - if (UTILS_UNLIKELY(usage & TextureUsage::PROTECTED)) { + if (any(usage & TextureUsage::PROTECTED)) { // renderbuffers don't have a protected mode, so we need to use a texture // because protected textures are only supported on GLES 3.2, MSAA will be available. usage |= TextureUsage::SAMPLEABLE; + } else if (any(usage & TextureUsage::UPLOADABLE)) { + // if we have the uploadable flag, we also need to use a texture + usage |= TextureUsage::SAMPLEABLE; + } else if (target != SamplerType::SAMPLER_2D) { + // renderbuffers can only be 2D + usage |= TextureUsage::SAMPLEABLE; + } else if (levels > 1) { + // renderbuffers can't have mip levels + usage |= TextureUsage::SAMPLEABLE; } auto& gl = mContext; @@ -803,13 +812,6 @@ void OpenGLDriver::createTextureR(Handle th, SamplerType target, uint textureStorage(t, w, h, depth, bool(usage & TextureUsage::PROTECTED)); } } else { - assert_invariant(any(usage & ( - TextureUsage::COLOR_ATTACHMENT | - TextureUsage::DEPTH_ATTACHMENT | - TextureUsage::STENCIL_ATTACHMENT))); - assert_invariant(levels == 1); - assert_invariant(target == SamplerType::SAMPLER_2D); - assert_invariant(none(usage & TextureUsage::PROTECTED)); t->gl.internalFormat = internalFormat; t->gl.target = GL_RENDERBUFFER; glGenRenderbuffers(1, &t->gl.id); diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index 3f21ce872d4..3fbd7f41444 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -450,11 +450,8 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph .levels = uint8_t(levelCount), .format = isES2 ? TextureFormat::DEPTH24 : TextureFormat::DEPTH32F }); - // workaround: since we have levels, this implies SAMPLEABLE (because of the gl - // backend, which implements non-sampleables with renderbuffers, which don't have levels). - // (should the gl driver revert to textures, in that case?) data.depth = builder.write(data.depth, - FrameGraphTexture::Usage::DEPTH_ATTACHMENT | FrameGraphTexture::Usage::SAMPLEABLE); + FrameGraphTexture::Usage::DEPTH_ATTACHMENT); if (config.picking) { data.picking = builder.createTexture("Picking Buffer", { diff --git a/filament/src/RendererUtils.cpp b/filament/src/RendererUtils.cpp index 8c63be153eb..3e1cafdbc9d 100644 --- a/filament/src/RendererUtils.cpp +++ b/filament/src/RendererUtils.cpp @@ -16,17 +16,35 @@ #include "RendererUtils.h" +#include "PostProcessManager.h" + #include "details/Engine.h" #include "details/View.h" #include "fg/FrameGraph.h" #include "fg/FrameGraphId.h" #include "fg/FrameGraphResources.h" +#include "fg/FrameGraphTexture.h" + +#include +#include +#include + +#include +#include +#include +#include #include #include #include +#include +#include + +#include +#include + namespace filament { using namespace backend; @@ -153,16 +171,9 @@ FrameGraphId RendererUtils::colorPass( data.depth = builder.read(data.depth, FrameGraphTexture::Usage::DEPTH_ATTACHMENT); data.color = builder.write(data.color, FrameGraphTexture::Usage::COLOR_ATTACHMENT); + data.depth = builder.write(data.depth, FrameGraphTexture::Usage::DEPTH_ATTACHMENT); if (engine.getConfig().stereoscopicType == StereoscopicType::MULTIVIEW) { - // Add sampleable usage flag for depth in multiview rendering, othewise it's - // treated as renderbuffer in the backend and crashed. - data.depth = builder.write(data.depth, - FrameGraphTexture::Usage::DEPTH_ATTACHMENT | - FrameGraphTexture::Usage::SAMPLEABLE); layerCount = engine.getConfig().stereoscopicEyeCount; - } else { - data.depth = builder.write(data.depth, - FrameGraphTexture::Usage::DEPTH_ATTACHMENT); } /* From 8ce6d54930ce4efd9b2e602f9d1f55928e95978b Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 29 Mar 2024 10:36:45 -0700 Subject: [PATCH 04/10] remove wrong `noexcept` in the backend going forward we want to be able to throw exceptions from the backend at the very least, we need to be consistant, currently we are potentially throwing exceptions from `noexcept` places. this changes makes it possible to throw exceptions from the backend, during handle construction and conversion to pointers, which wasn't allowed before. We still can't throw from dtors because it's generally a bad idea, better abort in that case. --- .../backend/include/private/backend/CommandStream.h | 4 ++-- filament/backend/include/private/backend/Driver.h | 2 +- .../backend/include/private/backend/HandleAllocator.h | 10 +++++----- filament/backend/src/CommandStream.cpp | 2 +- filament/backend/src/Driver.cpp | 2 +- filament/backend/src/HandleAllocator.cpp | 2 +- filament/backend/src/opengl/OpenGLDriver.h | 8 ++++---- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/filament/backend/include/private/backend/CommandStream.h b/filament/backend/include/private/backend/CommandStream.h index 985fa5fcd6e..f722794b52c 100644 --- a/filament/backend/include/private/backend/CommandStream.h +++ b/filament/backend/include/private/backend/CommandStream.h @@ -134,7 +134,7 @@ struct CommandType { public: template - static inline void execute(M&& method, D&& driver, CommandBase* base, intptr_t* next) noexcept { + static inline void execute(M&& method, D&& driver, CommandBase* base, intptr_t* next) { Command* self = static_cast(base); *next = align(sizeof(Command)); #if DEBUG_COMMAND_STREAM @@ -168,7 +168,7 @@ struct CommandType { class CustomCommand : public CommandBase { std::function mCommand; - static void execute(Driver&, CommandBase* base, intptr_t* next) noexcept; + static void execute(Driver&, CommandBase* base, intptr_t* next); public: inline CustomCommand(CustomCommand&& rhs) = default; inline explicit CustomCommand(std::function cmd) diff --git a/filament/backend/include/private/backend/Driver.h b/filament/backend/include/private/backend/Driver.h index 4b30bdad77a..527052378e6 100644 --- a/filament/backend/include/private/backend/Driver.h +++ b/filament/backend/include/private/backend/Driver.h @@ -76,7 +76,7 @@ class Driver { // the fn function will execute a batch of driver commands // this gives the driver a chance to wrap their execution in a meaningful manner // the default implementation simply calls fn - virtual void execute(std::function const& fn) noexcept; + virtual void execute(std::function const& fn); // This is called on debug build, or when enabled manually on the backend thread side. virtual void debugCommandBegin(CommandStream* cmds, diff --git a/filament/backend/include/private/backend/HandleAllocator.h b/filament/backend/include/private/backend/HandleAllocator.h index 578ce5d6f1a..bcf4bfa902f 100644 --- a/filament/backend/include/private/backend/HandleAllocator.h +++ b/filament/backend/include/private/backend/HandleAllocator.h @@ -65,7 +65,7 @@ class HandleAllocator { * */ template - Handle allocateAndConstruct(ARGS&& ... args) noexcept { + Handle allocateAndConstruct(ARGS&& ... args) { Handle h{ allocateHandle() }; D* addr = handle_cast(h); new(addr) D(std::forward(args)...); @@ -97,7 +97,7 @@ class HandleAllocator { */ template typename std::enable_if_t, D>* - destroyAndConstruct(Handle const& handle, ARGS&& ... args) noexcept { + destroyAndConstruct(Handle const& handle, ARGS&& ... args) { assert_invariant(handle); D* addr = handle_cast(const_cast&>(handle)); assert_invariant(addr); @@ -163,7 +163,7 @@ class HandleAllocator { inline typename std::enable_if_t< std::is_pointer_v && std::is_base_of_v>, Dp> - handle_cast(Handle& handle) noexcept { + handle_cast(Handle& handle) { assert_invariant(handle); auto [p, tag] = handleToPointer(handle.getId()); @@ -185,7 +185,7 @@ class HandleAllocator { inline typename std::enable_if_t< std::is_pointer_v && std::is_base_of_v>, Dp> - handle_cast(Handle const& handle) noexcept { + handle_cast(Handle const& handle) { return handle_cast(const_cast&>(handle)); } @@ -317,7 +317,7 @@ class HandleAllocator { return (id & HANDLE_HEAP_FLAG) == 0u; } - HandleBase::HandleId allocateHandleSlow(size_t size) noexcept; + HandleBase::HandleId allocateHandleSlow(size_t size); void deallocateHandleSlow(HandleBase::HandleId id, size_t size) noexcept; // We inline this because it's just 4 instructions in the fast case diff --git a/filament/backend/src/CommandStream.cpp b/filament/backend/src/CommandStream.cpp index 29bb2184575..69730d688c8 100644 --- a/filament/backend/src/CommandStream.cpp +++ b/filament/backend/src/CommandStream.cpp @@ -149,7 +149,7 @@ void CommandType::Command::log() noexcept { // ------------------------------------------------------------------------------------------------ -void CustomCommand::execute(Driver&, CommandBase* base, intptr_t* next) noexcept { +void CustomCommand::execute(Driver&, CommandBase* base, intptr_t* next) { *next = CustomCommand::align(sizeof(CustomCommand)); static_cast(base)->mCommand(); static_cast(base)->~CustomCommand(); diff --git a/filament/backend/src/Driver.cpp b/filament/backend/src/Driver.cpp index ef165d7667b..f33f855d9f4 100644 --- a/filament/backend/src/Driver.cpp +++ b/filament/backend/src/Driver.cpp @@ -214,7 +214,7 @@ size_t Driver::getElementTypeSize(ElementType type) noexcept { Driver::~Driver() noexcept = default; -void Driver::execute(std::function const& fn) noexcept { +void Driver::execute(std::function const& fn) { fn(); } diff --git a/filament/backend/src/HandleAllocator.cpp b/filament/backend/src/HandleAllocator.cpp index fb58cb1b588..a5a9e7c98c8 100644 --- a/filament/backend/src/HandleAllocator.cpp +++ b/filament/backend/src/HandleAllocator.cpp @@ -107,7 +107,7 @@ void* HandleAllocator::handleToPointerSlow(HandleBase::HandleId id) } template -HandleBase::HandleId HandleAllocator::allocateHandleSlow(size_t size) noexcept { +HandleBase::HandleId HandleAllocator::allocateHandleSlow(size_t size) { void* p = ::malloc(size); std::unique_lock lock(mLock); diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index 6dad88c082b..100148101d5 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -268,13 +268,13 @@ class OpenGLDriver final : public DriverBase { HandleAllocatorGL mHandleAllocator; template - Handle initHandle(ARGS&& ... args) noexcept { + Handle initHandle(ARGS&& ... args) { return mHandleAllocator.allocateAndConstruct(std::forward(args) ...); } template typename std::enable_if::value, D>::type* - construct(Handle const& handle, ARGS&& ... args) noexcept { + construct(Handle const& handle, ARGS&& ... args) { return mHandleAllocator.destroyAndConstruct(handle, std::forward(args) ...); } @@ -288,7 +288,7 @@ class OpenGLDriver final : public DriverBase { typename std::enable_if_t< std::is_pointer_v && std::is_base_of_v>, Dp> - handle_cast(Handle& handle) noexcept { + handle_cast(Handle& handle) { return mHandleAllocator.handle_cast(handle); } @@ -296,7 +296,7 @@ class OpenGLDriver final : public DriverBase { inline typename std::enable_if_t< std::is_pointer_v && std::is_base_of_v>, Dp> - handle_cast(Handle const& handle) noexcept { + handle_cast(Handle const& handle) { return mHandleAllocator.handle_cast(handle); } From 348e61fd76dc9a8dea829d5bd02d68166801831d Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 29 Mar 2024 15:50:37 -0700 Subject: [PATCH 05/10] remove unused code --- filament/src/details/Material.cpp | 8 -------- filament/src/details/Material.h | 2 -- 2 files changed, 10 deletions(-) diff --git a/filament/src/details/Material.cpp b/filament/src/details/Material.cpp index 66bf9ee67b2..d1658103d0f 100644 --- a/filament/src/details/Material.cpp +++ b/filament/src/details/Material.cpp @@ -323,14 +323,6 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder) parser->getMaskThreshold(&mMaskThreshold); } - // The fade blending mode only affects shading. For proper sorting we need to - // treat this blending mode as a regular transparent blending operation. - if (UTILS_UNLIKELY(mBlendingMode == BlendingMode::FADE)) { - mRenderBlendingMode = BlendingMode::TRANSPARENT; - } else { - mRenderBlendingMode = mBlendingMode; - } - if (mShading == Shading::UNLIT) { parser->hasShadowMultiplier(&mHasShadowMultiplier); } diff --git a/filament/src/details/Material.h b/filament/src/details/Material.h index 85e7932a0c8..4de4bbb68a5 100644 --- a/filament/src/details/Material.h +++ b/filament/src/details/Material.h @@ -127,7 +127,6 @@ class FMaterial : public Material { Shading getShading() const noexcept { return mShading; } Interpolation getInterpolation() const noexcept { return mInterpolation; } BlendingMode getBlendingMode() const noexcept { return mBlendingMode; } - BlendingMode getRenderBlendingMode() const noexcept { return mRenderBlendingMode; } VertexDomain getVertexDomain() const noexcept { return mVertexDomain; } MaterialDomain getMaterialDomain() const noexcept { return mMaterialDomain; } CullingMode getCullingMode() const noexcept { return mCullingMode; } @@ -223,7 +222,6 @@ class FMaterial : public Material { mutable std::array, VARIANT_COUNT> mCachedPrograms; backend::RasterState mRasterState; - BlendingMode mRenderBlendingMode = BlendingMode::OPAQUE; TransparencyMode mTransparencyMode = TransparencyMode::DEFAULT; bool mIsVariantLit = false; backend::FeatureLevel mFeatureLevel = backend::FeatureLevel::FEATURE_LEVEL_1; From 1c55ad49ee5fa2a9b7a6c0127228e54968a24847 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 29 Mar 2024 16:58:55 -0700 Subject: [PATCH 06/10] add support for custom blend functions BUGS=[331610785] --- docs/Materials.md.html | 33 ++++++++++++- filament/src/MaterialParser.cpp | 10 ++++ filament/src/MaterialParser.h | 1 + filament/src/details/Material.cpp | 10 ++++ filament/src/details/Material.h | 1 + .../include/filament/MaterialChunkType.h | 1 + .../include/filament/MaterialEnums.h | 2 + .../filamat/include/filamat/MaterialBuilder.h | 11 +++++ libs/filamat/src/MaterialBuilder.cpp | 20 ++++++++ libs/filamat/src/shaders/ShaderGenerator.cpp | 6 +++ libs/gltfio/src/UbershaderProvider.cpp | 1 + libs/matdbg/src/CommonWriter.h | 1 + libs/uberz/src/WritableArchive.cpp | 2 + tools/matc/src/matc/ParametersProcessor.cpp | 48 +++++++++++++++++++ 14 files changed, 146 insertions(+), 1 deletion(-) diff --git a/docs/Materials.md.html b/docs/Materials.md.html index 1e63bcef0da..d34b5f5ef4e 100644 --- a/docs/Materials.md.html +++ b/docs/Materials.md.html @@ -1397,7 +1397,7 @@ : `string` Value -: Any of `opaque`, `transparent`, `fade`, `add`, `masked`, `multiply`, `screen`. Defaults to `opaque`. +: Any of `opaque`, `transparent`, `fade`, `add`, `masked`, `multiply`, `screen`, `custom`. Defaults to `opaque`. Description : Defines how/if the rendered object is blended with the content of the render target. @@ -1420,6 +1420,7 @@ of the material's output defines whether a fragment is discarded or not. Additionally, ALPHA_TO_COVERAGE is enabled for non-translucent views. See the maskThreshold section for more information. + - **Custom**: blending is enabled. But the blending function is user specified. See `blendFunction`. !!! Note When `blending` is set to `masked`, alpha to coverage is automatically enabled for the material. @@ -1432,6 +1433,36 @@ } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### Blending and transparency: blendFunction + +Type +: `object` + +Fields +: `srcRGB`, `srcA`, `dstRGB`, `dstA` + +Description +: - *srcRGB*: source function applied to the RGB channels + - *srcA*: source function applied to the alpha channel + - *srcRGB*: destination function applied to the RGB channels + - *srcRGB*: destination function applied to the alpha channel + The values possible for each functions are one of `zero`, `one`, `srcColor`, `oneMinusSrcColor`, + `dstColor`, `oneMinusDstColor`, `srcAlpha`, `oneMinusSrcAlpha`, `dstAlpha`, + `oneMinusDstAlpha`, `srcAlphaSaturate` + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON +material { + blending : custom, + blendFunction : + { + srcRGB: one, + srcA: one, + dstRGB: oneMinusSrcColor, + dstA: oneMinusSrcAlpha + } + } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ### Blending and transparency: postLightingBlending Type diff --git a/filament/src/MaterialParser.cpp b/filament/src/MaterialParser.cpp index 3b492bd6a4f..5427835a282 100644 --- a/filament/src/MaterialParser.cpp +++ b/filament/src/MaterialParser.cpp @@ -277,6 +277,16 @@ bool MaterialParser::getBlendingMode(BlendingMode* value) const noexcept { return mImpl.getFromSimpleChunk(ChunkType::MaterialBlendingMode, reinterpret_cast(value)); } +bool MaterialParser::getCustomBlendFunction(std::array* value) const noexcept { + uint32_t blendFunctions = 0; + bool const result = mImpl.getFromSimpleChunk(ChunkType::MaterialBlendFunction, &blendFunctions); + (*value)[0] = BlendFunction((blendFunctions >> 24) & 0xFF); + (*value)[1] = BlendFunction((blendFunctions >> 16) & 0xFF); + (*value)[2] = BlendFunction((blendFunctions >> 8) & 0xFF); + (*value)[3] = BlendFunction((blendFunctions >> 0) & 0xFF); + return result; +} + bool MaterialParser::getMaskThreshold(float* value) const noexcept { return mImpl.getFromSimpleChunk(ChunkType::MaterialMaskThreshold, value); } diff --git a/filament/src/MaterialParser.h b/filament/src/MaterialParser.h index 955c8b2a152..638e93d5662 100644 --- a/filament/src/MaterialParser.h +++ b/filament/src/MaterialParser.h @@ -102,6 +102,7 @@ class MaterialParser { bool getShading(Shading*) const noexcept; bool getBlendingMode(BlendingMode*) const noexcept; + bool getCustomBlendFunction(std::array*) const noexcept; bool getMaskThreshold(float*) const noexcept; bool getAlphaToCoverageSet(bool*) const noexcept; bool getAlphaToCoverage(bool*) const noexcept; diff --git a/filament/src/details/Material.cpp b/filament/src/details/Material.cpp index d1658103d0f..5deb07bd51b 100644 --- a/filament/src/details/Material.cpp +++ b/filament/src/details/Material.cpp @@ -323,6 +323,10 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder) parser->getMaskThreshold(&mMaskThreshold); } + if (mBlendingMode == BlendingMode::CUSTOM) { + parser->getCustomBlendFunction(&mCustomBlendFunctions); + } + if (mShading == Shading::UNLIT) { parser->hasShadowMultiplier(&mHasShadowMultiplier); } @@ -373,6 +377,12 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder) mRasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_COLOR; mRasterState.depthWrite = false; break; + case BlendingMode::CUSTOM: + mRasterState.blendFunctionSrcRGB = mCustomBlendFunctions[0]; + mRasterState.blendFunctionSrcAlpha = mCustomBlendFunctions[1]; + mRasterState.blendFunctionDstRGB = mCustomBlendFunctions[2]; + mRasterState.blendFunctionDstAlpha = mCustomBlendFunctions[3]; + mRasterState.depthWrite = false; } bool depthWriteSet = false; diff --git a/filament/src/details/Material.h b/filament/src/details/Material.h index 4de4bbb68a5..9bdd30ae01f 100644 --- a/filament/src/details/Material.h +++ b/filament/src/details/Material.h @@ -228,6 +228,7 @@ class FMaterial : public Material { Shading mShading = Shading::UNLIT; BlendingMode mBlendingMode = BlendingMode::OPAQUE; + std::array mCustomBlendFunctions = {}; Interpolation mInterpolation = Interpolation::SMOOTH; VertexDomain mVertexDomain = VertexDomain::OBJECT; MaterialDomain mMaterialDomain = MaterialDomain::SURFACE; diff --git a/libs/filabridge/include/filament/MaterialChunkType.h b/libs/filabridge/include/filament/MaterialChunkType.h index 6cff20039a1..27d50c1683a 100644 --- a/libs/filabridge/include/filament/MaterialChunkType.h +++ b/libs/filabridge/include/filament/MaterialChunkType.h @@ -59,6 +59,7 @@ enum UTILS_PUBLIC ChunkType : uint64_t { MaterialFeatureLevel = charTo64bitNum("MAT_FEAT"), MaterialShading = charTo64bitNum("MAT_SHAD"), MaterialBlendingMode = charTo64bitNum("MAT_BLEN"), + MaterialBlendFunction = charTo64bitNum("MAT_BLFN"), MaterialTransparencyMode = charTo64bitNum("MAT_TRMD"), MaterialMaskThreshold = charTo64bitNum("MAT_THRS"), MaterialShadowMultiplier = charTo64bitNum("MAT_SHML"), diff --git a/libs/filabridge/include/filament/MaterialEnums.h b/libs/filabridge/include/filament/MaterialEnums.h index ebe2ccce20e..9f348481895 100644 --- a/libs/filabridge/include/filament/MaterialEnums.h +++ b/libs/filabridge/include/filament/MaterialEnums.h @@ -80,6 +80,8 @@ enum class BlendingMode : uint8_t { MULTIPLY, //! material brightens what's behind it SCREEN, + //! custom blending function + CUSTOM, }; /** diff --git a/libs/filamat/include/filamat/MaterialBuilder.h b/libs/filamat/include/filamat/MaterialBuilder.h index 2e2d096309f..4b66965d746 100644 --- a/libs/filamat/include/filamat/MaterialBuilder.h +++ b/libs/filamat/include/filamat/MaterialBuilder.h @@ -227,6 +227,7 @@ class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase { using ShaderQuality = filament::ShaderQuality; using BlendingMode = filament::BlendingMode; + using BlendFunction = filament::backend::BlendFunction; using Shading = filament::Shading; using Interpolation = filament::Interpolation; using VertexDomain = filament::VertexDomain; @@ -407,6 +408,15 @@ class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase { */ MaterialBuilder& blending(BlendingMode blending) noexcept; + /** + * Set the blend function for this material. blending must be et to CUSTOM. + */ + MaterialBuilder& customBlendFunctions( + BlendFunction srcRGB, + BlendFunction srcA, + BlendFunction dstRGB, + BlendFunction dstA) noexcept; + /** * Set the blending mode of the post-lighting color for this material. * Only OPAQUE, TRANSPARENT and ADD are supported, the default is TRANSPARENT. @@ -828,6 +838,7 @@ class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase { FeatureLevel mFeatureLevel = FeatureLevel::FEATURE_LEVEL_1; BlendingMode mBlendingMode = BlendingMode::OPAQUE; BlendingMode mPostLightingBlendingMode = BlendingMode::TRANSPARENT; + std::array mCustomBlendFunctions = {}; CullingMode mCullingMode = CullingMode::BACK; Shading mShading = Shading::LIT; MaterialDomain mMaterialDomain = MaterialDomain::SURFACE; diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index 746c49caf3c..109d6e43da5 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -388,6 +388,16 @@ MaterialBuilder& MaterialBuilder::blending(BlendingMode blending) noexcept { return *this; } +MaterialBuilder& MaterialBuilder::customBlendFunctions( + BlendFunction srcRGB, BlendFunction srcA, + BlendFunction dstRGB, BlendFunction dstA) noexcept { + mCustomBlendFunctions[0] = srcRGB; + mCustomBlendFunctions[1] = srcA; + mCustomBlendFunctions[2] = dstRGB; + mCustomBlendFunctions[3] = dstA; + return *this; +} + MaterialBuilder& MaterialBuilder::postLightingBlending(BlendingMode blending) noexcept { mPostLightingBlendingMode = blending; return *this; @@ -1510,6 +1520,16 @@ void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo& container.emplace(ChunkType::MaterialDoubleSided, mDoubleSided); container.emplace(ChunkType::MaterialBlendingMode, static_cast(mBlendingMode)); + + if (mBlendingMode == BlendingMode::CUSTOM) { + uint32_t const blendFunctions = + (uint32_t(mCustomBlendFunctions[0]) << 24) | + (uint32_t(mCustomBlendFunctions[1]) << 16) | + (uint32_t(mCustomBlendFunctions[2]) << 8) | + (uint32_t(mCustomBlendFunctions[3]) << 0); + container.emplace< uint32_t >(ChunkType::MaterialBlendFunction, blendFunctions); + } + container.emplace(ChunkType::MaterialTransparencyMode, static_cast(mTransparencyMode)); container.emplace(ChunkType::MaterialReflectionMode, diff --git a/libs/filamat/src/shaders/ShaderGenerator.cpp b/libs/filamat/src/shaders/ShaderGenerator.cpp index af4f1198de9..92508566857 100644 --- a/libs/filamat/src/shaders/ShaderGenerator.cpp +++ b/libs/filamat/src/shaders/ShaderGenerator.cpp @@ -157,6 +157,9 @@ void ShaderGenerator::generateSurfaceMaterialVariantDefines(utils::io::sstream& case BlendingMode::SCREEN: CodeGenerator::generateDefine(out, "BLEND_MODE_SCREEN", true); break; + case BlendingMode::CUSTOM: + CodeGenerator::generateDefine(out, "BLEND_MODE_CUSTOM", true); + break; } switch (material.postLightingBlendingMode) { @@ -175,6 +178,9 @@ void ShaderGenerator::generateSurfaceMaterialVariantDefines(utils::io::sstream& case BlendingMode::SCREEN: CodeGenerator::generateDefine(out, "POST_LIGHTING_BLEND_MODE_SCREEN", true); break; + case BlendingMode::CUSTOM: + CodeGenerator::generateDefine(out, "POST_LIGHTING_BLEND_MODE_CUSTOM", true); + break; default: break; } diff --git a/libs/gltfio/src/UbershaderProvider.cpp b/libs/gltfio/src/UbershaderProvider.cpp index 8196273f232..7e184f648d4 100644 --- a/libs/gltfio/src/UbershaderProvider.cpp +++ b/libs/gltfio/src/UbershaderProvider.cpp @@ -338,6 +338,7 @@ const char* toString(BlendingMode blendingMode) noexcept { case BlendingMode::FADE: return "fade"; case BlendingMode::MULTIPLY: return "multiply"; case BlendingMode::SCREEN: return "screen"; + case BlendingMode::CUSTOM: return "custom"; } } diff --git a/libs/matdbg/src/CommonWriter.h b/libs/matdbg/src/CommonWriter.h index 6d2afc1ee4e..9e49df9a862 100644 --- a/libs/matdbg/src/CommonWriter.h +++ b/libs/matdbg/src/CommonWriter.h @@ -65,6 +65,7 @@ const char* toString(BlendingMode blendingMode) noexcept { case BlendingMode::FADE: return "fade"; case BlendingMode::MULTIPLY: return "multiply"; case BlendingMode::SCREEN: return "screen"; + case BlendingMode::CUSTOM: return "custom"; } return "--"; } diff --git a/libs/uberz/src/WritableArchive.cpp b/libs/uberz/src/WritableArchive.cpp index d7fface9472..09e601f8684 100644 --- a/libs/uberz/src/WritableArchive.cpp +++ b/libs/uberz/src/WritableArchive.cpp @@ -76,6 +76,8 @@ static string_view readBlendingMode(string_view cursor, BlendingMode* blending) *blending = BlendingMode::MULTIPLY; } else if (sz = readPrefix("screen"sv, cursor); sz > 0) { *blending = BlendingMode::SCREEN; + } else if (sz = readPrefix("custom"sv, cursor); sz > 0) { + *blending = BlendingMode::CUSTOM; } return { cursor.data(), sz }; } diff --git a/tools/matc/src/matc/ParametersProcessor.cpp b/tools/matc/src/matc/ParametersProcessor.cpp index 77a74fa9f93..828597e51a6 100644 --- a/tools/matc/src/matc/ParametersProcessor.cpp +++ b/tools/matc/src/matc/ParametersProcessor.cpp @@ -671,6 +671,7 @@ static bool processBlending(MaterialBuilder& builder, const JsonishValue& value) { "fade", MaterialBuilder::BlendingMode::FADE }, { "multiply", MaterialBuilder::BlendingMode::MULTIPLY }, { "screen", MaterialBuilder::BlendingMode::SCREEN }, + { "custom", MaterialBuilder::BlendingMode::CUSTOM }, }; auto jsonString = value.toJsonString(); if (!isStringValidEnum(strToEnum, jsonString->getString())) { @@ -681,6 +682,52 @@ static bool processBlending(MaterialBuilder& builder, const JsonishValue& value) return true; } +static bool processBlendFunction(MaterialBuilder& builder, const JsonishValue& value) { + static const std::unordered_map strToEnum{ + { "zero", MaterialBuilder::BlendFunction::ZERO }, + { "one", MaterialBuilder::BlendFunction::ONE }, + { "srcColor", MaterialBuilder::BlendFunction::SRC_COLOR }, + { "oneMinusSrcColor", MaterialBuilder::BlendFunction::ONE_MINUS_SRC_COLOR }, + { "dstColor", MaterialBuilder::BlendFunction::DST_COLOR }, + { "oneMinusDstColor", MaterialBuilder::BlendFunction::ONE_MINUS_DST_COLOR }, + { "srcAlpha", MaterialBuilder::BlendFunction::SRC_ALPHA }, + { "oneMinusSrcAlpha", MaterialBuilder::BlendFunction::ONE_MINUS_SRC_ALPHA }, + { "dstAlpha", MaterialBuilder::BlendFunction::DST_ALPHA }, + { "oneMinusDstAlpha", MaterialBuilder::BlendFunction::ONE_MINUS_DST_ALPHA }, + { "srcAlphaSaturate", MaterialBuilder::BlendFunction::SRC_ALPHA_SATURATE }, + }; + + if (value.getType() != JsonishValue::Type::OBJECT) { + std::cerr << "blendFunction must be an OBJECT." << std::endl; + } + + JsonishObject const* const jsonObject = value.toJsonObject(); + + MaterialBuilder::BlendFunction srcRGB, srcA, dstRGB, dstA; + std::pair functions[] = { + { "srcRGB", &srcRGB }, + { "srcA", &srcA }, + { "dstRGB", &dstRGB }, + { "dstA", &dstA }, + }; + + for (auto&& entry : functions) { + const char* key = entry.first; + const JsonishValue* v = jsonObject->getValue(key); + if (!v) { + std::cerr << "blendFunction: entry without '" << key << "' key." << std::endl; + return false; + } + if (v->getType() != JsonishValue::STRING) { + std::cerr << "blendFunction: '" << key << "' value must be STRING." << std::endl; + return false; + } + *entry.second = stringToEnum(strToEnum, v->toJsonString()->getString()); + } + builder.customBlendFunctions(srcRGB, srcA, dstRGB, dstA); + return true; +} + static bool processPostLightingBlending(MaterialBuilder& builder, const JsonishValue& value) { static const std::unordered_map strToEnum { { "add", MaterialBuilder::BlendingMode::ADD }, @@ -1194,6 +1241,7 @@ ParametersProcessor::ParametersProcessor() { mParameters["variables"] = { &processVariables, Type::ARRAY }; mParameters["requires"] = { &processRequires, Type::ARRAY }; mParameters["blending"] = { &processBlending, Type::STRING }; + mParameters["blendFunction"] = { &processBlendFunction, Type::OBJECT }; mParameters["postLightingBlending"] = { &processPostLightingBlending, Type::STRING }; mParameters["vertexDomain"] = { &processVertexDomain, Type::STRING }; mParameters["culling"] = { &processCulling, Type::STRING }; From 3ec2b47df7f22b95bae7e7e16d520e3edbae736f Mon Sep 17 00:00:00 2001 From: Benjamin Doherty Date: Mon, 1 Apr 2024 16:44:32 -0700 Subject: [PATCH 07/10] Release Filament 1.51.2 --- README.md | 4 ++-- RELEASE_NOTES.md | 3 +++ android/gradle.properties | 2 +- ios/CocoaPods/Filament.podspec | 4 ++-- web/filament-js/package.json | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a1dc91cdc6b..f2e6856085d 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.51.1' + implementation 'com.google.android.filament:filament-android:1.51.2' } ``` @@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`: iOS projects can use CocoaPods to install the latest release: ```shell -pod 'Filament', '~> 1.51.1' +pod 'Filament', '~> 1.51.2' ``` ### Snapshots diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index d60e6d45843..8cb9157a994 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,6 +7,9 @@ A new header is inserted each time a *tag* is created. Instead, if you are authoring a PR for the main branch, add your release note to [NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md). +## v1.51.3 + + ## v1.51.2 - engine: Add experimental APIs `Engine::builder::paused()` and `Engine::setPaused()` diff --git a/android/gradle.properties b/android/gradle.properties index 685dd260796..c677c8262ab 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.51.1 +VERSION_NAME=1.51.2 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index b51a82ab371..3ed06a44db5 100644 --- a/ios/CocoaPods/Filament.podspec +++ b/ios/CocoaPods/Filament.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = "Filament" - spec.version = "1.51.1" + spec.version = "1.51.2" spec.license = { :type => "Apache 2.0", :file => "LICENSE" } spec.homepage = "https://google.github.io/filament" spec.authors = "Google LLC." spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL." spec.platform = :ios, "11.0" - spec.source = { :http => "https://github.com/google/filament/releases/download/v1.51.1/filament-v1.51.1-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.51.2/filament-v1.51.2-ios.tgz" } # Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon. spec.pod_target_xcconfig = { diff --git a/web/filament-js/package.json b/web/filament-js/package.json index 7f24bbdf4a6..62fb8be635a 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.51.1", + "version": "1.51.2", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js", From 81658541a13dc96aed5aaffb020f178013fa9bbb Mon Sep 17 00:00:00 2001 From: Benjamin Doherty Date: Mon, 1 Apr 2024 16:44:40 -0700 Subject: [PATCH 08/10] Bump version to 1.51.3 --- README.md | 4 ++-- android/gradle.properties | 2 +- ios/CocoaPods/Filament.podspec | 4 ++-- web/filament-js/package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f2e6856085d..9fc2f823a5a 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.51.2' + implementation 'com.google.android.filament:filament-android:1.51.3' } ``` @@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`: iOS projects can use CocoaPods to install the latest release: ```shell -pod 'Filament', '~> 1.51.2' +pod 'Filament', '~> 1.51.3' ``` ### Snapshots diff --git a/android/gradle.properties b/android/gradle.properties index c677c8262ab..187e11e9c1f 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.51.2 +VERSION_NAME=1.51.3 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index 3ed06a44db5..8543885f0a3 100644 --- a/ios/CocoaPods/Filament.podspec +++ b/ios/CocoaPods/Filament.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = "Filament" - spec.version = "1.51.2" + spec.version = "1.51.3" spec.license = { :type => "Apache 2.0", :file => "LICENSE" } spec.homepage = "https://google.github.io/filament" spec.authors = "Google LLC." spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL." spec.platform = :ios, "11.0" - spec.source = { :http => "https://github.com/google/filament/releases/download/v1.51.2/filament-v1.51.2-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.51.3/filament-v1.51.3-ios.tgz" } # Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon. spec.pod_target_xcconfig = { diff --git a/web/filament-js/package.json b/web/filament-js/package.json index 62fb8be635a..b114a397027 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.51.2", + "version": "1.51.3", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js", From d468303bc932e213c17c8cb54ef8de89883cd536 Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Fri, 5 Apr 2024 17:49:56 -0700 Subject: [PATCH 09/10] Export utils::panic function (#7740) --- libs/utils/include/utils/debug.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/utils/include/utils/debug.h b/libs/utils/include/utils/debug.h index 4c118725177..0f6ecdb27e1 100644 --- a/libs/utils/include/utils/debug.h +++ b/libs/utils/include/utils/debug.h @@ -20,6 +20,7 @@ #include namespace utils { +UTILS_PUBLIC void panic(const char *func, const char * file, int line, const char *assertion) noexcept; } // namespace filament From de1edbdf2590612e415a37d1763ce1d13d844fd9 Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Fri, 5 Apr 2024 17:50:07 -0700 Subject: [PATCH 10/10] Metal re-apply: throw an NSException when attempting to draw with invalid program (#7741) --- filament/backend/src/metal/MetalDriver.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index f0e23ccb033..f99a6b63a66 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -1634,7 +1634,7 @@ return; } - ASSERT_PRECONDITION(bool(functions), "Attempting to bind an invalid Metal program."); + functions.validate(); auto [fragment, vertex] = functions.getRasterFunctions();