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
* materials: introduce MaterialCache
Presently, Filament Materials are instantiated by first parsing a bunch of
read-only data from a material file, then applying a bunch of options from its
Builder before settling on a final, immutable Material object. If two different
Material instances need to be parameterized differently, e.g. setting their spec
constants independently, each has to do all of these steps independently for
each variation.
This change introduces two new concepts: MaterialDefinition, representing the
deserialized, read-only state of a material file, and MaterialCache, a
reference-counted system responsible for managing the lifetimes of
MaterialDefinitions. Now, each Material asks the cache if a MaterialDefinition
exists for the particular UUID of the data it's trying to read; if not,
MaterialCache creates a new entry transparently. If a hundred different
Materials all try to load the same material data, only one
MaterialDefinition (and its associated GPU resources) will be created.
This first PR is the least possible invasive implementation of this feature.
There are a lot of room for improvements (and more planned). For example, each
Material still manages its own compiled shader program cache, but we can easily
move this to the MaterialCache in future PRs, further enabling the planned
mutable spec constants feature.
Additionally, there's room here to add a Material::toBuilder() method, which
could take an extant material and create a Builder object from it already
parameterized with all of the same options, a la the prototype design pattern.
* material cache: key on crc32
* material cache: make materialParser private
* move RefCountedMap to utils and add unit tests
* material cache: make create functions private
* material cache: fix broken tests on iOS/web
* material cache: address more comments
The new cmake FILAMENT_ENABLE_PERFETTO must be set to enable
perfetto traces on Android. It is disabled by default on release
builds, enabled otherwise.
The reason for this is that the perfetto SDK adds about 800K of code
to the library. The text section goes from 2.2 to 1.4 MB
- libbackend (except webgpu)
- libfilament
- libutils
std::string generates a lot of code bloat, we use CString instead.
We also update CString to be more compatible with std::string's api.
This commit introduces a CRC32 checksum to material packages to ensure
data integrity.
When a material is loaded, this checksum is verified. If the check
fails, an error is logged, and the material fails to load. For older
material packages without a CRC32 checksum, a warning is logged and
proceed.
BUGS=[373396840]
We link the behavior of certain precondition/postcondition checks to feature flag states.
- If provided *flag* is true, then this macro will assert when the *condition* is false.
- If provided *flag* is fase, then this macro will output a warning when the condition is false.
- If the condition is true, then neither of the above will happen
These two macros will enable us to provide less restrictive behavior for certain correctness assertions, allowing clients to modify their before enabling these assertions by default.