- Added `copyRange()` to `StructureOfArrays` to efficiently copy a range
of elements from another SoA of the same type. It uses `std::copy_n`
which leverages `memcpy` for trivially copyable types.
- Added `operator[]` to `StructureOfArrays` returning `IteratorValueRef`.
- Added `operator=` for `Structure` (tuple) to `IteratorValueRef` to
allow direct assignment: `soa[i] = tuple`.
- Added unit tests for these new methods in `test_StructureOfArrays.cpp`.
* Implement batch callback system for scene cache incremental updates.
This change adds a batch callback mechanism to track changes in component
managers and the entity manager, avoiding full cache rebuilds in the
future scene cache implementation.
1. SingleInstanceComponentManager:
- Added SingleInstanceComponentManagerBase to handle callbacks without
template bloat.
- Implemented batch delivery using Slice<const Entity> and a fixed-size
array of 16 for dirty entities to avoid heap allocations.
- Added compile-time option for sorted insertion (default to linear).
2. Manager Integration:
- RenderableManager: Added notifications to setters.
- LightManager: Added notifications to setters
- TransformManager: Handled transactions by deferring notifications
until commit, and supported hierarchical updates in children.
3. EntityManager:
- Added a new batching callback API for entity destruction.
- Used std::function for callbacks to allow thread-safe copying of the
callback list outside the lock.
- Simple accumulation in loop and flush when full, no bypass.
4. Tests:
- Added formal unit tests for all managers and entity manager callbacks.
* Implement grid-based world origin snapping in View
Implement a grid-based world origin snapping system in View to avoid
per-frame transform updates in the future. This will allow to
improve CPU performance and to enable future caching of acceleration
structures like BVH.
The feature is protected by the 'view.enable_grid_based_world_origin'
feature flag. The grid size can be set
manually via View::setGridSize or calculated automatically as 10%
of the camera's far plane distance.
A 50% hysteresis ratio is applied to prevent rapid origin flipping
near grid edges.
Exposed the new API to Java and JavaScript bindings and added
unit tests in filament_test.cpp.
BUGS=[504726278]
* Refine grid-based world origin snapping implementation
Refine the grid-based world origin snapping in View with several
improvements:
1. Support Orthographic Projections:
Calculate automatic grid size using projection matrix elements,
working for both perspective and ortho without assuming positive
near plane.
2. Stable Automatic Grid Size:
Only update effective grid size when a position snap occurs.
This prevents instability when frustum scale changes smoothly.
3. Immediate Manual Override:
Force an immediate snap when user manually changes grid size.
Added test cases for ortho and auto-grid size in filament_test.cpp.
* Filament Error Handling Remediation and noexcept Cleanup
- Replaced assert_invariant with FILAMENT_CHECK_PRECONDITION in
Renderer::beginFrame for caller bugs.
- Removed noexcept from Camera::setCustomProjection to allow precondition
checks to throw.
- Removed noexcept from Texture and InstanceBuffer methods using precondition
checks.
- Documented silent clamping in View::setBloomOptions.
- Clarified comment in FrameGraphResources regarding preconditions.
- Refined MaterialInstance::commit to split texture loop into check and update
passes, preventing partial state changes on precondition failure.
* backend: Propagate backend thread exceptions to the main thread.
Introduce a mechanism to catch exceptions thrown on the backend thread and
rethrow them on the main thread. This prevents deadlocks and allows the
application to handle fatal backend failures gracefully.
- Consolidate synchronization primitives in DriverBase.
- Add mHasUnrecoverableError flag to interrupt blocked fence waits.
- Optimize waitForFence to avoid extra atomic reads in common paths.
- Propagate FenceStatus::ERROR across all backends.
- CommandBufferQueue now stores a std::exception_ptr when the backend fails.
- The backend enters a "zombie" state on failure, skipping further command
execution but allowing clean shutdown.
- Public APIs in Renderer and Engine now check for stored exceptions and
rethrow them, documented with @throws.
- Guarded by __EXCEPTIONS to ensure no overhead when exceptions are disabled.
- Add unit test for fence interruption and document new APIs.
BUGS=[407545700]
* feat: harden backend exceptions and add hasUnrecoverableFailure API
- Update Renderer::beginFrame() and Renderer::shouldRenderFrame() to
return false early if an unrecoverable backend exception has been
delivered to the main thread.
- Document the new return behavior for beginFrame() and
shouldRenderFrame() in Renderer.h.
- Add Engine::hasUnrecoverableFailure() to the public API to allow
apps to check for fatal errors without relying on exceptions.
- Implement hasUnrecoverableFailure() in FEngine by delegating to
CommandBufferQueue.
- Expose Engine::hasUnrecoverableFailure() to Java bindings
(Engine.java and JNI).
- Expose Engine::hasUnrecoverableFailure() to JavaScript bindings
(jsbindings.cpp).
* java: propagate C++ Panics & exceptions to JAVA
* a new tribool type in libutils (header only)
* Support `Engine::compile` overload to generate view-dependent variants
Implemented an `Engine::compile()` method to infer and generate shader
permutations directly based on feature states from a provided `View`
alongside `tribool` settings (skinning, shadowReceiver).
- Added a new `Material::compile()` overload that directly accepts
a precalculated `FixedCapacityVector<Variant>`, decoupling the
Material compilation process from specific feature flag checks.
FIXES=[468058969]
- Fix constant wrap-around: Define `BIT_COUNT`, `BITS_PER_WORD`, and
`WORD_COUNT` (fixed typo from `WORLD_COUNT`) as `size_t` rather than
`T` to prevent silent overflows on large bitsets using small integer
types.
- Fix NEON `all()` truncation: Remove the generic `T` cast to correctly
evaluate bounds across the full 64-bit vector lanes.
- Fix non-NEON `count()` overflow: Use a `size_t` accumulator rather
than `T` to prevent overflow when counting >255 bits on `uint8_t`
parameters.
- Fix NEON strict alignment UB: Enforce unconditional `alignas(16)` on
`storage` when `BIT_COUNT` satisfies 128-bit vector multiples, adding
a compile-time `static_assert` to ensure ABI expectations match NEON
load intrinsics.
- Remove dead masking code inside `firstSetBit()`.
libfilament (including libutils and libmath) are 100% std::string
free.
std::string is pulled in the .so (on android) through libc++ for
exception handling, even if we're not using them. There is not much
we can do here, but at least, it's not because of us!
utils::ostream still references it but only as an inline function,
so if the inline is not called, std::string won't be pulled in.
It's also referenced from Path.cpp, but that's not included in
libfilament.
On certain linux, macOS environment, there is already a system
getopt. This often creates conflict when compiling filament.
Here we alias utils::getopt to either the system getopt (if
present) or third_party/getopt.
Fixes#7551
* utils: add LRU cache to RefCountedMap
This change introduces a new data structure LruCache and uses it in
RefCountedMap to keep a fixed number of cache entries alive after their
reference count has dropped to zero in the main map.
* utils: address LRU cache comments
Instead of computing the fog "inline", in the forward pass, we can
instead compute it as post-process pass that is applied with a
simple fullscreen quad blending. On tilers, the operation entirely
stays in the tile, on desktop GPU it is a blending operation.
This works only for opaque materials.
The benefit is that fog will become immune to overdraw, and the forward
pass shader will be simplified, hopefully leading to less register
pressure. Overall performance should be improved.
Another benefit is that it will allow us to free the "fog" texture
slot from all opaque materials.
Transparent materials are unchanged.
This feature is currently DISABLED, and still work in progress; but it
should be mostly functional.
To test it:
```
env material.enable_fog_as_postprocess=true ./out/samples/gltf_viewer
```
This change refactor the fog code, but shouldn't have any impact on the
current behavior.
* engine: add program cache
This is another chunky change.
The core of this change is to cache programs in MaterialCache according to a
"specialization" (ProgramSpecialization) which is defined as the program cache
ID (the same key used for the OpenGL binary blob cache), the variant, and the
set of spec constants.
As part of this change, a lot of the implementation details of shader
compilation were refactored from Material to MaterialDefinition. The resulting
flow is a lot cleaner and easier to reason about, since shader compilation is
now a pure function of the MaterialDefinition + ProgramSpecialization.
Since the global cache program lookups might take a bit of time to compute
hashes, etc, I left the set of cached programs in Material as well, which kind
of acts like an L1 cache. The effect is that prepareProgram() and getProgram()
should be no slower than HEAD, even with the more complex caching requirements.
I'm planning on writing a document about this (and all changes up until this
point), but I'm being asked to work on higher priority things and I wanted to
have this PR out for review in the meantime so it doesn't bitrot.
* engine: fix unit tests
* engine: fix spec constants intern pool memory leak
* engine: address program cache comments
* engine: address more program cache comments
* engine: matdbg support for program cache
* engine: reinstate descriptorLayout calls
* engine: address bitrot
* engine: add feature flag to disable program cache
* engine: use material CRC32 for program cache
The "cache ID" of a material is supposed to uniquely identify a shader program
and all its variants. This is true to a certain extent, but does not account for
the code generation that happens at runtime. Two materials may have "identical"
shader programs, but due to each material's differing unique metadata, the final
compiled programs may end up very different. Unfortunately, this means we cannot
rely on the "cache ID" alone to determine a shader program's reusability.
Ideally, we should hash this "cache ID" with the exact set of changes to each
shader program so that we could reuse programs across materials. Instead, as a
stopgap solution, use the material's CRC32 instead.
* engine: fix double-free in program cache
* engine: address comments
* engine: assert_invariant empty material cache
PerformanceHint manager needs a java thread during initialization,
so we need to attach a jvm to the thread that's going to be used.
That thread is the filament backend thread, not necessarily the thread
the platform is created on.
So we make sure to do that from the backend thread.
FIXES=[427945768]
* feat(engine): Add automatic frame skipping to manage CPU/GPU latency
Introduces a new feature, disabled by default, that allows the engine to automatically skip frames when the CPU gets too far ahead of the display's refresh rate. This helps to reduce overall latency by preventing a backlog of frames from building up in the driver queue.
The feature can be enabled with the "engine.skip_frame_when_cpu_ahead_of_display" property.
To implement this, the compositor timing mechanism has been refactored. Instead of reporting an absolute `expectedPresentTime`, the backend now provides an `expectedPresentLatency` relative to vsync. This is more robust against synchronization issues with platform callbacks (like Android's Choreographer), as the latency is generally a constant value.
BUGS=[474599530]
This commit clarifies and corrects documentation in several public header
files. The changes include fixing typos, improving wording, and adding
missing details to make the API easier to understand and use.
No functional changes are included in this commit.
* split FeatureFlagManager out of FEngine
- Separate the Feature flags management from FEngine.
- Make FeatureFlagManager available to backends through DriverConfig
- add a way to override a feature flag value at runtime using
environment variables or system properties (on Android).
e.g.:
```
env "feature.name=true" gltf_viewer
```
or
```
adb shell setprop debug.feature.name true
```
Co-authored-by: Powei Feng <powei@google.com>
This commit introduces async methods and functions across both the
public and backend APIs, enabling non-blocking creation and updates for
Texture, VertexBuffer, and IndexBuffer resources.
Asynchronous resource management is disabled by default. Users should
enable this to use the feature.
Java bindings and a C++ code sample will follow in subsequent PRs.
BUGS=[442921995]
The "const char*" used for the string literal parameter of the `feature`
method becomes invalid once it passes outside the Java binding scope,
leading to invalid data access. This fix ensures the string is safely
stored.
Add support for heterogeneous lookup in associative containers that
use CString keys. Add conversion operators for std::string_view and
raw string literals to CString.
The frameId coming from a Renderer must be monotonic when seen from
a SwapChain (Specifically a ANativeWindow on Android), if it's not
the case, we must clear that part of the history.
This can happen if a SwapChain is used with two different Renderer; at
this point that SwapChain's history is no longer connected to that
Renderer.
* HandleAllocator::deallocate() was unsafe
It needs to know the concrete type to call the proper destructor, so
if it was given a base type handle (e.g. Handle<HwFoo>) it would not
destroy it properly.
* add AsyncJobQueue::cancelAll()
* Fix a race condition when tearing down FrameInfo
It is actually invalid to destroy a Handle<HwFence> while inside
fenceWait().
Updated the HwFence implementations so that they don't pretend they can
handle being destroyed during fenceWait(), they can't.
FrameInfo now cancels all the pending callbacks and waits for the
currently executing one to terminate, *before* destroying the
handles.
Reenable the gpuFrameComplete metric, as it should be working now.
* Use a custom, non-allocating map for frame ids
* use memory_order_relaxed for the id of heap allocated handles
* Added displayPresent time to FrameInfo
To do this, we added support for queryFrameTiming() to the backend,
as a synchronous API. Then FrameInfo uses it to update the
corresponding history entry.
displayPresent time can be used to detect "buffer stuffing", i.e.
when the GPU gets too much ahead of the display. Currently
the information is returned to the user only. Eventually filament will
make use of it to determine if a frame skip is mandated.
* API BREAK: rename frameTime to gpuFrameDuration
* FrameInfo now contains compositor timings
- the presentation deadline
- the refresh rate from the display
- the composition-display latency
* set FrameInfo data to INVALID if feature is not supported
report presentDeadline properly.
* Add missing includes.
* Add parenthesis around operators to suppress compiler warning.
* Remove duplicate definition of is_supported_aux_t.
* Explicitly create descriptions.
* Remove usage of anonymous struct with non-trivially constructible members.
This is an error on some compilers (e.g. gcc).
* Remove unnecessary rvalue-reference on pointer type.
* Explicitly construct SamplerParams to suppress compiler warnings.
* Place attribute specifier before declaration.
* Remove usage of anonymous struct with a non-trivially constructible member.
Replace the `array` union member with an `operator[]` to provide similar
functionality.
Some compilers (e.g. gcc) do not support this non-standard use-case.
* Use same warning settings as main filament project.
* fix a possible deadlock in AsyncJobQueue
drainAndExit() could get stuck because it waited for the job
queue to be empty, but that was not signaled.
in fact, drainAndExit() didn't need to do that.
* Improvements to FrameInfo
- return the GPU Complete timestamp
- return the app VSYNC timestamp
- works TimerQueries are not supported
The VSYNC time is just a convenience as it is the same value
provided by the application during Renderer::beginFrame() or via
Renderer::setVsyncTime().
* Make JsonishParser use utils::Status
- add unsupported error in utils::Status
- add invalid case in the test
* return a pair of Status and string in resolveEscapes;
use initializer list for JsonishString and move that to the header.
* Use utils::Status in MaterialParser
* Use utils::sstream instead of std::stringstream
* Remove remaining std::cerr and dep; update MaterialParser::reflectParameters
* make error message in utils::Status more generic
---------
Co-authored-by: Powei Feng <powei@google.com>
ImmutableCString is a string class similar to CString except it's
immutable. ImmutableCString occupies 16 bytes instead of 8 for CString.
However, ImmutableCString is able to avoid memory allocation when
constructed from a string literal, and in that way it us similar
to StaticString.
ImmutableCString can be auto converted from StaticString.
The backend tag tracking is updated to use ImmutableCString and
the FrameGraph resource manager us updated to use StaticString.
Together these changes significantly cut down heap allocations due to
internal tagging.
We also add optional tracking to {Immutable}CString.
* Minor changes in utils::Status
- << operator doesn't have to be friend
- simplify getErrorMessage to not use strlen internally
* Replace std::ostream to utils::io::ostream
* utils: RefCountedInternPool/RefCountedMap
First, introduce RefCountedInternPool, a reference counted intern pool of
Slice<const T>. Just acquire() a slice that you want and you're guaranteed to
get exactly one canonical value-equal Slice<const T> back.
Additionally, introduce the concept of NullValue to RefCountedMap. A NullValue
defines what should be considered an uninitialized value; by default, it's the
default value of that type (0 for ints, nullptr for pointers, etc). This allows
us to lazily-initialize values in the map. A client can acquire() a bunch of
different resources which will be initialized only when get(factory) is called.
If a client attempts to get() a value without specifying a factory, and the
value is not initialized (i.e. equal to NullValue{}()), RefCountedMap will
panic.
* utils: add unit tests for ref-counted collections
* utils: remove C++20 features, fix memory issue
* utils: remove RefCounted from InternPool
* slice: fix memory semantics
* slice: prefer passing slice by value
This lets us do nice things like coercing Slice<T> to Slice<const T>, etc.
* slice: fix unit tests
* slice: fix copy/assignment, hash function
Don't attempt to define a copy constructor/assignment operator which would
convert a constant type to a mutable type.
Additionally, fix the hash function such that we're hashing U instead of const
U.
* new utility AsyncJobQueue
this is a very simple job queue, it spawns a thread and runs the jobs
pushed to the queue in sequence.
* use AsyncJobQueue in OpenGLTimerQuery