Compare commits

..
Author SHA1 Message Date
Sungun Park 7017bde04d Optimize thread variables in ServiceThread
Wraps thread-related member variables in preprocessor checks to ensure
they are excluded when multithreading is not supported. Previously,
these variables were declared unconditionally, leading to unnecessary
memory usage for platforms that don't support multithreading.
2026-01-20 07:42:15 -08:00
Sungun Park 7701e7a65a Handle deferred destruction for asynchronous objects (#9604)
When an asynchronous object is destroyed immediately after creation, the
background creation process may still be active, holding a reference to
the object. We now defer destruction in these cases until the creation
process completes to ensure the reference remains valid.

Implementation details:
1. Add a mechanism to stop the ServiceThread to drain pending
   asynchronous tasks earlier. This ensures the mCreationComplete flag
   in the frontend object is set to true.
2. Later, the engine's terminate performs garbage collection for the
   deferred destruction. All of them must be successfully processed.

BUGS=[442921995]
2026-01-17 02:44:28 +00:00
Filament Bot 65a91832a8 [automated] Updating /docs due to commit acb47ff
Full commit hash is acb47ffed5

DOCS_ALLOW_DIRECT_EDITS
2026-01-16 00:26:35 +00:00
Powei Feng acb47ffed5 Release Filament 1.68.4 2026-01-15 16:21:37 -08:00
Filament Bot 13c0304d84 [automated] Updating /docs due to commit febdf39
Full commit hash is febdf3974c

DOCS_ALLOW_DIRECT_EDITS
2026-01-15 23:24:29 +00:00
Powei Feng febdf3974c docs: improve release and test documentation (#9609)
- Reorder the release-related documents into one heading.
 - Added CocoaPods README as part of the documentation.
 - Fixed typo for renderdiff doc
 - Added backend test doc
2026-01-15 23:22:00 +00:00
Powei Feng 390acec928 vk: add feature flag for acquiring swapchain in makeCurrent (#9610)
Removing this behavior in #9541 caused a breakage in one of our
clients. We use a feature flag to enable the old behavior.

BUGS=476144715
2026-01-15 22:48:12 +00:00
Powei Feng ff806f8c3e Misc fixes to address old compiler errors (#9611)
Certain older compilers (e.g. clang in NDK 25.1.8937393) cannot
handle the c++ stylistic changes that were recently added
(though they are correct by spec).

 - In Engine.cpp, .find() cannot automatically infer the right type
   (std::string_view vs. utils::CString).
 - In fg/framegraph, various templated short-hands still require
   typename.
2026-01-15 20:27:26 +00:00
Powei Feng 06c4faabc3 vk: disable pushconstant backend test for CI
Due to flakiness.
2026-01-15 11:36:46 -08:00
Powei Feng 92aec16fa3 Add comment to indicate TextureFormat value (#9608)
This will help with debugging if we needed to print out a
TextureFormat value.
2026-01-15 19:21:39 +00:00
Mathias Agopian f1ffb783d8 feat(engine): Add automatic frame skipping to manage CPU/GPU latency (#9595)
* 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]
2026-01-15 09:50:56 -08:00
Mathias Agopian b708300586 Refactor implicit DriverApi dependency (#9606)
Removed implicit dependency on FEngine::getDriverApi() in critical 
rendering paths. This change makes the DriverApi dependency explicit by 
passing it as a parameter.


Key changes:

- FRenderer: Now accepts DriverApi& in renderInternal and renderJob. 
Caches feature levels and capability flags in the constructor.

- PostProcessManager: Caches feature flags and workaround flags in 
init(). Updated PostProcessMaterial and configure* methods to accept 
DriverApi&.

- FMaterial: Caches support flags (stereo, parallel shader compile) and
default material pointer in the constructor. 
Updated precacheDepthVariants and prepareProgram to rely on these 
cached values or passed parameters.

- ShadowMapManager: Caches workaround flags in the constructor.

- FEngine: Updated prepare() to accept DriverApi&.

- RenderPass: Updated to accept DriverApi& in constructor and 
appendCommands.

- Removed implicit DriverApi calls from hot paths to reduce overhead 
and improve safety.


One common pattern in this change is to cache getters in constructors
so that we don't need the DriverApi dependency later during rendering.
The intention here is to remove DriverApi& from as many places as
possible so that we can later have multithreading for command
recording.

This PR should not change any behavior.
2026-01-15 09:11:12 -08:00
HanYunChenLuo f88d757d06 Add glibc check to support build filament on Linux musl-based distrib… (#9592) 2026-01-14 23:22:07 +00:00
Powei Feng 4d96f188d1 backend: CallbackHandler dstor inlined in header (#9605)
Defining the destructor in a cpp will break downstream clients.

The previous move to cpp was part of #9508.
2026-01-14 22:22:10 +00:00
Powei Feng 2d943f40bb vk: fix push constant implementation and test (#9588)
All stages share a push constant "block". We need to order
the fragment stage bytes to after the vertex stage if they
both exists.

FIXES=453776664
2026-01-14 18:18:04 +00:00
Doris Wu 92c058a736 fix gtao shader on mobile (#9591) 2026-01-13 14:11:34 +00:00
Mathias Agopian ba819bcfca Docs: Improve documentation in public headers (#9603)
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.
2026-01-12 14:31:42 -08:00
Mathias AgopianandPowei Feng e22f1adfa7 make "native streams" deprecated (#9602)
Co-authored-by: Powei Feng <powei@google.com>
2026-01-12 14:31:15 -08:00
Anish Goyal f2bca03360 Add external format to cache prewarming (#9558)
Provides logic to load and check for external format ids, and
build fake pipelines against them when relevant, to prevent
hitching when using external formats.

For now, we're going to use upto five likely types of YCbCr
conversions, which seem to cover all usecases encountered. This
means we might compile pipelines with external samplers a total of
4 additional times on top of the baseline (5 in total), or 3 additional
times on the devices we're currently testing (4 in total).

* Add base pipeline prewarm call for ext samplers

This is necessary because in some cases, a material that supports
external samplers will use RGB inputs instead of YCbCr inputs, and will
miss the cache.
2026-01-12 19:32:01 +00:00
Ben Doherty 5f07d701f0 Fix CocoaPods build (#9597) 2026-01-12 10:20:51 -08:00
Mathias Agopian 496a50bc89 make getWorldFromModelMatrix() accessible in fragment shader (#9584)
this requires to specify `apiLevel: 2` in the material.

FIXES=[474353927]
2026-01-12 09:32:23 -08:00
Mathias AgopianandPowei Feng 6ccb6c4cce split FeatureFlagManager out of FEngine (#9596)
* 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>
2026-01-12 09:31:51 -08:00
Powei Feng 42c78fd0a9 github: refactor postsubmit CI tasks into single yml (#9587) 2026-01-12 17:28:53 +00:00
Doris Wu 3d0e2923ae Fix VB-GTAO on remote webui (#9599) 2026-01-12 19:10:30 +09:00
Mathias Agopian 408b2371f0 allow FILAMENT_TRACING_CALL to take extra parameters (#9593) 2026-01-09 15:08:27 -08:00
Powei Feng 6ea08b40a8 gl: small fixes to push constant implementation and test (#9594)
- Add code for handling empty/null constant name
 - Use glUniform1ui() instead of glUniform1i() to workaround
   crash on macbook pro (m4).
 - Fully specify the constant name in the test (e.g.
   `pushConstantsF.red` instead of `red`).
 - Make sure that the uniform names are different between
   vertex and fragment in the test. This is due to different
   constant structs being defined between the two stages.

FIXES=453757504
2026-01-09 14:48:52 -08:00
Doris Wu 5eb0f7d3ec Fix the vbotest sample (#9581)
* set clear to true

* feedback
2026-01-09 10:15:44 +08:00
Powei Feng d465d59c3a github: run filament tests in presbumit (#9586) 2026-01-08 21:25:58 +00:00
Filament Bot af9a60d175 [automated] Updating /docs due to commit 8e0f0c9
Full commit hash is 8e0f0c92ce

DOCS_ALLOW_DIRECT_EDITS
2026-01-08 20:19:49 +00:00
Benjamin Doherty 8e0f0c92ce Release Filament 1.68.3 2026-01-08 12:14:07 -08:00
Anish Goyal 5a14fb4b5d Cache prewarm base case (#9552)
Prevents hitching for most pipelines, on certain devices with Turnip-based drivers

This does not address external samplers yet. This simply handles the
case where we want to prewarm a pipeline with the base configuration.

Refactor program's descriptor set layout bindings, clean up some leaking
resources
2026-01-08 11:43:32 -08:00
dependabot[bot] 22a1aacb21 Bump urllib3 in /docs_src/build in the pip group across 1 directory (#9585)
Bumps the pip group with 1 update in the /docs_src/build directory: [urllib3](https://github.com/urllib3/urllib3).


Updates `urllib3` from 2.6.0 to 2.6.3
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.6.0...2.6.3)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.6.3
  dependency-type: direct:production
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-08 18:48:08 +00:00
dependabot[bot] e5b6c11399 Bump urllib3 in /test/renderdiff/src in the pip group across 1 directory (#9582)
Bumps the pip group with 1 update in the /test/renderdiff/src directory: [urllib3](https://github.com/urllib3/urllib3).


Updates `urllib3` from 2.6.0 to 2.6.3
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.6.0...2.6.3)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.6.3
  dependency-type: direct:production
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-08 10:28:15 -08:00
Mathias Agopian 85ebd67a28 feat(taa): Overhaul TAA implementation for improved quality and upscaling (#9573)
This commit introduces a significant rework of the Temporal Anti-Aliasing (TAA) system, focusing on improving reconstruction quality, robustness, and introducing flexible upscaling.

Core TAA Algorithm improvements:
- Replaced the Catmull-Rom filter with a more efficient 5-tap Lanczos filter for history sampling, which includes deringing to reduce artifacts.
- The input color buffer is now properly "unjittered" using a Lanczos reconstruction filter.
- Improved the history rejection algorithm by skipping the expensive accurate clipping when the history sample is already within the neighborhood's color gamut.
- Added a new `hdr` option to properly handle HDR content by tonemapping colors before blending and untonemapping the result.
- Removed the ineffective `VARIANCE` only history rejection method.
- Added protection against negative numbers in `sqrt()` for increased stability.

TAA Upscaling:
- Replaced the boolean `upscaling` flag with a float factor, allowing for variable upscaling ratios (e.g., 1.5x, 2x).
- Upscaling now correctly adjusts viewport and projection settings.
- The TAA shader now receives viewport and resolution information to correctly handle upscaled rendering.

API and Configuration Changes:
- Deprecated the `filterWidth` TAA option as it no longer has an effect.
- Introduced the `upscaling` float property to `TemporalAntiAliasingOptions`.
- Added the `hdr` boolean property to `TemporalAntiAliasingOptions`.

Other Changes:
- Updated UI elements in the viewer and material sandbox to reflect the new TAA options.
- Updated Javascript bindings and TypeScript definitions for the new TAA settings.
- Refactored shader code for clarity and performance.
2026-01-07 15:25:38 -08:00
Powei Feng f33a779668 vk: move swapchain acquire() to as late as possible (#9541)
makeCurrent is not meant to acquire the swapchain; we should
do so at the momemnt we need it, to shorten the amount of time
a swapchain image/buffer needs to be held.
2026-01-07 18:36:54 +00:00
Sungun Park 1b5916b655 Rename AsyncCallbackType to AsyncCompletionCallback (#9579) 2026-01-07 18:18:49 +00:00
Anish Goyal d8720cd858 Rename DescriptorSetLayoutBinding to DescriptorSetLayoutDescriptor (#9576)
Since the struct refers to descriptors as opposed to specifically
bindings (although they do contain binding information as well), this
name is more appropriate.
2026-01-07 16:52:50 +00:00
Doris Wu 44636bddaa Split Skinning out of Visibility struct (#9575) 2026-01-07 11:37:42 +08:00
Sungun Park 1741723687 Add user parameter to runCommandAsync (#9577) 2026-01-06 18:37:42 -08:00
Mathias Agopian ad2c291d4a dispersion in XYZ space (#9572)
- spectral reconstructions with 4 samples
- unroll the whole dispersion computation to improve performance
  (batch texture fetches and reuse common values)
- tool to generate the matrices for spectral integration
2026-01-06 16:58:56 -08:00
Mathias Agopian 52ffd80041 Refactor FrameGraph pass API for flexibility (#9571)
This commit simplifies and unifies the FrameGraph's `addPass` API.
Key changes:
- The `addPass` method now uses a single, more flexible implementation
  that handles different lambda signatures for both the setup and
  execute stages.
- The execute lambda can now optionally omit the `DriverApi&` parameter,
  reducing boilerplate for simple passes.
- The `addTrivialSideEffectPass` helper has been removed.
  Side-effect-only passes can now be created directly with `addPass`
2026-01-06 14:20:47 -08:00
Doris Wu 44dde744ea Several optimizations for UBO batching (#9545) 2026-01-06 05:52:32 +00:00
Mathias Agopian c18ddf929e Improve frame_generator sample tool (#9570)
- Add support for vector parameters (float2, float3, float4) in the 
  parameters file using `{x, y, z}` syntax.
- Allow comments (`#`, `//`) and empty lines in the parameters file.
- Make the end value optional in the parameters file 
  (defaults to start value).
- Add `--size` / `-S` option to specify viewport dimensions.
- Optimize rendering by pre-filtering active material parameters.
- Remove hardcoded default parameters and silently ignore missing 
  parameters to support shared configuration files.
- Add documentation for the parameters file format.
2026-01-05 20:28:04 -08:00
Mathias Agopian 5661365248 improved the dispersion computation (#9544)
- Split the function so that the 3-components loop is more apparent.
- Factored out the parts of the computation that don't depend on the
index of refraction, so they're only computed once.
- Moved the lod-from-roughness computation out of the loop as well. 
  It does depend on the IOR, but so little that it's not worth it.

The most important result of this change is that the code is now in
good shape if we wanted to change the implementation of dispersion for
these cases (for e.g.) :
- do the computation in the XYZ space
- use more than 3 wavelengths samples
- or use a stochastic approach, trading banding for noise

RDIFF_BRANCH=ma/better-dispersion
2026-01-05 20:27:34 -08:00
Powei Feng bcb9d258c2 vk: fix broken android build (#9574)
Should use VK_NULL_HANDLE instead of nullptr where applicable
in VulkanPipelineCache.
2026-01-05 20:27:07 -08:00
Anish Goyal 53a94c4547 Add thread pool and callback manager / knobs for enabling + disabling prewarm (#9515)
* Update createPipeline to have pipeline key input
Right now, createPipeline in VulkanPipelineCache assumes that you are
building a pipeline using mPipelineRequirements as the key, and that it
should be stored in the cache. In the case of the pipeline prewarming
change, this is not going to be the case; sometimes, the pipeline will
be stored in the cache, and sometimes it will be deleted immediately.
Also, the prewarmed pipelines will be created using separately defined
keys.

* Add knobs for enabling / disabling prewarm

* Add thread pool to VulkanPipelineCache

* Fix dynamic rendering enablement check
Query device features to ensure it is supported / we don't just have the
extension. Also, proactively enable dynamic rendering when creating the
device.
2026-01-05 23:55:08 +00:00
Filament Bot 928ffe94a7 [automated] Updating /docs due to commit dcb78c7
Full commit hash is dcb78c7144

DOCS_ALLOW_DIRECT_EDITS
2026-01-05 21:56:49 +00:00
Mathias Agopian dcb78c7144 update dispersion documentation (#9567)
* add dispersion parameter to material_sandbox

* frame_generator fixes

- fix skybox
- for baseColor to white (workaround)

* update dispersion documentation source
2026-01-05 13:54:24 -08:00
Sungun Park 43dd8fa1cc Fix MockDriver (#9569)
This is missing changes from
https://github.com/google/filament/commit/0eff54b807d236ed0782be18b75412ccc3c0ce8f
2026-01-05 21:08:50 +00:00
Anish Goyal 91a5f00d30 Remove unnecessary log statement (#9568)
It is not an error for a device to not have this API.
2026-01-05 12:41:34 -08:00
Sungun Park 0eff54b807 Add async support check to backend (#9542)
BUGS=[442921995]
2026-01-05 20:10:36 +00:00
Lucas Leandro 68eb0ce3f1 Add java bindings for changing from default to screen-space reflection in real-time MaterialBuilder (#9548) 2026-01-05 11:44:54 -08:00
Benjamin SchulzandSungun Park 023318c08d Fixes "error: templates must have C++ linkage" when compiling with older clang versions. (#9562)
Co-authored-by: Sungun Park <sungunpark@google.com>
2026-01-05 11:43:54 -08:00
rafadevaiandSerge Metral c0e3aa2b0a VK: In UMA, apply the staging bypass for everything (#9538)
Currently only uniform buffers benefit from the bypass,
but this can also be extended to others buffers too.

This also help trying to match the performance of the
GL backend in Android.

FIXES=[470138463]

Co-authored-by: Serge Metral <sergemetral@google.com>
2026-01-05 11:36:54 -08:00
Anish Goyal a6d1b9188f Add descriptor set layouts to Program (#9522)
This will help later for parallel compilation
2026-01-05 18:59:07 +00:00
Sungun Park 43193c5ac5 Add missing async destruction for BufferObject and IndexBuffer (#9565)
As with Texture, now BufferObject and IndexBuffer will be destroyed via
the async queue if they were asynchronously created.

BUGS=[442921995]
2026-01-05 18:15:01 +00:00
Mathias Agopian 35c58047ee move the depth clear prepare into the framegraph (#9549)
depth clear prepare was done outside of the framegraph, it's now
moved into the colorpass prepare pass.
2026-01-03 15:04:51 -08:00
Mathias Agopian 2190f3544f fix build when FILAMENT_SUPPORTS_VULKAN is OFF (#9557) 2026-01-03 15:03:30 -08:00
Mathias Agopian fd8ea78e04 Fix TAA (#9556)
TAA had been broken for a while, the jitter was no longer applied.

We now compute the jittered camera before we set it into the 
per frame UBO.
2026-01-03 15:03:06 -08:00
Emily Banerjee 7fc336a6d9 Fix GCC type mismatch error in Platform::debugUpdateStat (#9563) 2026-01-02 09:48:28 -08:00
yein 3cc6fae5c0 Add api level enforcement (#9561)
Api level is now enforced when generating code by appending #defines of client requested and unstable apis.
This ensures that the client can only use unstable apis when they explicitly add `apiLevel` in their .mat file.

FIXES=468340631
2025-12-29 13:38:02 -08:00
yein f4f75da016 Fix garbage data getting added to the source material (#9553) 2025-12-26 09:29:13 -08:00
Filament Bot bdeba1aa86 [automated] Updating /docs due to commit 8991be4
Full commit hash is 8991be4eea

DOCS_ALLOW_DIRECT_EDITS
2025-12-24 00:55:04 +00:00
Ben Doherty 8991be4eea Fix incorrect GLSL types in Materials documentation (#9555) 2025-12-23 16:52:27 -08:00
yein 940b93ceb8 Replace slog to LOG (#9554) 2025-12-23 13:45:42 -08:00
Filament Bot 00eb3d0d4f [automated] Updating /docs due to commit 7f61eb7
Full commit hash is 7f61eb7a0a

DOCS_ALLOW_DIRECT_EDITS
2025-12-23 19:44:04 +00:00
Benn Herrera 7f61eb7a0a GLTFIO Webp Texture Support (#9406) 2025-12-23 11:40:01 -08:00
yein 53f506670c Add apiLevel and add parsing logic (#9535) 2025-12-22 13:52:32 -08:00
Mathias AgopianandPowei Feng 9fe7ab31ed Make FrameGraph resource management extensible (#9536)
* rename ResourceAllocator to TextureCache

This better represents what this class is for.

* Make FrameGraph resource management extensible

This refactors the FrameGraph's resource management to allow for 
user-defined custom resources.
 
A new `ResourceAllocator` template abstracts the creation and 
destruction of resources, with specializations for different resource 
types (e.g., generic, backend-dependent, textures). 
This removes hardcoded resource management logic from the `FrameGraph` 
execution loop.
 
A `ResourceCreationContext` is introduced to provide the necessary 
context for resource allocation.
 
Tests for generic and backend custom resources have been added to 
validate the new system.

* Update filament/src/fg/FrameGraphDummyLink.h

Co-authored-by: Powei Feng <powei@google.com>

---------

Co-authored-by: Powei Feng <powei@google.com>
2025-12-22 11:08:53 -08:00
Mathias Agopian 008534b8a2 Fix dispersion with uber-shaders (#9543)
Fixes #9540
2025-12-22 10:12:54 -08:00
Sungun Park 2c5842f908 Implement asynchronous resource management (#9508)
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]
2025-12-19 21:18:32 -08:00
Powei Feng a8ee9d473e android: fix texture rendertarget sample for vk (#9528)
- add a flag to run the sample using regular, non-external
   texture as render target.
 - Add a non-external version of the material
 - vk: fix y-flipping issue with uvToRenderTargetUV()
2025-12-19 22:15:22 +00:00
Mathias Agopian 1e3ab83e6a Remove the dependency of RenderPassBuilder on DriverApi (#9533)
The main goal of this CL is to break the dependency of RenderPassBuilder
on DriverApi. The dependency only existed for the auto-instancing 
feature, which needed to allocate and update a UBO on the fly.

We want to break that dependency so that RenderPassBuilder::build().
which is an expensive call, could run on a separate thread. In the
future this could allow, for example, shadow and ssao passes to 
run in parallel.

A new method RenderPass::finalize(DriverApi&) is added which *must* be 
called before calling getExecutor(), this is where the temporary
UBO is allocated and updated. We need a new method because this must be 
called on the main thread before a render pass is started.

This implementation stores the UBO data needed for instancing until
finalize() is called, if any.

We introduce a compact() utility that efficiently scans a range finding
"equivalent" consecutive objects and removes duplicates. The previous
code did that with an extra remove pass which invalidated all 
iterators.
2025-12-19 13:50:20 -08:00
yein 9720da2c68 Fix Json lexeme trying to allocate a string with a huge size due to underflow (#9539) 2025-12-19 13:29:01 -08:00
yein ee74e2d50c Fix missing dep in CompressedStringChunk (#9534) 2025-12-18 13:35:49 -08:00
Powei Feng 6171009add test: fixing broken webgpu+android build (#9529)
The build was failing because the some tint libs are no longer
real dependencies

Fixes #9520
2025-12-18 18:16:21 +00:00
Mathias Agopian d299a444fa don't limit FILAMENT_ENABLE_COVERAGE to DEBUG builds (#9532) 2025-12-18 09:24:19 -08:00
rafadevai 107276e9cc VK: Refactor platform Vulkan initialization (#9523)
* VK: Refactor platform Vulkan initialization

Refactor the platform code to allow overriding
how the vkInstance, vkPhysicalDevice and vkDevice
are created.

This refactor will also consolidate where the extensions
and features are enabled/disabled into VulkanPlatform,
instead of each platform doing its own individual setup
if needed. It also address knowing if a feature or
extension has been enabled, unless we keep adding
entries to the SharedContext which is not scalable.

The createDriver function now have a more defined structure,
mostly how and where features are queried and enabled.

- Get shared context data.
- Create instance if missing.
- Select physical device if missing.
- Query physical device support and set supported
engine features into the VulkanContext.
- Select the queues
- Create the device and queues

* Address review comments

Added some documentation on the new functions
Move the querying and config of features into its
own function.
2025-12-18 09:23:18 -08:00
Mathias Agopian fe00cbf106 feature flags now default to const. (#9530)
This PR doesn't update most of the existing flags that are marked as
"mutable", they're probably wrong.
2025-12-17 10:34:31 -08:00
Filament Bot 02d0ddbcfe [automated] Updating /docs due to commit c4802f7
Full commit hash is c4802f7683

DOCS_ALLOW_DIRECT_EDITS
2025-12-16 23:01:53 +00:00
279 changed files with 13735 additions and 7395 deletions
-25
View File
@@ -1,25 +0,0 @@
name: Android
on:
push:
branches:
- main
- release
- rc/**
jobs:
build-android:
name: build-android
# We intentially use a larger runner here to enable larger disk space
# (standard linux runner will fail on disk space and faster build time).
runs-on: 'ubuntu-24.04-16core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- name: Run Android Continuous
uses: ./.github/actions/android-continuous
with:
build-abi: armeabi-v7a,arm64-v8a,x86_64
-29
View File
@@ -1,29 +0,0 @@
name: iOS
on:
push:
branches:
- main
- release
- rc/**
jobs:
build-ios:
name: build-ios
runs-on: macos-14-xlarge
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/mac-prereq
- name: Run build script
run: |
cd build/ios && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-ios
path: out/filament-release-ios.tgz
- name: Build iOS samples
run: |
cd build/ios && ./build-samples.sh continuous
-26
View File
@@ -1,26 +0,0 @@
name: Linux
on:
push:
branches:
- main
- release
- rc/**
jobs:
build-linux:
name: build-linux
runs-on: 'ubuntu-24.04-16core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- name: Run build script
run: |
cd build/linux && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-linux
path: out/filament-release-linux.tgz
-29
View File
@@ -1,29 +0,0 @@
name: macOS
on:
push:
branches:
- main
- release
- rc/**
jobs:
build-mac:
name: build-mac
runs-on: macos-14-xlarge
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/mac-prereq
- name: Run build script
run: |
cd build/mac && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-mac
path: out/filament-release-darwin.tgz
- name: Check public headers
run: |
test/check-headers/test.sh out/release/filament/include
+59
View File
@@ -0,0 +1,59 @@
name: 'Postsubmit Tasks'
on:
push:
branches:
- main
jobs:
update-renderdiff-goldens:
name: update-renderdiff-goldens
runs-on: 'ubuntu-24.04-4core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- id: get_commit_msg
uses: ./.github/actions/get-commit-msg
- name: Prerequisites
run: pip install tifffile numpy
- name: Run update script
env:
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
COMMIT_MESSAGE: ${{ steps.get_commit_msg.outputs.msg }}
run: |
GOLDEN_BRANCH=$(echo "${COMMIT_MESSAGE}" | python3 test/renderdiff/src/commit_msg.py)
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
if [[ "${GOLDEN_BRANCH}" != "main" ]]; then
git config --global user.email "filament.bot@gmail.com"
git config --global user.name "Filament Bot"
git config --global credential.helper cache
echo "branch==${GOLDEN_BRANCH}"
echo "hash==${COMMIT_HASH}"
python3 test/renderdiff/src/update_golden.py --branch=${GOLDEN_BRANCH} \
--merge-to-main --filament-tag=${COMMIT_HASH} --golden-repo-token=${GH_TOKEN}
fi
update-docs:
name: update-docs
runs-on: 'ubuntu-24.04-4core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- id: get_commit_msg
uses: ./.github/actions/get-commit-msg
- name: Prerequisites
run: pip install selenium
- name: Run update script
env:
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
run: |
bash docs_src/build/install_mdbook.sh && source ~/.bashrc
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
git config --global user.email "filament.bot@gmail.com"
git config --global user.name "Filament Bot"
git config --global credential.helper cache
bash docs_src/build/postsubmit.sh ${COMMIT_HASH} ${GH_TOKEN}
+101 -45
View File
@@ -1,59 +1,115 @@
name: 'Post-submit tasks'
name: 'Postsubmit CI'
on:
push:
branches:
- main
- release
- rc/**
jobs:
update-renderdiff-goldens:
name: update-renderdiff-goldens
runs-on: 'ubuntu-24.04-4core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- id: get_commit_msg
uses: ./.github/actions/get-commit-msg
- name: Prerequisites
run: pip install tifffile numpy
- name: Run update script
env:
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
COMMIT_MESSAGE: ${{ steps.get_commit_msg.outputs.msg }}
run: |
GOLDEN_BRANCH=$(echo "${COMMIT_MESSAGE}" | python3 test/renderdiff/src/commit_msg.py)
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
if [[ "${GOLDEN_BRANCH}" != "main" ]]; then
git config --global user.email "filament.bot@gmail.com"
git config --global user.name "Filament Bot"
git config --global credential.helper cache
echo "branch==${GOLDEN_BRANCH}"
echo "hash==${COMMIT_HASH}"
python3 test/renderdiff/src/update_golden.py --branch=${GOLDEN_BRANCH} \
--merge-to-main --filament-tag=${COMMIT_HASH} --golden-repo-token=${GH_TOKEN}
fi
build-android:
name: build-android
# We intentially use a larger runner here to enable larger disk space
# (standard linux runner will fail on disk space and faster build time).
runs-on: 'ubuntu-24.04-16core'
update-docs:
name: update-docs
runs-on: 'ubuntu-24.04-4core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- id: get_commit_msg
uses: ./.github/actions/get-commit-msg
- name: Prerequisites
run: pip install selenium
- name: Run update script
env:
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
- name: Run Android Continuous
uses: ./.github/actions/android-continuous
with:
build-abi: armeabi-v7a,arm64-v8a,x86_64
build-ios:
name: build-ios
runs-on: macos-14-xlarge
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/mac-prereq
- name: Run build script
run: |
bash docs_src/build/install_mdbook.sh && source ~/.bashrc
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
git config --global user.email "filament.bot@gmail.com"
git config --global user.name "Filament Bot"
git config --global credential.helper cache
bash docs_src/build/postsubmit.sh ${COMMIT_HASH} ${GH_TOKEN}
cd build/ios && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-ios
path: out/filament-release-ios.tgz
- name: Build iOS samples
run: |
cd build/ios && ./build-samples.sh continuous
build-linux:
name: build-linux
runs-on: 'ubuntu-24.04-16core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- name: Run build script
run: |
cd build/linux && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-linux
path: out/filament-release-linux.tgz
build-mac:
name: build-mac
runs-on: macos-14-xlarge
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/mac-prereq
- name: Run build script
run: |
cd build/mac && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-mac
path: out/filament-release-darwin.tgz
- name: Check public headers
run: |
test/check-headers/test.sh out/release/filament/include
build-web:
name: build-web
runs-on: 'ubuntu-24.04-16core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- uses: ./.github/actions/web-prereq
- name: Run build script
run: |
cd build/web && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-web
path: out/filament-release-web.tgz
build-windows:
name: build-windows
runs-on: windows-2022-32core
steps:
- uses: actions/checkout@v4.1.6
- name: Run build script
run: |
build\windows\build-github.bat continuous
shell: cmd
- uses: actions/upload-artifact@v4
with:
name: filament-windows
path: out/filament-windows.tgz
+2 -2
View File
@@ -1,4 +1,4 @@
name: Presubmit
name: 'Presubmit CI'
on:
push:
@@ -19,7 +19,7 @@ jobs:
- uses: ./.github/actions/mac-prereq
- name: Run build script
run: |
cd build/mac && printf "y" | ./build.sh presubmit
cd build/mac && printf "y" | ./build.sh presubmit-with-test
- name: Test material parser
run: |
out/cmake-release/filament/test/test_material_parser
-27
View File
@@ -1,27 +0,0 @@
name: Web
on:
push:
branches:
- main
- release
- rc/**
jobs:
build-web:
name: build-web
runs-on: 'ubuntu-24.04-16core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- uses: ./.github/actions/web-prereq
- name: Run build script
run: |
cd build/web && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-web
path: out/filament-release-web.tgz
-24
View File
@@ -1,24 +0,0 @@
name: Windows
on:
push:
branches:
- main
- release
- rc/**
jobs:
build-windows:
name: build-windows
runs-on: windows-2022-32core
steps:
- uses: actions/checkout@v4.1.6
- name: Run build script
run: |
build\windows\build-github.bat continuous
shell: cmd
- uses: actions/upload-artifact@v4
with:
name: filament-windows
path: out/filament-windows.tgz
+15 -3
View File
@@ -367,14 +367,22 @@ endif()
if (LINUX)
option(USE_STATIC_LIBCXX "Link against the static runtime libraries." ON)
# Add this step to support both glibc-based Linux distributions (e.g., Ubuntu, Debian)
# and musl-based distributions (e.g., Alpine).
include(CheckSymbolExists)
check_symbol_exists(__GLIBC__ "features.h" CLANG_WITH_GLIBC)
if (${USE_STATIC_LIBCXX})
if (FILAMENT_USING_GCC)
link_libraries("-static-libgcc -static-libstdc++")
else ()
elseif (CLANG_WITH_GLIBC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
link_libraries("-static-libgcc -static-libstdc++")
link_libraries(libc++.a)
link_libraries(libc++abi.a)
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
endif()
endif()
@@ -473,7 +481,7 @@ endif()
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${EXTRA_SANITIZE_OPTIONS}")
if (FILAMENT_ENABLE_COVERAGE)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-instr-generate -fcoverage-mapping")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-instr-generate -fcoverage-mapping -Wno-pass-failed")
endif()
# Disable the stack check for macOS to workaround a known issue in clang 11.0.0.
@@ -563,6 +571,10 @@ if (FILAMENT_SUPPORTS_WEBGPU)
add_definitions(-DFILAMENT_SUPPORTS_WEBGPU)
endif()
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
add_definitions(-DFILAMENT_SUPPORTS_WEBP_TEXTURES)
endif()
# Build with Metal support on non-WebGL Apple platforms.
if (APPLE AND NOT WEBGL)
option(FILAMENT_SUPPORTS_METAL "Include the Metal backend" ON)
@@ -915,7 +927,6 @@ endif()
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
add_subdirectory(${EXTERNAL}/libwebp/tnt)
add_definitions(-DFILAMENT_SUPPORTS_WEBP_TEXTURES)
endif()
if (FILAMENT_SUPPORTS_VULKAN)
@@ -973,6 +984,7 @@ if (IS_HOST_PLATFORM)
add_subdirectory(${TOOLS}/roughness-prefilter)
add_subdirectory(${TOOLS}/specular-color)
add_subdirectory(${TOOLS}/uberz)
add_subdirectory(${TOOLS}/specgen)
endif()
# Generate exported executables for cross-compiled builds (Android, WebGL, and iOS)
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.68.3'
implementation 'com.google.android.filament:filament-android:1.68.4'
}
```
@@ -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.68.3'
pod 'Filament', '~> 1.68.4'
```
## Documentation
+9
View File
@@ -7,6 +7,15 @@ 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.68.5
- engine: "native" Streams are officially deprecated. Use "acquired" streams instead.
- engine: add "engine.skip_frame_when_cpu_ahead_of_display" feature [b/474599530]
## v1.68.4
- gltfio: Add optional support for webp textures (EXT_texture_webp), controlled via FILAMENT_SUPPORTS_WEBP_TEXTURES cmake option
## v1.68.3
- materials: added support for the glTF `KHR_materials_dispersion` extension, which adds dispersion for refractive objects
@@ -335,6 +335,13 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderRefract
builder->refractionMode((MaterialBuilder::RefractionMode) mode);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderReflectionMode(JNIEnv* env,
jclass, jlong nativeBuilder, jint mode) {
auto builder = (MaterialBuilder*) nativeBuilder;
builder->reflectionMode((MaterialBuilder::ReflectionMode) mode);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderRefractionType(JNIEnv* env,
jclass, jlong nativeBuilder, jint type) {
@@ -177,6 +177,11 @@ public class MaterialBuilder {
SCREEN_SPACE
}
public enum ReflectionMode {
DEFAULT,
SCREEN_SPACE
}
public enum RefractionType {
SOLID,
THIN
@@ -403,6 +408,12 @@ public class MaterialBuilder {
return this;
}
@NonNull
public MaterialBuilder reflectionMode(ReflectionMode mode) {
nMaterialBuilderReflectionMode(mNativeObject, mode.ordinal());
return this;
}
@NonNull
public MaterialBuilder refractionType(RefractionType type) {
nMaterialBuilderRefractionType(mNativeObject, type.ordinal());
@@ -604,6 +615,7 @@ public class MaterialBuilder {
private static native void nMaterialBuilderSpecularAntiAliasingThreshold(long mNativeObject,
float threshold);
private static native void nMaterialBuilderRefractionMode(long nativeBuilder, int mode);
private static native void nMaterialBuilderReflectionMode(long nativeBuilder, int mode);
private static native void nMaterialBuilderRefractionType(long nativeBuilder, int type);
private static native void nMaterialBuilderClearCoatIorChange(long mNativeObject,
boolean clearCoatIorChange);
@@ -2041,10 +2041,6 @@ public class View {
* use an AABB neighborhood
*/
AABB,
/**
* use the variance of the neighborhood (not recommended)
*/
VARIANCE,
/**
* use both AABB and variance
*/
@@ -2075,7 +2071,7 @@ public class View {
}
/**
* reconstruction filter width typically between 1 (sharper) and 2 (smoother)
* @deprecated has no effect.
*/
public float filterWidth = 1.0f;
/**
@@ -2095,9 +2091,9 @@ public class View {
*/
public boolean enabled = false;
/**
* 4x TAA upscaling. Disables Dynamic Resolution. [BETA]
* Upscaling factor. Disables Dynamic Resolution. [BETA]
*/
public boolean upscaling = false;
public float upscaling = 1.0f;
/**
* whether to filter the history buffer
*/
@@ -2110,6 +2106,10 @@ public class View {
* whether to use the YcoCg color-space for history rejection
*/
public boolean useYCoCg = false;
/**
* set to true for HDR content
*/
public boolean hdr = true;
/**
* type of color gamut box
*/
+14
View File
@@ -6,6 +6,7 @@ option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" OFF)
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
option(FILAMENT_SUPPORTS_WEBGPU "Enables WebGPU on Android" OFF)
option(FILAMENT_SUPPORTS_WEBP_TEXTURES "Enable webp texture support on Android" OFF)
set(CMAKE_CXX_STANDARD 20)
@@ -30,6 +31,12 @@ add_library(stb STATIC IMPORTED)
set_target_properties(stb PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libstb.a)
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
add_library(webpdecoder STATIC IMPORTED)
set_target_properties(webpdecoder PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libwebpdecoder.a)
endif()
add_library(basis_transcoder STATIC IMPORTED)
set_target_properties(basis_transcoder PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libbasis_transcoder.a)
@@ -81,6 +88,10 @@ set(GLTFIO_INCLUDE_DIRS
../../libs/ktxreader/include
)
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
list(APPEND GLTFIO_INCLUDE_DIRS ../../third_party/libwebp/src)
endif()
add_library(gltfio-jni SHARED ${GLTFIO_SRCS})
target_compile_definitions(gltfio-jni PUBLIC GLTFIO_DRACO_SUPPORTED=1)
@@ -107,3 +118,6 @@ target_link_libraries(gltfio-jni
PRIVATE perfetto # needed only when FILAMENT_ENABLE_PERFETTO is defined
PRIVATE log # needed only when perfetto above is used
)
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
target_link_libraries(gltfio-jni PRIVATE webpdecoder)
endif()
@@ -128,6 +128,18 @@ Java_com_google_android_filament_gltfio_ResourceLoader_nCreateKtx2Provider(JNIEn
return (jlong) createKtx2Provider(engine);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_gltfio_ResourceLoader_nIsWebpSupported(JNIEnv*, jclass) {
return (jboolean) isWebpSupported();
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_gltfio_ResourceLoader_nCreateWebpProvider(JNIEnv*, jclass,
jlong nativeEngine) {
Engine* engine = (Engine*) nativeEngine;
return (jlong) createWebpProvider(engine);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_ResourceLoader_nDestroyTextureProvider(JNIEnv*, jclass,
jlong nativeProvider) {
@@ -37,6 +37,7 @@ public class ResourceLoader {
private final long mNativeObject;
private final long mNativeStbProvider;
private final long mNativeKtx2Provider;
private final long mNativeWebpProvider;
/**
* Constructs a resource loader tied to the given Filament engine.
@@ -50,9 +51,17 @@ public class ResourceLoader {
mNativeObject = nCreateResourceLoader(nativeEngine, false);
mNativeStbProvider = nCreateStbProvider(nativeEngine);
mNativeKtx2Provider = nCreateKtx2Provider(nativeEngine);
nAddTextureProvider(mNativeObject, "image/jpeg", mNativeStbProvider);
nAddTextureProvider(mNativeObject, "image/png", mNativeStbProvider);
nAddTextureProvider(mNativeObject, "image/ktx2", mNativeKtx2Provider);
if (nIsWebpSupported()) {
mNativeWebpProvider = nCreateWebpProvider(nativeEngine);
nAddTextureProvider(mNativeObject, "image/webp", mNativeWebpProvider);
}
else {
mNativeWebpProvider = 0;
}
}
/**
@@ -68,9 +77,17 @@ public class ResourceLoader {
mNativeObject = nCreateResourceLoader(nativeEngine, normalizeSkinningWeights);
mNativeStbProvider = nCreateStbProvider(nativeEngine);
mNativeKtx2Provider = nCreateKtx2Provider(nativeEngine);
nAddTextureProvider(mNativeObject, "image/jpeg", mNativeStbProvider);
nAddTextureProvider(mNativeObject, "image/png", mNativeStbProvider);
nAddTextureProvider(mNativeObject, "image/ktx2", mNativeKtx2Provider);
if (nIsWebpSupported()) {
mNativeWebpProvider = nCreateWebpProvider(nativeEngine);
nAddTextureProvider(mNativeObject, "image/webp", mNativeWebpProvider);
}
else {
mNativeWebpProvider = 0;
}
}
/**
@@ -80,6 +97,9 @@ public class ResourceLoader {
nDestroyResourceLoader(mNativeObject);
nDestroyTextureProvider(mNativeStbProvider);
nDestroyTextureProvider(mNativeKtx2Provider);
if (nIsWebpSupported()) {
nDestroyTextureProvider(mNativeWebpProvider);
}
}
/**
@@ -191,6 +211,9 @@ public class ResourceLoader {
private static native long nCreateStbProvider(long nativeEngine);
private static native long nCreateKtx2Provider(long nativeEngine);
private static native boolean nIsWebpSupported();
private static native long nCreateWebpProvider(long nativeEngine);
private static native void nAddTextureProvider(long nativeLoader, String url, long nativeProvider);
private static native void nDestroyTextureProvider(long nativeProvider);
}
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.68.3
VERSION_NAME=1.68.4
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
@@ -76,11 +76,16 @@ class MainActivity : Activity() {
private var texture: Texture? = null
private var renderTarget: RenderTarget? = null
private var useExternalTexture = true
private lateinit var offscreenView: View
private lateinit var offscreenCamera: Camera
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// To use set this flag with adb, run
// adb shell am start -n com.google.android.filament.texturetarget/.MainActivity --ez useExternalTexture false
useExternalTexture = intent.getBooleanExtra("useExternalTexture", true)
surfaceView = SurfaceView(this)
setContentView(surfaceView)
choreographer = Choreographer.getInstance()
@@ -173,8 +178,15 @@ class MainActivity : Activity() {
readUncompressedAsset("materials/baked_color.filamat").let {
triangleMaterial = Material.Builder().payload(it, it.remaining()).build(engine)
}
readUncompressedAsset("materials/textured.filamat").let {
texturedMaterial = Material.Builder().payload(it, it.remaining()).build(engine)
if (useExternalTexture) {
readUncompressedAsset("materials/texturedExternal.filamat").let {
texturedMaterial = Material.Builder().payload(it, it.remaining()).build(engine)
}
} else {
readUncompressedAsset("materials/textured.filamat").let {
texturedMaterial = Material.Builder().payload(it, it.remaining()).build(engine)
}
}
}
@@ -385,33 +397,41 @@ class MainActivity : Activity() {
texture?.let { engine.destroyTexture(it) }
hardwareBuffer?.close()
// Create a new render target.
hardwareBuffer = HardwareBuffer.create(width, height,
HardwareBuffer.RGBA_8888, 1,
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or HardwareBuffer.USAGE_GPU_COLOR_OUTPUT)
if (useExternalTexture) {
// Create a new render target.
hardwareBuffer = HardwareBuffer.create(width, height,
HardwareBuffer.RGBA_8888, 1,
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or HardwareBuffer.USAGE_GPU_COLOR_OUTPUT)
texture = Texture.Builder()
.width(width)
.height(height)
.usage(Texture.Usage.COLOR_ATTACHMENT or Texture.Usage.SAMPLEABLE)
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
.format(Texture.InternalFormat.RGBA8)
.external()
.build(engine)
texture = Texture.Builder()
.width(width)
.height(height)
.usage(Texture.Usage.COLOR_ATTACHMENT or Texture.Usage.SAMPLEABLE)
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
.format(Texture.InternalFormat.RGBA8)
.external()
.build(engine)
texture!!.setExternalImage(engine, hardwareBuffer!!)
texture!!.setExternalImage(engine, hardwareBuffer!!)
} else {
texture = Texture.Builder()
.width(width)
.height(height)
.levels(1)
.usage(Texture.Usage.COLOR_ATTACHMENT or Texture.Usage.SAMPLEABLE)
.format(Texture.InternalFormat.RGBA8)
.build(engine)
}
renderTarget = RenderTarget.Builder()
.texture(RenderTarget.AttachmentPoint.COLOR, texture!!)
.build(engine)
offscreenView.renderTarget = renderTarget
// Set the texture on the quad material.
texturedMaterial.defaultInstance.setParameter("texture", texture!!,
TextureSampler(TextureSampler.MinFilter.LINEAR, TextureSampler.MagFilter.LINEAR,
TextureSampler.WrapMode.CLAMP_TO_EDGE))
TextureSampler.WrapMode.CLAMP_TO_EDGE))
FilamentHelper.synchronizePendingFrames(engine)
}
}
@@ -3,7 +3,7 @@ material {
shadingModel : unlit,
parameters : [
{
type : samplerExternal,
type : sampler2d,
name : texture
}
],
@@ -15,6 +15,6 @@ material {
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = texture(materialParams_texture, getUV0());
material.baseColor = texture(materialParams_texture, uvToRenderTargetUV(getUV0()));
}
}
@@ -0,0 +1,20 @@
material {
name : textured,
shadingModel : unlit,
parameters : [
{
type : samplerExternal,
name : texture
}
],
requires: [
uv0
]
}
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = texture(materialParams_texture, uvToRenderTargetUV(getUV0()));
}
}
+5
View File
@@ -34,6 +34,11 @@ if [[ "$TARGET" == "presubmit" ]]; then
BUILD_RELEASE=release
fi
if [[ "$TARGET" == "presubmit-with-test" ]]; then
BUILD_RELEASE=release
RUN_TESTS=-u
fi
if [[ "$TARGET" == "debug" ]]; then
BUILD_DEBUG=debug
GENERATE_ARCHIVES=-a
+30 -6
View File
@@ -97,6 +97,7 @@ in table [standardProperties].
**transmission** | Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is
**ior** | Index of refraction, either for refractive objects or as an alternative to reflectance
**microThickness** | Thickness of the thin layer of refractive objects
**dispersion** | Strength of the dispersion effect for refractive objects, specified as 20/Abbe number
**bentNormal** | A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality
**shadowStrength** | Strength factor between 0 and 1 for all shadows received by this material
[Table [standardProperties]: Properties of the standard model]
@@ -126,6 +127,7 @@ The type and range of each property is described in table [standardPropertiesTyp
**absorption** | float3 | [0..n] |
**microThickness** | float | [0..n] |
**thickness** | float | [0..n] |
**dispersion** | float | [0..n] | Realistic values are between [0, 1], with the exception of Rutile, which has a value of 2.04
[Table [standardPropertiesTypes]: Range and type of the standard model's properties]
@@ -153,13 +155,14 @@ The type and range of each property is described in table [standardPropertiesTyp
as-is, which can lead to physically impossible materials, however, this might be desirable
for artistic reasons.
!!! Note: About `thickness` and `microThickness` for refraction
!!! Note: About `thickness`, `microThickness` and `dispersion` for refraction
`thickness` represents the thickness of solid objects in the direction of the normal, for
satisfactory results, this should be provided per fragment (e.g.: as a texture) or at least per
vertex. `microThickness` represent the thickness of the thin layer of an object, and can
generally be provided as a constant value. For example, a 1mm thin hollow sphere of radius 1m,
would have a `thickness` of 1 and a `microThickness` of 0.001. Currently `thickness` is not
used when `refractionType` is set to `thin`.
would have a `thickness` of 1 and a `microThickness` of 0.001. Dispersion controls the angular
separation of colors transmitting through a volume, and can be set by a constant value.
Currently `thickness` and `dispersion` are not used when `refractionType` is set to `thin`.
### Base color
@@ -651,6 +654,26 @@ the `refractionType` is set to `solid` and `absorption` coefficients are set.
![Figure [varyingThickness]: `thickness` varying from 0.0 at the top of the prism to 3.0 at the
bottom of the prism](images/material_thickness.png)
### Dispersion
The dispersion property controls the angular separation of colors transmitting through a relatively
clear volume. It can only be used when `refractionType` is set to `volume`.
Its value is specified as 20/Abbe number. When the value is zero, no dispersion is used.
Table [commonMatDispersion] describes acceptable dispersion values for various types of materials.
Material | Abbe Number (V) | Dispersion (20/V)
--------------------------:|:------------------:|:-----------------
Rutile | 9.8 | 2.04
Polycarbonate | 32 | 0.625
Diamond | 55 | 0.36
Water | 55 | 0.36
Crown Glass | 59 | 0.33
[Table [commonMatDispersion]: Dispersion of common materials]
![Figure [dispersionProperty]: `dispersion` varying from 0.0
(left) to 5.0 (right)](images/materials/dispersion.png)
## Subsurface model
### Thickness
@@ -2276,6 +2299,7 @@ struct MaterialInputs {
float3 absorption; // default float3(0.0, 0.0, 0.0)
float ior; // default: 1.5
float microThickness; // default: 0.0, not available with refractionType "solid"
float dispersion; // default: 0.0, not available with refractionType "thin"
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2456,9 +2480,9 @@ type aliases:
**uint2** | uvec2 | A vector of 2 unsigned integers
**uint3** | uvec3 | A vector of 3 unsigned integers
**uint4** | uvec4 | A vector of 4 unsigned integers
**float2** | float2 | A vector of 2 floats
**float3** | float3 | A vector of 3 floats
**float4** | float4 | A vector of 4 floats
**float2** | vec2 | A vector of 2 floats
**float3** | vec3 | A vector of 3 floats
**float4** | vec4 | A vector of 4 floats
**float4x4** | mat4 | A 4x4 float matrix
**float3x3** | mat3 | A 3x3 float matrix
+3 -3
View File
@@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Build for Android on Windows - Filament</title>
<title>Android on Windows - Filament</title>
<!-- Custom HTML head -->
@@ -273,7 +273,7 @@ copy filament-android\build\outputs\aar\filament-android-release.aar ..\..\out\
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../build/maven_release.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/contributing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -287,7 +287,7 @@ copy filament-android\build\outputs\aar\filament-android-release.aar ..\..\out\
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../build/maven_release.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/contributing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+29
View File
@@ -327,12 +327,41 @@ host tools are required to successfully build for Android.</p>
<p>Note that the main target is the ARM 64-bit target. Our implementation is optimized first and
foremost for <code>arm64-v8a</code>.</p>
<p>To build Android on Windows machines, see <a href="android/Windows.html">android/Windows.md</a>.</p>
<h4 id="important-sdk-location"><a class="header" href="#important-sdk-location">Important: SDK location</a></h4>
<p>Either ensure your <code>ANDROID_HOME</code> environment variable is set or make sure the root project
contains a <code>local.properties</code> file with the <code>sdk.dir</code> property pointing to your installation of
the Android SDK.</p>
<h4 id="easy-android-build"><a class="header" href="#easy-android-build">Easy Android build</a></h4>
<p>The easiest way to build Filament for Android is to use <code>build.sh</code> and the
<code>-p android</code> flag. For instance to build the release target:</p>
<pre><code class="language-shell">./build.sh -p android release
</code></pre>
<p>To build a sample (such as <code>android/samples/sample-hello-triangle</code>) for an ARM 64-bit phone, you would run</p>
<pre><code class="language-shell">./build.sh -p android -q arm64-v8a -k sample-hello-triangle release
</code></pre>
<p>The output APK can be found in <code>android/samples/sample-hello-triangle/build/outputs/apk/release/sample-hello-triangle-release-unsigned.apk</code></p>
<p>Run <code>build.sh -h</code> for more information.</p>
<h4 id="android-studio"><a class="header" href="#android-studio">Android Studio</a></h4>
<p>You must use the latest stable release of Android Studio.</p>
<p>The Android build of filament is separated into java/kotlin client APIs, a layer of jni bindings
that bridges java/kotlin with native code, and Filament and other component code that have been compiled
into architecture-specific libraries. Our default Android Studio gradle setup can compile java/kotlin and
the jni bindings for you, but it will treat the filament libraries as already compiled and present on
the system.</p>
<p>Therefore, before compiling the sample app or any other targets, you must
make sure that the native filament libraries have been compiled and are located at a prescribed location
so that the jni bindings can link against them. You can do so by using the easy build script</p>
<pre><code class="language-shell">./build.sh -p android release -q arm64-v8a
</code></pre>
<p>Note that the above step will also install host machine tools into prescribed locations. These tools are
required for compiling Filament assets such as materials and environment maps.</p>
<p>Now we are ready to compile the apps. To open the project, point Studio to the <code>android</code> folder.
After opening the project and syncing with Gradle, select the sample of your choice
using the drop-down widget in the toolbar. Additionally, you will need to select a deployment target.
By doing so, Android Studio will automatically try to compile the app only for that specific
device's architecture. So if you are targeting a new Pixel phone, make sure that the step above
(compiling the library) is targeting ARM 64-bit (<code>-q arm64-v8a</code> ), and if you are running the app on
an emulator on a Linux machine with an x86 64-bit chipset, you would indicate (<code>-q x86_64</code>) in the above step.</p>
<h4 id="manual-builds"><a class="header" href="#manual-builds">Manual builds</a></h4>
<p>Invoke CMake in a build directory of your choice, inside of filament's directory. The commands
below show how to build Filament for ARM 64-bit (<code>aarch64</code>).</p>
+2 -2
View File
@@ -209,7 +209,7 @@ as possible. The current external dependencies of the runtime library include:</
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../build/maven_release.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../build/windows_android.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -223,7 +223,7 @@ as possible. The current external dependencies of the runtime library include:</
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../build/maven_release.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../build/windows_android.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
+3 -3
View File
@@ -203,7 +203,7 @@ tree into <code>docs_src/src_mdbook/src/dup</code>. Moreover, to restore valid l
to perform a number of URL replacements in addition to the copy. These replacements are
described in <a href="https://github.com/google/filament/blob/main/docs_src/build/duplicates.json"><code>docs_src/build/duplicates.json</code></a>.</p>
<h3 id="core-concept-docs"><a class="header" href="#core-concept-docs">Core concept docs</a></h3>
<p>The primary design of Filament as a phyiscally-based renderer and details of its materials
<p>The primary design of Filament as a physically-based renderer and details of its materials
system are described in <code>Filament.md.html</code> and <code>Materials.md.html</code>, respectively. These two
documents are written in <a href="https://casual-effects.com/markdeep/"><code>markdeep</code></a>. To embed them into our book, we</p>
<ol>
@@ -253,7 +253,7 @@ add a link in <code>SUMMARY.md</code>, and perform the steps outlined in
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/release_guide.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/branching.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -267,7 +267,7 @@ add a link in <code>SUMMARY.md</code>, and perform the steps outlined in
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/release_guide.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/branching.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
+2 -2
View File
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.68.0'
implementation 'com.google.android.filament:filament-android:1.68.4'
}
</code></pre>
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
@@ -196,7 +196,7 @@ dependencies {
</div>
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
<p>iOS projects can use CocoaPods to install the latest release:</p>
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.68.0'
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.68.4'
</code></pre>
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
<ul>
+230
View File
@@ -0,0 +1,230 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>backend - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="backend-tests"><a class="header" href="#backend-tests">Backend Tests</a></h1>
<p>This directory (<code>/test/backend</code>) contains scripts to run Filament's backend tests using a software
rasterizer (Mesa). This is useful for running tests in a continuous integration environment where a
GPU might not be available.</p>
<p>The <code>test.sh</code> script will:</p>
<ol>
<li>Build Mesa if needed.</li>
<li>Build the backend tests.</li>
<li>Run the tests using the OpenGL and Vulkan backends with Mesa.</li>
</ol>
<h2 id="flags"><a class="header" href="#flags">Flags</a></h2>
<p>The <code>test.sh</code> script accepts the following flags:</p>
<ul>
<li><code>--gtest_filter</code>: Filters the tests that are run. This is passed directly to the underlying
gtest executable.</li>
<li><code>--backend</code>: Specifies which backend to test. Can be <code>opengl</code>, <code>vulkan</code>, or a comma-separated
list (e.g., <code>opengl,vulkan</code>). Defaults to both.</li>
</ul>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/tests.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/test_renderdiff.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/tests.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/test_renderdiff.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
@@ -159,7 +159,8 @@
<div id="content" class="content">
<main>
<h1 id="rendering-difference-test"><a class="header" href="#rendering-difference-test">Rendering Difference Test</a></h1>
<p>This tool is a collections of scripts to run <code>gltf_viewer</code> and produce headless renderings.</p>
<p>This tool (<code>/test/renderdiff</code>) is a collections of scripts to run <code>gltf_viewer</code> and produce headless
renderings.</p>
<p>This is mainly useful for continuous integration where GPUs are generally not available on cloud
machines. To perform software rasterization, these scripts are centered around <a href="https://docs.mesa3d.org">Mesa</a>'s
software rasterizers, but nothing bars us from using another rasterizer like <a href="https://github.com/google/swiftshader">SwiftShader</a>.
@@ -251,7 +252,7 @@ git switch -c my-pr-branch-golden
</code></pre>
</li>
<li>In the commit message of your working branch on <code>filament</code>, add the following line
<pre><code>RDIFF_BBRANCH=my-pr-branch-golden
<pre><code>RDIFF_BRANCH=my-pr-branch-golden
</code></pre>
</li>
</ul>
@@ -292,7 +293,7 @@ the run number is <code>18023632663</code>.</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/tests.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/test_backend.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -306,7 +307,7 @@ the run number is <code>18023632663</code>.</p>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/tests.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/test_backend.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 MiB

+2732 -2773
View File
File diff suppressed because one or more lines are too long
+1903 -1902
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -165,7 +165,7 @@
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../dup/renderdiff.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/test_renderdiff.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -179,7 +179,7 @@
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../dup/renderdiff.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/test_renderdiff.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
+2 -2
View File
@@ -668,7 +668,7 @@ Values can be <strong>negative</strong> to change the orientation of the specula
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/versioning.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -682,7 +682,7 @@ Values can be <strong>negative</strong> to change the orientation of the specula
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/versioning.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+2 -2
View File
@@ -170,7 +170,7 @@ for in our Continuation Integration flow <a href="https://https://github.com/goo
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/renderdiff.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/test_backend.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -184,7 +184,7 @@ for in our Continuation Integration flow <a href="https://https://github.com/goo
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/renderdiff.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/test_backend.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
@@ -185,11 +185,11 @@ the <em>correct</em> fix in both the next release candidate branch <em>and</em>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/versioning.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/versioning.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/release_guide.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/docs.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -199,11 +199,11 @@ the <em>correct</em> fix in both the next release candidate branch <em>and</em>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/versioning.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/versioning.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/release_guide.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/docs.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+249
View File
@@ -0,0 +1,249 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>CocoaPods - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="filament-cocoapods"><a class="header" href="#filament-cocoapods">Filament CocoaPods</a></h1>
<p><a href="https://cocoapods.org/">CocoaPods</a> is the dependency manager Filament uses for Apple platforms
(macOS and iOS).</p>
<h2 id="installation"><a class="header" href="#installation">Installation</a></h2>
<p>On macOS, CocoaPods requires a modern Ruby environment. Avoid using the system Ruby; instead,
install the latest Ruby version using <code>brew</code>, <code>port,</code> or use a manager like <code>rbenv</code> or <code>rvm</code>. Once
Ruby is configured:</p>
<pre><code class="language-bash">gem install cocoapods
</code></pre>
<h2 id="linting-the-podspec"><a class="header" href="#linting-the-podspec">Linting the Podspec</a></h2>
<p>The Filament podspec is configured to fetch releases directly from GitHub. Before deployment,
CocoaPods must <strong>lint</strong> the spec to validate that the library compiles and links correctly across
all supported architectures.</p>
<p>To run the linter locally:</p>
<pre><code class="language-bash">cd ios/CocoaPods/
pod spec lint
</code></pre>
<h3 id="debugging-failures"><a class="header" href="#debugging-failures">Debugging Failures</a></h3>
<p>If the lint fails, use the <code>--verbose</code> flag to inspect the underlying <code>xcodebuild</code> output:</p>
<pre><code class="language-bash">pod spec lint --verbose
</code></pre>
<h2 id="isolating-subspecs"><a class="header" href="#isolating-subspecs">Isolating Subspecs</a></h2>
<p>Filament is partitioned into multiple <strong>subspecs</strong>. CocoaPods lints these individually. To
accelerate debugging or isolate a specific build failure (e.g., <code>Filament/filament</code>), use the
following command:</p>
<pre><code class="language-bash">pod spec lint --no-clean --verbose --subspec=Filament/filament 2&gt;&amp;1 | tee lint_output.log
</code></pre>
<ul>
<li><code>--no-clean</code>: Preserves the temporary Xcode workspace and build artifacts in <code>/var/folders/...</code>
for inspection.</li>
<li><code>--verbose</code>: Prints the full compiler and linker invocations.</li>
<li><code>--subspec</code>: Limits the scope of the lint to a specific component.</li>
</ul>
<blockquote>
<p><strong>Tip:</strong> To view all defined subspecs, grep the podspec file:
<code>grep "spec.subspec" ios/CocoaPods/Filament.podspec</code></p>
</blockquote>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../release/index.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../release/maven.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../release/index.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../release/maven.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
@@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Release Guide - Filament</title>
<title>Github - Filament</title>
<!-- Custom HTML head -->
@@ -250,11 +250,11 @@ release (for example, v1.42.2).</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/branching.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/maven.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/docs.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/versioning.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -264,11 +264,11 @@ release (for example, v1.42.2).</p>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/branching.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/maven.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/docs.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/versioning.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+215
View File
@@ -0,0 +1,215 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Release - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="release"><a class="header" href="#release">Release</a></h1>
<p>This is a collection of guides for releasing Filament on different distribution platforms, including
Github, Maven, and CocoaPods.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/material_properties.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../release/cocoapods.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/material_properties.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../release/cocoapods.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
@@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Maven Release - Filament</title>
<title>Maven - Filament</title>
<!-- Custom HTML head -->
@@ -218,11 +218,11 @@ the <strong>Publish</strong> button to publish the artifacts. It typically takes
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../build/windows_android.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/cocoapods.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/contributing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/guide.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -232,11 +232,11 @@ the <strong>Publish</strong> button to publish the artifacts. It typically takes
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../build/windows_android.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/cocoapods.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/contributing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/guide.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
@@ -186,11 +186,11 @@ post-process materials. However for now these two numbers must be set to the sam
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/material_properties.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/guide.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/branching.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/branching.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -200,11 +200,11 @@ post-process materials. However for now these two numbers must be set to the sam
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/material_properties.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/guide.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/branching.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/branching.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+12 -2
View File
@@ -307,7 +307,7 @@ class FilamentViewer extends LitElement {
asyncInterval: 30
};
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider) => {
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider, webpProvider) => {
this.srcBlobResources = {};
resourceLoader.asyncBeginLoad(this.asset);
const timer = setInterval(() => {
@@ -318,6 +318,9 @@ class FilamentViewer extends LitElement {
resourceLoader.delete();
stbProvider.delete();
ktx2Provider.delete();
if (webpProvider) {
webpProvider.delete();
}
this.animator = this.asset.getInstance().getAnimator();
this.animationStartTime = Date.now();
}
@@ -335,18 +338,25 @@ class FilamentViewer extends LitElement {
const stbProvider = new Filament.gltfio$StbProvider(this.engine);
const ktx2Provider = new Filament.gltfio$Ktx2Provider(this.engine);
let webpProvider = null;
resourceLoader.addStbProvider("image/jpeg", stbProvider);
resourceLoader.addStbProvider("image/png", stbProvider);
resourceLoader.addKtx2Provider("image/ktx2", ktx2Provider);
if (Filament.gltfio$WebpProvider.isWebpSupported()) {
webpProvider = new Filament.gltfio$WebpProvider(this.engine);
resourceLoader.addWebpProvider("image/webp", webpProvider);
}
let remaining = Object.keys(this.srcBlobResources).length;
for (const name in this.srcBlobResources) {
this.srcBlobResources[name].arrayBuffer().then(buffer => {
const desc = getBufferDescriptor(new Uint8Array(buffer));
resourceLoader.addResourceData(name, getBufferDescriptor(desc));
if (--remaining === 0) {
doneAddingResources(resourceLoader, stbProvider, ktx2Provider);
doneAddingResources(resourceLoader, stbProvider, ktx2Provider, webpProvider);
}
});
}
+1 -1
View File
@@ -49,7 +49,7 @@ to perform a number of URL replacements in addition to the copy. These replaceme
described in [`docs_src/build/duplicates.json`].
### Core concept docs
The primary design of Filament as a phyiscally-based renderer and details of its materials
The primary design of Filament as a physically-based renderer and details of its materials
system are described in `Filament.md.html` and `Materials.md.html`, respectively. These two
documents are written in [`markdeep`]. To embed them into our book, we
1. Convert the markdeep into html
+7 -1
View File
@@ -49,6 +49,9 @@
"libs/fgviewer/README.md": {
"dest": "dup/fgviewer.md"
},
"ios/CocoaPods/README.md": {
"dest": "release/cocoapods.md"
},
"tools/normal-blending/README.md": {
"dest": "dup/normal_blending.md"
},
@@ -83,9 +86,12 @@
"dest": "dup/docs.md"
},
"test/renderdiff/README.md": {
"dest": "dup/renderdiff.md",
"dest": "dup/test_renderdiff.md",
"link_transforms": {
"docs/images/": "../images/"
}
},
"test/backend/README.md": {
"dest": "dup/test_backend.md"
}
}
+1 -1
View File
@@ -10,6 +10,6 @@ sortedcontainers==2.4.0
trio==0.31.0
trio-websocket==0.12.2
typing_extensions==4.15.0
urllib3==2.6.0
urllib3==2.6.3
websocket-client==1.9.0
wsproto==1.2.0
+7 -4
View File
@@ -161,7 +161,7 @@ The type and range of each property is described in table [standardPropertiesTyp
vertex. `microThickness` represent the thickness of the thin layer of an object, and can
generally be provided as a constant value. For example, a 1mm thin hollow sphere of radius 1m,
would have a `thickness` of 1 and a `microThickness` of 0.001. Dispersion controls the angular
separation of colors transmitting through a volume, and can be set by a contant value.
separation of colors transmitting through a volume, and can be set by a constant value.
Currently `thickness` and `dispersion` are not used when `refractionType` is set to `thin`.
### Base color
@@ -671,6 +671,9 @@ Water | 55 | 0.36
Crown Glass | 59 | 0.33
[Table [commonMatDispersion]: Dispersion of common materials]
![Figure [dispersionProperty]: `dispersion` varying from 0.0
(left) to 5.0 (right)](images/materials/dispersion.png)
## Subsurface model
### Thickness
@@ -2477,9 +2480,9 @@ type aliases:
**uint2** | uvec2 | A vector of 2 unsigned integers
**uint3** | uvec3 | A vector of 3 unsigned integers
**uint4** | uvec4 | A vector of 4 unsigned integers
**float2** | float2 | A vector of 2 floats
**float3** | float3 | A vector of 3 floats
**float4** | float4 | A vector of 4 floats
**float2** | vec2 | A vector of 2 floats
**float3** | vec3 | A vector of 3 floats
**float4** | vec4 | A vector of 4 floats
**float4x4** | mat4 | A 4x4 float matrix
**float3x3** | mat3 | A 3x3 float matrix
+9 -6
View File
@@ -2,8 +2,7 @@
- [Introduction](./dup/intro.md)
- [Build](./dup/building.md)
- [Build for Android on Windows](./build/windows_android.md)
- [Maven Release](./build/maven_release.md)
- [Android on Windows](./build/windows_android.md)
- [Contribute](./dup/contributing.md)
- [Coding Style](./dup/code_style.md)
- [Core Concepts](./main/README.md)
@@ -14,9 +13,12 @@
- [Web Tutorial](./samples/web.md)
- [Technical Notes](./notes/README.md)
- [Material Properties](./notes/material_properties.md)
- [Versioning](./notes/versioning.md)
- [Branching](./notes/branching.md)
- [Release Guide](./notes/release_guide.md)
- [Release](./release/README.md)
- [CocoaPods](./release/cocoapods.md)
- [Maven](./release/maven.md)
- [Github](./release/guide.md)
- [Versioning](./release/versioning.md)
- [Branching](./release/branching.md)
- [Documentation](./dup/docs.md)
- [Debugging](./notes/debugging.md)
- [Metal](./notes/metal_debugging.md)
@@ -28,7 +30,8 @@
- [Performance analysis](./notes/performance_analysis.md)
- [Framegraph](./notes/framegraph.md)
- [Tests](./notes/tests.md)
- [renderdiff](./dup/renderdiff.md)
- [backend](./dup/test_backend.md)
- [renderdiff](./dup/test_renderdiff.md)
- [Libraries](./notes/libs.md)
- [bluegl](./dup/bluegl.md)
- [bluevk](./dup/bluevk.md)
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 MiB

@@ -0,0 +1,4 @@
# Release
This is a collection of guides for releasing Filament on different distribution platforms, including
Github, Maven, and CocoaPods.
+12 -2
View File
@@ -307,7 +307,7 @@ class FilamentViewer extends LitElement {
asyncInterval: 30
};
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider) => {
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider, webpProvider) => {
this.srcBlobResources = {};
resourceLoader.asyncBeginLoad(this.asset);
const timer = setInterval(() => {
@@ -318,6 +318,9 @@ class FilamentViewer extends LitElement {
resourceLoader.delete();
stbProvider.delete();
ktx2Provider.delete();
if (webpProvider) {
webpProvider.delete();
}
this.animator = this.asset.getInstance().getAnimator();
this.animationStartTime = Date.now();
}
@@ -335,18 +338,25 @@ class FilamentViewer extends LitElement {
const stbProvider = new Filament.gltfio$StbProvider(this.engine);
const ktx2Provider = new Filament.gltfio$Ktx2Provider(this.engine);
let webpProvider = null;
resourceLoader.addStbProvider("image/jpeg", stbProvider);
resourceLoader.addStbProvider("image/png", stbProvider);
resourceLoader.addKtx2Provider("image/ktx2", ktx2Provider);
if (Filament.gltfio$WebpProvider.isWebpSupported()) {
webpProvider = new Filament.gltfio$WebpProvider(this.engine);
resourceLoader.addWebpProvider("image/webp", webpProvider);
}
let remaining = Object.keys(this.srcBlobResources).length;
for (const name in this.srcBlobResources) {
this.srcBlobResources[name].arrayBuffer().then(buffer => {
const desc = getBufferDescriptor(new Uint8Array(buffer));
resourceLoader.addResourceData(name, getBufferDescriptor(desc));
if (--remaining === 0) {
doneAddingResources(resourceLoader, stbProvider, ktx2Provider);
doneAddingResources(resourceLoader, stbProvider, ktx2Provider, webpProvider);
}
});
}
+7 -2
View File
@@ -97,7 +97,6 @@ set(SRCS
src/RenderableManager.cpp
src/Renderer.cpp
src/RendererUtils.cpp
src/ResourceAllocator.cpp
src/ResourceList.cpp
src/Scene.cpp
src/ShadowMap.cpp
@@ -108,6 +107,7 @@ set(SRCS
src/SwapChain.cpp
src/Sync.cpp
src/Texture.cpp
src/TextureCache.cpp
src/ToneMapper.cpp
src/TransformManager.cpp
src/UniformBuffer.cpp
@@ -158,6 +158,7 @@ set(SRCS
src/fg/FrameGraphTexture.cpp
src/fg/PassNode.cpp
src/fg/ResourceNode.cpp
src/fg/ResourceCreationContext.cpp
src/fsr.cpp
src/ZstdHelper.cpp
)
@@ -168,6 +169,7 @@ set(PRIVATE_HDRS
src/Bimap.h
src/BufferPoolAllocator.h
src/ColorSpaceUtils.h
src/compact.h
src/Culler.h
src/DFG.h
src/FilamentAPI-impl.h
@@ -188,16 +190,17 @@ set(PRIVATE_HDRS
src/RenderPass.h
src/RenderPrimitive.h
src/RendererUtils.h
src/ResourceAllocator.h
src/ResourceList.h
src/ShadowMap.h
src/ShadowMapManager.h
src/SharedHandle.h
src/TextureCache.h
src/UniformBuffer.h
src/components/CameraManager.h
src/components/LightManager.h
src/components/RenderableManager.h
src/components/TransformManager.h
src/details/AsyncHelpers.h
src/details/BufferAllocator.h
src/details/BufferObject.h
src/details/Camera.h
@@ -232,6 +235,7 @@ set(PRIVATE_HDRS
src/ds/TypedUniformBuffer.h
src/fg/Blackboard.h
src/fg/FrameGraph.h
src/fg/FrameGraphDummyLink.h
src/fg/FrameGraphId.h
src/fg/FrameGraphPass.h
src/fg/FrameGraphRenderPass.h
@@ -241,6 +245,7 @@ set(PRIVATE_HDRS
src/fg/details/DependencyGraph.h
src/fg/details/PassNode.h
src/fg/details/Resource.h
src/fg/details/ResourceAllocator.h
src/fg/details/ResourceNode.h
src/fg/details/Utilities.h
src/fsr.h
@@ -17,6 +17,14 @@
#ifndef TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H
#define TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H
#ifdef __clang__
#pragma clang diagnostic push
// Disable the weak-vtables warning because we need the destructor to be inlined in the headers. It
// is not optimal (for build), but we have clients that compile their libraries (filament) and app
// in different rtti settings.
#pragma clang diagnostic ignored "-Wweak-vtables"
#endif
namespace filament::backend {
/**
@@ -69,4 +77,8 @@ protected:
} // namespace filament::backend
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif // TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H
+75 -68
View File
@@ -499,7 +499,7 @@ using descriptor_set_t = uint8_t;
using descriptor_binding_t = uint8_t;
struct DescriptorSetLayoutBinding {
struct DescriptorSetLayoutDescriptor {
static bool isSampler(DescriptorType type) noexcept {
return int(type) <= int(DescriptorType::SAMPLER_EXTERNAL);
}
@@ -513,8 +513,8 @@ struct DescriptorSetLayoutBinding {
DescriptorFlags flags = DescriptorFlags::NONE;
uint16_t count = 0;
friend bool operator==(DescriptorSetLayoutBinding const& lhs,
DescriptorSetLayoutBinding const& rhs) noexcept {
friend bool operator==(DescriptorSetLayoutDescriptor const& lhs,
DescriptorSetLayoutDescriptor const& rhs) noexcept {
return lhs.type == rhs.type &&
lhs.flags == rhs.flags &&
lhs.count == rhs.count &&
@@ -1009,98 +1009,99 @@ enum class CompressedPixelDataType : uint16_t {
*
* @see Texture
*/
// The [index] comments indicate the corresponding uint16_t values.
enum class TextureFormat : uint16_t {
// 8-bits per element
R8, R8_SNORM, R8UI, R8I, STENCIL8,
R8, R8_SNORM, R8UI, R8I, STENCIL8, // [0 - 4]
// 16-bits per element
R16F, R16UI, R16I,
RG8, RG8_SNORM, RG8UI, RG8I,
RGB565,
RGB9_E5, // 9995 is actually 32 bpp but it's here for historical reasons.
RGB5_A1,
RGBA4,
DEPTH16,
R16F, R16UI, R16I, // [5 - 7]
RG8, RG8_SNORM, RG8UI, RG8I, // [8 - 11]
RGB565, // [12]
RGB9_E5, // 9995 is actually 32 bpp but it's here for historical reasons. [13]
RGB5_A1, // [14]
RGBA4, // [15]
DEPTH16, // [16]
// 24-bits per element
RGB8, SRGB8, RGB8_SNORM, RGB8UI, RGB8I,
DEPTH24,
RGB8, SRGB8, RGB8_SNORM, RGB8UI, RGB8I, // [17 - 21]
DEPTH24, // [22]
// 32-bits per element
R32F, R32UI, R32I,
RG16F, RG16UI, RG16I,
R11F_G11F_B10F,
RGBA8, SRGB8_A8,RGBA8_SNORM,
UNUSED, // used to be rgbm
RGB10_A2, RGBA8UI, RGBA8I,
DEPTH32F, DEPTH24_STENCIL8, DEPTH32F_STENCIL8,
R32F, R32UI, R32I, // [23 - 25]
RG16F, RG16UI, RG16I, // [26 - 28]
R11F_G11F_B10F, // [29]
RGBA8, SRGB8_A8,RGBA8_SNORM, // [30 - 32]
UNUSED, // used to be rgbm [33]
RGB10_A2, RGBA8UI, RGBA8I, // [34 - 36]
DEPTH32F, DEPTH24_STENCIL8, DEPTH32F_STENCIL8, // [37 - 39]
// 48-bits per element
RGB16F, RGB16UI, RGB16I,
RGB16F, RGB16UI, RGB16I, // [40 - 42]
// 64-bits per element
RG32F, RG32UI, RG32I,
RGBA16F, RGBA16UI, RGBA16I,
RG32F, RG32UI, RG32I, // [43 - 45]
RGBA16F, RGBA16UI, RGBA16I, // [46 - 48]
// 96-bits per element
RGB32F, RGB32UI, RGB32I,
RGB32F, RGB32UI, RGB32I, // [49 - 51]
// 128-bits per element
RGBA32F, RGBA32UI, RGBA32I,
RGBA32F, RGBA32UI, RGBA32I, // [52 - 54]
// compressed formats
// Mandatory in GLES 3.0 and GL 4.3
EAC_R11, EAC_R11_SIGNED, EAC_RG11, EAC_RG11_SIGNED,
ETC2_RGB8, ETC2_SRGB8,
ETC2_RGB8_A1, ETC2_SRGB8_A1,
ETC2_EAC_RGBA8, ETC2_EAC_SRGBA8,
EAC_R11, EAC_R11_SIGNED, EAC_RG11, EAC_RG11_SIGNED, // [55 - 58]
ETC2_RGB8, ETC2_SRGB8, // [59 - 60]
ETC2_RGB8_A1, ETC2_SRGB8_A1, // [61 - 62]
ETC2_EAC_RGBA8, ETC2_EAC_SRGBA8, // [63 - 64]
// Available everywhere except Android/iOS
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA,
DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA,
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA, // [65 - 68]
DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA, // [69 - 72]
// ASTC formats are available with a GLES extension
RGBA_ASTC_4x4,
RGBA_ASTC_5x4,
RGBA_ASTC_5x5,
RGBA_ASTC_6x5,
RGBA_ASTC_6x6,
RGBA_ASTC_8x5,
RGBA_ASTC_8x6,
RGBA_ASTC_8x8,
RGBA_ASTC_10x5,
RGBA_ASTC_10x6,
RGBA_ASTC_10x8,
RGBA_ASTC_10x10,
RGBA_ASTC_12x10,
RGBA_ASTC_12x12,
SRGB8_ALPHA8_ASTC_4x4,
SRGB8_ALPHA8_ASTC_5x4,
SRGB8_ALPHA8_ASTC_5x5,
SRGB8_ALPHA8_ASTC_6x5,
SRGB8_ALPHA8_ASTC_6x6,
SRGB8_ALPHA8_ASTC_8x5,
SRGB8_ALPHA8_ASTC_8x6,
SRGB8_ALPHA8_ASTC_8x8,
SRGB8_ALPHA8_ASTC_10x5,
SRGB8_ALPHA8_ASTC_10x6,
SRGB8_ALPHA8_ASTC_10x8,
SRGB8_ALPHA8_ASTC_10x10,
SRGB8_ALPHA8_ASTC_12x10,
SRGB8_ALPHA8_ASTC_12x12,
RGBA_ASTC_4x4, // [73]
RGBA_ASTC_5x4, // [74]
RGBA_ASTC_5x5, // [75]
RGBA_ASTC_6x5, // [76]
RGBA_ASTC_6x6, // [77]
RGBA_ASTC_8x5, // [78]
RGBA_ASTC_8x6, // [79]
RGBA_ASTC_8x8, // [80]
RGBA_ASTC_10x5, // [81]
RGBA_ASTC_10x6, // [82]
RGBA_ASTC_10x8, // [83]
RGBA_ASTC_10x10, // [84]
RGBA_ASTC_12x10, // [85]
RGBA_ASTC_12x12, // [86]
SRGB8_ALPHA8_ASTC_4x4, // [87]
SRGB8_ALPHA8_ASTC_5x4, // [88]
SRGB8_ALPHA8_ASTC_5x5, // [89]
SRGB8_ALPHA8_ASTC_6x5, // [90]
SRGB8_ALPHA8_ASTC_6x6, // [91]
SRGB8_ALPHA8_ASTC_8x5, // [92]
SRGB8_ALPHA8_ASTC_8x6, // [93]
SRGB8_ALPHA8_ASTC_8x8, // [94]
SRGB8_ALPHA8_ASTC_10x5, // [95]
SRGB8_ALPHA8_ASTC_10x6, // [96]
SRGB8_ALPHA8_ASTC_10x8, // [97]
SRGB8_ALPHA8_ASTC_10x10, // [98]
SRGB8_ALPHA8_ASTC_12x10, // [99]
SRGB8_ALPHA8_ASTC_12x12, // [100]
// RGTC formats available with a GLES extension
RED_RGTC1, // BC4 unsigned
SIGNED_RED_RGTC1, // BC4 signed
RED_GREEN_RGTC2, // BC5 unsigned
SIGNED_RED_GREEN_RGTC2, // BC5 signed
RED_RGTC1, // BC4 unsigned [101]
SIGNED_RED_RGTC1, // BC4 signed [102]
RED_GREEN_RGTC2, // BC5 unsigned [103]
SIGNED_RED_GREEN_RGTC2, // BC5 signed [104]
// BPTC formats available with a GLES extension
RGB_BPTC_SIGNED_FLOAT, // BC6H signed
RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned
RGBA_BPTC_UNORM, // BC7
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB
RGB_BPTC_SIGNED_FLOAT, // BC6H signed [105]
RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned [106]
RGBA_BPTC_UNORM, // BC7 [107]
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB [108]
};
TextureType getTextureType(TextureFormat format) noexcept;
@@ -1385,7 +1386,7 @@ static_assert(sizeof(SamplerParams) <= sizeof(uint64_t),
struct DescriptorSetLayout {
std::variant<utils::StaticString, utils::CString, std::monostate> label;
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
utils::FixedCapacityVector<DescriptorSetLayoutDescriptor> descriptors;
};
//! blending equation function
@@ -1715,6 +1716,12 @@ using CompositorTiming = Platform::CompositorTiming;
using AsynchronousMode = Platform::AsynchronousMode;
using AsyncCallId = uint32_t;
static constexpr AsyncCallId InvalidAsyncCallId = std::numeric_limits<AsyncCallId>::max();
using AsynchronousMode = Platform::AsynchronousMode;
} // namespace filament::backend
template<> struct utils::EnableBitMaskOperators<filament::backend::ShaderStageFlags>
+35 -21
View File
@@ -31,6 +31,10 @@
#include <memory>
#include <mutex>
namespace utils {
class FeatureFlagManager;
}
namespace filament::backend {
class CallbackHandler;
@@ -104,6 +108,11 @@ public:
/** duration in nanosecond on the std::steady_clock */
using duration_ns = int64_t;
static constexpr time_point_ns INVALID = -1; //!< value not supported
/**
* The time delta [ns] between subsequent composition events.
*/
duration_ns compositeInterval;
/**
* The timestamp [ns] since epoch of the next time the compositor will begin composition.
* This is effectively the deadline for when the compositor must receive a newly queued
@@ -111,11 +120,6 @@ public:
*/
time_point_ns compositeDeadline;
/**
* The time delta [ns] between subsequent composition events.
*/
duration_ns compositeInterval;
/**
* The time delta [ns] between the start of composition and the expected present time of
* that composition. This can be used to estimate the latency of the actual present time.
@@ -123,22 +127,9 @@ public:
duration_ns compositeToPresentLatency;
/**
* The timestamp [ns] since epoch of the system's expected presentation time.
* INVALID if not supported.
* Expected latency [ns] of frame presentation relative to vsync.
*/
time_point_ns expectedPresentTime;
/**
* The timestamp [ns] since epoch of the current frame's start (i.e. vsync)
* INVALID if not supported.
*/
time_point_ns frameTime;
/**
* The timestamp [ns] since epoch of the current frame's deadline
* INVALID if not supported.
*/
time_point_ns frameTimelineDeadline;
duration_ns expectedPresentLatency;
};
struct FrameTimestamps {
@@ -278,6 +269,11 @@ public:
};
struct DriverConfig {
/**
* Reference to the system's FeatureFlagManager. Can be nullptr.
*/
utils::FeatureFlagManager const * UTILS_NULLABLE featureFlagManager = nullptr;
/**
* Size of handle arena in bytes. Setting to 0 indicates default value is to be used.
* Driver clamps to valid values.
@@ -288,7 +284,8 @@ public:
/**
* Set to `true` to forcibly disable parallel shader compilation in the backend.
* Currently only honored by the GL and Metal backends.
* Currently only honored by the GL and Metal backends, and the Vulkan backend
* when some experimental features are enabled.
*/
bool disableParallelShaderCompile = false;
@@ -319,6 +316,12 @@ public:
*/
StereoscopicType stereoscopicType = StereoscopicType::NONE;
/*
* The number of eyes to render when stereoscopic rendering is enabled. Supported values are
* between 1 and Engine::getMaxStereoscopicEyes() (inclusive).
*/
uint8_t stereoscopicEyeCount = 2;
/**
* Assert the native window associated to a SwapChain is valid when calling makeCurrent().
* This is only supported for:
@@ -340,6 +343,17 @@ public:
*/
GpuContextPriority gpuContextPriority = GpuContextPriority::DEFAULT;
/**
* Enables asynchronous pipeline cache preloading, if supported on this device.
* This is only supported for:
* - VulkanPlatform
* When the following device extensions are available:
* - VK_KHR_dynamic_rendering
* - VK_EXT_vertex_input_dynamic_state
* Should be enabled only for devices where it has been shown this is effective.
*/
bool vulkanEnableAsyncPipelineCachePrewarming = false;
/**
* Bypass the staging buffer because the device is of Unified Memory Architecture.
* This is only supported for:
@@ -50,7 +50,13 @@ public:
descriptor_binding_t binding;
};
struct DescriptorSetLayoutBinding {
descriptor_set_t set;
DescriptorSetLayout layout;
};
using SpecializationConstant = std::variant<int32_t, float, bool>;
using DescriptorSetLayoutArray = utils::FixedCapacityVector<DescriptorSetLayoutBinding>;
struct Uniform { // For ES2 support
utils::CString name; // full qualified name of the uniform field
@@ -147,6 +153,19 @@ public:
return mDescriptorBindings;
}
inline Program& descriptorLayout(backend::descriptor_set_t set,
DescriptorSetLayout descriptorLayout) noexcept {
mDescriptorLayouts.push_back({
.set = set,
.layout = std::move(descriptorLayout),
});
return *this;
}
const DescriptorSetLayoutArray& getDescriptorSetLayouts() const noexcept {
return mDescriptorLayouts;
}
utils::FixedCapacityVector<PushConstant> const& getPushConstants(
ShaderStage stage) const noexcept {
return mPushConstants[static_cast<uint8_t>(stage)];
@@ -176,6 +195,11 @@ private:
std::array<utils::FixedCapacityVector<PushConstant>, SHADER_TYPE_COUNT> mPushConstants;
DescriptorSetInfo mDescriptorBindings;
// Descriptions for descriptor set layouts that may be used for this Program, which
// can be useful for attempting to compile the pipeline ahead of time.
DescriptorSetLayoutArray mDescriptorLayouts =
DescriptorSetLayoutArray::with_capacity(MAX_DESCRIPTOR_SET_COUNT);
// For ES2 support only
AttributesInfo mAttributes;
BindingUniformsInfo mBindingUniformsInfo;
@@ -64,7 +64,7 @@ protected:
std::vector<int> mAttribs;
// For shared contexts
static constexpr int SHARED_CONTEXT_NUM = 1;
static constexpr int SHARED_CONTEXT_NUM = 2;
std::vector<HGLRC> mAdditionalContexts;
std::atomic<int> mNextFreeSharedContextIndex{0};
};
@@ -28,6 +28,7 @@
#include <utils/Hash.h>
#include <utils/PrivateImplementation.h>
#include <cstring>
#include <cstddef>
#include <functional>
#include <string>
@@ -55,14 +56,31 @@ struct VulkanCmdFence;
*/
class VulkanPlatform : public Platform, utils::PrivateImplementation<VulkanPlatformPrivate> {
public:
/**
* Encapsulates information required to instantiate a known external format,
* typically for the purpose of preloading a pipeline cache for materials using
* external formats for samplers.
*/
struct ExternalYcbcrFormat {
uint64_t externalFormat;
VkSamplerYcbcrModelConversion ycbcrModelConversion;
VkSamplerYcbcrRange ycbcrRange;
};
struct ExtensionHashFn {
std::size_t operator()(utils::CString const& s) const noexcept {
return std::hash<std::string>{}(s.data());
}
};
// Note: utils::CString::operator== has an edge case that breaks for the extension set.
// Instead, we'll provide our own comparator.
struct ExtensionEqualFn {
bool operator()(utils::CString const& a, utils::CString const& b) const noexcept {
return strcmp(a.c_str(), b.c_str()) == 0;
}
};
// Utility for managing device or instance extensions during initialization.
using ExtensionSet = std::unordered_set<utils::CString, ExtensionHashFn>;
using ExtensionSet = std::unordered_set<utils::CString, ExtensionHashFn, ExtensionEqualFn>;
/**
* A collection of handles to objects and metadata that comprises a Vulkan context. The client
@@ -437,6 +455,50 @@ protected:
std::shared_ptr<VulkanCmdFence> fenceStatus;
};
/**
* Creates the VkInstance used by Filament's Vulkan backend.
*
* This method can be overridden in subclasses to customize VkInstance creation, such as
* adding application-specific layers or extensions.
*
* The provided `createInfo` contains layers and extensions required by Filament.
* If you override this method and need to modify the `createInfo` struct, you must first
* make a copy of it and modify the copy.
*
* @param createInfo The VkInstanceCreateInfo prepared by Filament.
* @return The created VkInstance, or VK_NULL_HANDLE on failure.
*/
virtual VkInstance createVkInstance(VkInstanceCreateInfo const& createInfo) noexcept;
/**
* Selects a VkPhysicalDevice (GPU) for Filament's Vulkan backend to use.
*
* This method can be overridden in subclasses to implement custom GPU selection logic.
* For example, an application might override this to prefer a discrete GPU over an
* integrated one based on device properties.
*
* The default implementation selects the first device that meets Filament's requirements.
*
* @param instance The VkInstance to enumerate devices from.
* @return The selected VkPhysicalDevice, or VK_NULL_HANDLE if no suitable device is found.
*/
virtual VkPhysicalDevice selectVkPhysicalDevice(VkInstance instance) noexcept;
/**
* Creates the VkDevice used by Filament's Vulkan backend.
*
* This method can be overridden in subclasses to customize VkDevice creation, such as
* adding application-specific extensions or enabling features.
*
* The provided `createInfo` contains extensions and features required by Filament.
* If you override this method and need to modify the `createInfo` struct, you must first
* make a copy of it and modify the copy.
*
* @param createInfo The VkDeviceCreateInfo prepared by Filament.
* @return The created VkDevice, or VK_NULL_HANDLE on failure.
*/
virtual VkDevice createVkDevice(VkDeviceCreateInfo const& createInfo) noexcept;
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
virtual ExtensionSet getSwapchainInstanceExtensions() const = 0;
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
@@ -449,7 +511,48 @@ protected:
*/
bool isTransientAttachmentSupported() const noexcept;
/**
* For pipeline cache prewarming, if external samplers are present, we need to build
* the fake pipeline using the proper formats specified. Since there's no way to
* get these at material build time, we allow the app to register them before
* creating materials.
*
* @param format The format, containing the external format value which should be
* extracted from an AHardwareBuffer.
*/
void registerPipelineCachePrewarmExternalFormat(const ExternalYcbcrFormat& format) noexcept;
private:
/**
* Contains information about features that should be requested
* when calling vkCreateDevice, based on feature support from
* vkGetPhysicalDeviceFeatures2.
*/
struct MiscDeviceFeatures {
/**
* This allows creation of a VkGraphicsPipeline without a
* render pass specified.
*/
bool dynamicRendering;
/**
* Allows creation of a 2d image view, or 2d image view array,
* to be created from a 3d VkImage.
*/
bool imageView2Don3DImage;
};
void createInstance(ExtensionSet const& requiredExts) noexcept;
void queryAndSetDeviceFeatures(Platform::DriverConfig const& driverConfig,
ExtensionSet const& instExts, ExtensionSet const& deviceExts,
void* sharedContext) noexcept;
void createLogicalDeviceAndQueues(ExtensionSet const& deviceExtensions,
VkPhysicalDeviceFeatures const& features,
VkPhysicalDeviceVulkan11Features const& vk11Features, bool createProtectedQueue,
MiscDeviceFeatures const& requestedFeatures) noexcept;
friend struct VulkanPlatformPrivate;
};
@@ -81,7 +81,6 @@ public:
bool queryFrameTimestamps(SwapChain const* swapchain, uint64_t frameId,
FrameTimestamps* outFrameTimestamps) const noexcept override;
protected:
ExtensionSet getSwapchainInstanceExtensions() const override;
@@ -70,6 +70,11 @@ public:
// is where the driver can execute user callbacks.
virtual void purge() noexcept = 0;
// Called from the engine thread (render-thread) to execute the `callback` via the `handler` if
// it is available. Otherwise, if `handler` is null, the `callback` is executed on the main
// thread via `purge()`.
virtual void scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) = 0;
virtual ShaderModel getShaderModel() const noexcept = 0;
// The shader languages used for shaders for this driver in order of preference, used to inform
@@ -74,8 +74,9 @@
#define APPLY10(M, A, ...) EXPAND(M(A)), EXPAND(APPLY9(M, __VA_ARGS__))
#define APPLY11(M, A, ...) EXPAND(M(A)), EXPAND(APPLY10(M, __VA_ARGS__))
#define APPLY12(M, A, ...) EXPAND(M(A)), EXPAND(APPLY11(M, __VA_ARGS__))
#define APPLY_N__(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, X, ...) APPLY##X
#define APPLY(M, ...) EXPAND(EXPAND(APPLY_N__(M, __VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(M, __VA_ARGS__))
#define APPLY13(M, A, ...) EXPAND(M(A)), EXPAND(APPLY12(M, __VA_ARGS__))
#define APPLY_N__(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, X, ...) APPLY##X
#define APPLY(M, ...) EXPAND(EXPAND(APPLY_N__(M, __VA_ARGS__, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(M, __VA_ARGS__))
#define PAIR_ARGS_0(M, ...)
@@ -91,11 +92,12 @@
#define PAIR_ARGS_10(M, X, Y, ...) M(X, Y), EXPAND(PAIR_ARGS_9(M, __VA_ARGS__))
#define PAIR_ARGS_11(M, X, Y, ...) M(X, Y), EXPAND(PAIR_ARGS_10(M, __VA_ARGS__))
#define PAIR_ARGS_12(M, X, Y, ...) M(X, Y), EXPAND(PAIR_ARGS_11(M, __VA_ARGS__))
#define PAIR_ARGS_13(M, X, Y, ...) M(X, Y), EXPAND(PAIR_ARGS_12(M, __VA_ARGS__))
#define PAIR_ARGS_N__(_0, E1, _1, E2, _2, E3, _3, E4, _4, E5, _5, E6, _6, E7, _7, E8, _8, E9, _9, E10, _10, E11, _11, E12, _12, X, ...) PAIR_ARGS_##X
#define PAIR_ARGS_N__(_0, E1, _1, E2, _2, E3, _3, E4, _4, E5, _5, E6, _6, E7, _7, E8, _8, E9, _9, E10, _10, E11, _11, E12, _12, E13, _13, X, ...) PAIR_ARGS_##X
#define PAIR_ARGS_N(M, ...) \
EXPAND(EXPAND(PAIR_ARGS_N__(0, ##__VA_ARGS__, 12, E, 11, E, 10, E, 9, E, 8, E, 7, E, 6, E, 5, E, 4, E, 3, E, 2, E, 1, E, 0))(M, __VA_ARGS__))
EXPAND(EXPAND(PAIR_ARGS_N__(0, ##__VA_ARGS__, 13, E, 12, E, 11, E, 10, E, 9, E, 8, E, 7, E, 6, E, 5, E, 4, E, 3, E, 2, E, 1, E, 0))(M, __VA_ARGS__))
#define ARG(T, P) T P
@@ -192,11 +194,27 @@ DECL_DRIVER_API_TAGGED_R_N(backend::IndexBufferHandle, createIndexBuffer,
uint32_t, indexCount,
backend::BufferUsage, usage)
DECL_DRIVER_API_TAGGED_R_N(backend::IndexBufferHandle, createIndexBufferAsync,
backend::ElementType, elementType,
uint32_t, indexCount,
backend::BufferUsage, usage,
backend::CallbackHandler*, handler,
backend::CallbackHandler::Callback, callback,
void*, user)
DECL_DRIVER_API_TAGGED_R_N(backend::BufferObjectHandle, createBufferObject,
uint32_t, byteCount,
backend::BufferObjectBinding, bindingType,
backend::BufferUsage, usage)
DECL_DRIVER_API_TAGGED_R_N(backend::BufferObjectHandle, createBufferObjectAsync,
uint32_t, byteCount,
backend::BufferObjectBinding, bindingType,
backend::BufferUsage, usage,
backend::CallbackHandler*, handler,
backend::CallbackHandler::Callback, callback,
void*, user)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTexture,
backend::SamplerType, target,
uint8_t, levels,
@@ -207,6 +225,19 @@ DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTexture,
uint32_t, depth,
backend::TextureUsage, usage)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureAsync,
backend::SamplerType, target,
uint8_t, levels,
backend::TextureFormat, format,
uint8_t, samples,
uint32_t, width,
uint32_t, height,
uint32_t, depth,
backend::TextureUsage, usage,
backend::CallbackHandler*, handler,
backend::CallbackHandler::Callback, callback,
void*, user)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureView,
backend::TextureHandle, texture,
uint8_t, baseLevel,
@@ -219,6 +250,16 @@ DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureViewSwizzle,
backend::TextureSwizzle, b,
backend::TextureSwizzle, a)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureViewSwizzleAsync,
backend::TextureHandle, texture,
backend::TextureSwizzle, r,
backend::TextureSwizzle, g,
backend::TextureSwizzle, b,
backend::TextureSwizzle, a,
backend::CallbackHandler*, handler,
backend::CallbackHandler::Callback, callback,
void*, user)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureExternalImage2,
backend::SamplerType, target,
backend::TextureFormat, format,
@@ -254,6 +295,20 @@ DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, importTexture,
uint32_t, depth,
backend::TextureUsage, usage)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, importTextureAsync,
intptr_t, id,
backend::SamplerType, target,
uint8_t, levels,
backend::TextureFormat, format,
uint8_t, samples,
uint32_t, width,
uint32_t, height,
uint32_t, depth,
backend::TextureUsage, usage,
backend::CallbackHandler*, handler,
backend::CallbackHandler::Callback, callback,
void*, user)
DECL_DRIVER_API_TAGGED_R_N(backend::RenderPrimitiveHandle, createRenderPrimitive,
backend::VertexBufferHandle, vbh,
backend::IndexBufferHandle, ibh,
@@ -357,6 +412,7 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthStencilResolveSupported)
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isDepthStencilBlitSupported, backend::TextureFormat, format)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isProtectedTexturesSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isAsynchronousModeEnabled)
DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers)
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize)
DECL_DRIVER_API_SYNCHRONOUS_N(size_t, getMaxTextureSize, backend::SamplerType, target)
@@ -382,16 +438,40 @@ DECL_DRIVER_API_N(setVertexBufferObject,
uint32_t, index,
backend::BufferObjectHandle, bufferObject)
DECL_DRIVER_API_R_N(backend::AsyncCallId, setVertexBufferObjectAsync,
backend::VertexBufferHandle, vbh,
uint32_t, index,
backend::BufferObjectHandle, bufferObject,
backend::CallbackHandler*, handler,
backend::CallbackHandler::Callback, callback,
void*, user)
DECL_DRIVER_API_N(updateIndexBuffer,
backend::IndexBufferHandle, ibh,
backend::BufferDescriptor&&, data,
uint32_t, byteOffset)
DECL_DRIVER_API_R_N(backend::AsyncCallId, updateIndexBufferAsync,
backend::IndexBufferHandle, ibh,
backend::BufferDescriptor&&, data,
uint32_t, byteOffset,
backend::CallbackHandler*, handler,
backend::CallbackHandler::Callback, callback,
void*, user)
DECL_DRIVER_API_N(updateBufferObject,
backend::BufferObjectHandle, ibh,
backend::BufferDescriptor&&, data,
uint32_t, byteOffset)
DECL_DRIVER_API_R_N(backend::AsyncCallId, updateBufferObjectAsync,
backend::BufferObjectHandle, ibh,
backend::BufferDescriptor&&, data,
uint32_t, byteOffset,
backend::CallbackHandler*, handler,
backend::CallbackHandler::Callback, callback,
void*, user)
DECL_DRIVER_API_N(updateBufferObjectUnsynchronized,
backend::BufferObjectHandle, boh,
backend::BufferDescriptor&&, data,
@@ -411,6 +491,20 @@ DECL_DRIVER_API_N(update3DImage,
uint32_t, depth,
backend::PixelBufferDescriptor&&, data)
DECL_DRIVER_API_R_N(backend::AsyncCallId, update3DImageAsync,
backend::TextureHandle, th,
uint32_t, level,
uint32_t, xoffset,
uint32_t, yoffset,
uint32_t, zoffset,
uint32_t, width,
uint32_t, height,
uint32_t, depth,
backend::PixelBufferDescriptor&&, data,
backend::CallbackHandler*, handler,
backend::CallbackHandler::Callback, callback,
void*, user)
DECL_DRIVER_API_N(generateMipmaps,
backend::TextureHandle, th)
@@ -577,6 +671,19 @@ DECL_DRIVER_API_N(dispatchCompute,
DECL_DRIVER_API_N(scissor,
Viewport, scissor)
/*
* Asyncronous operation helpers
* --------------------
*/
DECL_DRIVER_API_R_N(backend::AsyncCallId, queueCommandAsync,
utils::Invocable<void(void)>&&, command,
backend::CallbackHandler*, handler,
backend::CallbackHandler::Callback, callback,
void*, user)
DECL_DRIVER_API_SYNCHRONOUS_N(bool, cancelAsyncJob, backend::AsyncCallId, jobId)
#if defined(__clang__)
#pragma clang diagnostic pop
+53 -36
View File
@@ -28,7 +28,9 @@
#include <utils/Logger.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/JobSystem.h>
#include <utils/ostream.h>
#include <utils/Panic.h>
#include <math/half.h>
#include <math/vec2.h>
@@ -47,45 +49,41 @@ using namespace filament::math;
namespace filament::backend {
DriverBase::DriverBase() noexcept {
if constexpr (UTILS_HAS_THREADING) {
// This thread services user callbacks
mServiceThread = std::thread([this]() {
do {
auto& serviceThreadCondition = mServiceThreadCondition;
auto& serviceThreadCallbackQueue = mServiceThreadCallbackQueue;
DriverBase::DriverBase(const Platform::DriverConfig& driverConfig) noexcept
: mDriverConfig(driverConfig) {
#if UTILS_HAS_THREADING
// This thread services user callbacks
mServiceThread = std::thread([this]() {
JobSystem::setThreadName("ServiceThread");
do {
auto& serviceThreadCondition = mServiceThreadCondition;
auto& serviceThreadCallbackQueue = mServiceThreadCallbackQueue;
// wait for some callbacks to dispatch
std::unique_lock<std::mutex> lock(mServiceThreadLock);
while (serviceThreadCallbackQueue.empty() && !mExitRequested) {
serviceThreadCondition.wait(lock);
}
if (mExitRequested) {
break;
}
// move the callbacks to a temporary vector
auto callbacks(std::move(serviceThreadCallbackQueue));
lock.unlock();
// and make sure to call them without our lock held
for (auto[handler, callback, user]: callbacks) {
handler->post(user, callback);
}
} while (true);
});
}
// wait for some callbacks to dispatch
std::unique_lock<std::mutex> lock(mServiceThreadLock);
while (serviceThreadCallbackQueue.empty() && !mExitRequested) {
serviceThreadCondition.wait(lock);
}
if (mExitRequested) {
break;
}
// move the callbacks to a temporary vector
auto callbacks(std::move(serviceThreadCallbackQueue));
lock.unlock();
// and make sure to call them without our lock held
for (auto[handler, callback, user]: callbacks) {
handler->post(user, callback);
}
} while (true);
});
#endif
}
DriverBase::~DriverBase() noexcept {
assert_invariant(mCallbacks.empty());
assert_invariant(mServiceThreadCallbackQueue.empty());
if constexpr (UTILS_HAS_THREADING) {
// quit our service thread
std::unique_lock<std::mutex> lock(mServiceThreadLock);
mExitRequested = true;
mServiceThreadCondition.notify_one();
lock.unlock();
mServiceThread.join();
}
#if UTILS_HAS_THREADING
stopServiceThread();
#endif
}
// ------------------------------------------------------------------------------------------------
@@ -109,11 +107,14 @@ void DriverBase::CallbackData::release(CallbackData* data) {
void DriverBase::scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) {
if (handler && UTILS_HAS_THREADING) {
#if UTILS_HAS_THREADING
if (handler) {
std::lock_guard<std::mutex> const lock(mServiceThreadLock);
mServiceThreadCallbackQueue.emplace_back(handler, callback, user);
mServiceThreadCondition.notify_one();
} else {
} else
#endif
{
std::lock_guard<std::mutex> const lock(mPurgeLock);
mCallbacks.emplace_back(user, callback);
}
@@ -181,6 +182,22 @@ void DriverBase::debugCommandEnd(CommandStream* cmds, bool synchronous,
}
}
#if UTILS_HAS_THREADING
void DriverBase::stopServiceThread() noexcept {
if (!mServiceThread.joinable()) {
return;
}
{
std::lock_guard<std::mutex> lock(mServiceThreadLock);
mExitRequested = true;
}
mServiceThreadCondition.notify_one();
mServiceThread.join();
assert_invariant(mServiceThreadCallbackQueue.empty());
}
#endif
size_t Driver::getElementTypeSize(ElementType type) noexcept {
switch (type) {
case ElementType::BYTE: return sizeof(int8_t);
+33 -12
View File
@@ -72,22 +72,24 @@ struct HwVertexBuffer : public HwBase {
};
struct HwBufferObject : public HwBase {
uint32_t byteCount{};
uint32_t byteCount : 31;
uint32_t asynchronous : 1;
HwBufferObject() noexcept = default;
explicit HwBufferObject(uint32_t byteCount) noexcept : byteCount(byteCount) {}
explicit HwBufferObject(uint32_t byteCount, bool async) noexcept : byteCount(byteCount), asynchronous(async) {}
};
struct HwMemoryMappedBuffer : public HwBase {
};
struct HwIndexBuffer : public HwBase {
uint32_t count : 27;
uint32_t count : 26; // 67M indices
uint32_t elementSize : 5;
uint32_t asynchronous : 1;
HwIndexBuffer() noexcept : count{}, elementSize{} { }
HwIndexBuffer(uint8_t elementSize, uint32_t indexCount) noexcept :
count(indexCount), elementSize(elementSize) {
HwIndexBuffer(uint8_t elementSize, uint32_t indexCount, bool async) noexcept :
count(indexCount), elementSize(elementSize), asynchronous(async) {
// we could almost store elementSize on 4 bits because it's never > 16 and never 0
assert_invariant(elementSize > 0 && elementSize <= 16);
assert_invariant(indexCount < (1u << 27));
@@ -120,16 +122,19 @@ struct HwTexture : public HwBase {
uint8_t levels : 4; // This allows up to 15 levels (max texture size of 32768 x 32768)
uint8_t samples : 4; // Sample count per pixel (should always be a power of 2)
TextureFormat format{};
uint8_t reserved0 = 0;
struct {
uint8_t asynchronous : 1;
uint8_t reserved : 7;
};
TextureUsage usage{};
uint16_t reserved1 = 0;
HwStream* hwStream = nullptr;
HwTexture() noexcept : levels{}, samples{} {}
HwTexture(backend::SamplerType target, uint8_t levels, uint8_t samples,
uint32_t width, uint32_t height, uint32_t depth, TextureFormat fmt, TextureUsage usage) noexcept
: width(width), height(height), depth(depth),
target(target), levels(levels), samples(samples), format(fmt), usage(usage) { }
HwTexture(backend::SamplerType target, uint8_t levels, uint8_t samples, uint32_t width,
uint32_t height, uint32_t depth, TextureFormat fmt, TextureUsage usage, bool async) noexcept
: width(width), height(height), depth(depth), target(target), levels(levels),
samples(samples), format(fmt), asynchronous(async), usage(usage) {}
};
struct HwRenderTarget : public HwBase {
@@ -168,11 +173,13 @@ struct HwTimerQuery : public HwBase {
/*
* Base class of all Driver implementations
* If multithreading is supported, this class creates a `ServiceThread` responsible for executing
* user handlers.
*/
class DriverBase : public Driver {
public:
DriverBase() noexcept;
explicit DriverBase(const Platform::DriverConfig& driverConfig) noexcept;
~DriverBase() noexcept override;
void purge() noexcept final;
@@ -205,7 +212,7 @@ public:
});
}
void scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback);
void scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) final;
// --------------------------------------------------------------------------------------------
// Privates
@@ -214,6 +221,10 @@ public:
protected:
class CallbackDataDetails;
Platform::DriverConfig const& getDriverConfig() const noexcept {
return mDriverConfig;
}
void scheduleDestroy(BufferDescriptor&& buffer) {
if (buffer.hasCallback()) {
scheduleDestroySlow(std::move(buffer));
@@ -227,15 +238,25 @@ protected:
void debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
void debugCommandEnd(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
#if UTILS_HAS_THREADING
// Stops the `ServiceThread`. This method is called during destruction but may be called
// explicitly if earlier shutdown is needed. This method is idempotent.
void stopServiceThread() noexcept;
#endif
private:
const Platform::DriverConfig mDriverConfig;
std::mutex mPurgeLock;
std::vector<std::pair<void*, CallbackHandler::Callback>> mCallbacks;
#if UTILS_HAS_THREADING
std::thread mServiceThread;
std::mutex mServiceThreadLock;
std::condition_variable mServiceThreadCondition;
std::vector<std::tuple<CallbackHandler*, CallbackHandler::Callback, void*>> mServiceThreadCallbackQueue;
bool mExitRequested = false;
#endif
};
+1 -1
View File
@@ -194,7 +194,7 @@ void Platform::debugUpdateStat(const char* key, uint64_t intValue) {
callback = mDebugUpdateStat;
}
if (callback) {
(*callback)(key, intValue, "");
(*callback)(key, intValue, utils::CString(""));
}
}
+1
View File
@@ -161,6 +161,7 @@ private:
const std::function<void(const BufferState&, MetalBuffer*, uint32_t)>& f);
backend::StereoscopicType const mStereoscopicType;
backend::AsynchronousMode const mAsynchronousMode;
};
} // namespace backend
+123 -2
View File
@@ -111,14 +111,16 @@ Dispatcher MetalDriver::getDispatcher() const noexcept {
MetalDriver::MetalDriver(
PlatformMetal* platform, const Platform::DriverConfig& driverConfig) noexcept
: mPlatform(*platform),
: DriverBase(driverConfig),
mPlatform(*platform),
mContext(new MetalContext),
mHandleAllocator(
"Handles",
driverConfig.handleArenaSize,
driverConfig.disableHandleUseAfterFreeCheck,
driverConfig.disableHeapHandleTags),
mStereoscopicType(driverConfig.stereoscopicType) {
mStereoscopicType(driverConfig.stereoscopicType),
mAsynchronousMode(driverConfig.asynchronousMode) {
mContext->driver = this;
TrackedMetalBuffer::setPlatform(platform);
@@ -461,6 +463,12 @@ void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elem
mHandleAllocator.associateTagToHandle(ibh.getId(), std::move(tag));
}
void MetalDriver::createIndexBufferAsyncR(Handle<HwIndexBuffer> ibh, ElementType elementType,
uint32_t indexCount, BufferUsage usage, CallbackHandler* handler,
CallbackHandler::Callback callback, void* user, utils::ImmutableCString&& tag) {
// TODO: implement this.
}
void MetalDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, utils::ImmutableCString&& tag) {
auto* bufferObject =
@@ -472,6 +480,12 @@ void MetalDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteC
mHandleAllocator.associateTagToHandle(boh.getId(), std::move(tag));
}
void MetalDriver::createBufferObjectAsyncR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, CallbackHandler* handler,
CallbackHandler::Callback callback, void* user, utils::ImmutableCString&& tag) {
// TODO: implement this.
}
// fixme: TextureUsage is a bitfield
inline const char* stringify(TextureUsage usage) {
switch (usage) {
@@ -523,6 +537,13 @@ void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createTextureAsyncR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, TextureUsage usage, CallbackHandler* handler,
CallbackHandler::Callback callback, void* user, utils::ImmutableCString&& tag) {
// TODO: implement this.
}
void MetalDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
uint8_t baseLevel, uint8_t levelCount, utils::ImmutableCString&& tag) {
MetalTexture const* src = handle_cast<MetalTexture>(srch);
@@ -543,6 +564,13 @@ void MetalDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTextu
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createTextureViewSwizzleAsyncR(Handle<HwTexture> th, Handle<HwTexture> srch,
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
backend::TextureSwizzle a, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user, utils::ImmutableCString&& tag) {
// TODO: implement this.
}
void MetalDriver::createTextureExternalImage2R(Handle<HwTexture> th,
backend::SamplerType target,
backend::TextureFormat format,
@@ -602,6 +630,14 @@ void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::importTextureAsyncR(Handle<HwTexture> th, intptr_t i,
SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, TextureUsage usage, CallbackHandler* handler,
CallbackHandler::Callback callback, void* user, utils::ImmutableCString&& tag) {
// TODO: implement this.
}
void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
PrimitiveType pt, utils::ImmutableCString&& tag) {
@@ -794,14 +830,26 @@ Handle<HwIndexBuffer> MetalDriver::createIndexBufferS() noexcept {
return alloc_handle<MetalIndexBuffer>();
}
Handle<HwIndexBuffer> MetalDriver::createIndexBufferAsyncS() noexcept {
return alloc_handle<MetalIndexBuffer>();
}
Handle<HwBufferObject> MetalDriver::createBufferObjectS() noexcept {
return alloc_handle<MetalBufferObject>();
}
Handle<HwBufferObject> MetalDriver::createBufferObjectAsyncS() noexcept {
return alloc_handle<MetalBufferObject>();
}
Handle<HwTexture> MetalDriver::createTextureS() noexcept {
return alloc_handle<MetalTexture>();
}
Handle<HwTexture> MetalDriver::createTextureAsyncS() noexcept {
return alloc_handle<MetalTexture>();
}
Handle<HwTexture> MetalDriver::createTextureViewS() noexcept {
return alloc_handle<MetalTexture>();
}
@@ -810,6 +858,10 @@ Handle<HwTexture> MetalDriver::createTextureViewSwizzleS() noexcept {
return alloc_handle<MetalTexture>();
}
Handle<HwTexture> MetalDriver::createTextureViewSwizzleAsyncS() noexcept {
return alloc_handle<MetalTexture>();
}
Handle<HwTexture> MetalDriver::createTextureExternalImage2S() noexcept {
return alloc_handle<MetalTexture>();
}
@@ -826,6 +878,30 @@ Handle<HwTexture> MetalDriver::importTextureS() noexcept {
return alloc_handle<MetalTexture>();
}
Handle<HwTexture> MetalDriver::importTextureAsyncS() noexcept {
return alloc_handle<MetalTexture>();
}
AsyncCallId MetalDriver::update3DImageAsyncS() noexcept {
// TODO: implement this.
return InvalidAsyncCallId;
}
AsyncCallId MetalDriver::setVertexBufferObjectAsyncS() noexcept {
// TODO: implement this.
return InvalidAsyncCallId;
}
AsyncCallId MetalDriver::updateBufferObjectAsyncS() noexcept {
// TODO: implement this.
return InvalidAsyncCallId;
}
AsyncCallId MetalDriver::updateIndexBufferAsyncS() noexcept {
// TODO: implement this.
return InvalidAsyncCallId;
}
Handle<HwRenderPrimitive> MetalDriver::createRenderPrimitiveS() noexcept {
return alloc_handle<MetalRenderPrimitive>();
}
@@ -874,6 +950,11 @@ Handle<HwDescriptorSet> MetalDriver::createDescriptorSetS() noexcept {
return alloc_handle<MetalDescriptorSet>();
}
AsyncCallId MetalDriver::queueCommandAsyncS() noexcept {
// TODO: implement this.
return InvalidAsyncCallId;
}
void MetalDriver::destroyVertexBufferInfo(Handle<HwVertexBufferInfo> vbih) {
if (vbih) {
destruct_handle<MetalVertexBufferInfo>(vbih);
@@ -1216,6 +1297,10 @@ bool MetalDriver::isDepthClampSupported() {
return mContext->supportsDepthClamp;
}
bool MetalDriver::isAsynchronousModeEnabled() {
return false;
}
bool MetalDriver::isWorkaroundNeeded(Workaround workaround) {
switch (workaround) {
case Workaround::SPLIT_EASU:
@@ -1291,6 +1376,12 @@ void MetalDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&
[&]() { return mHandleAllocator.getHandleTag(ibh.getId()).c_str_safe(); });
scheduleDestroy(std::move(data));
}
void MetalDriver::updateIndexBufferAsyncR(AsyncCallId jobId, Handle<HwIndexBuffer> ibh,
BufferDescriptor&& data, uint32_t byteOffset, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
// TODO: implement this.
}
void MetalDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescriptor&& data,
uint32_t byteOffset) {
@@ -1307,6 +1398,12 @@ void MetalDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescripto
scheduleDestroy(std::move(data));
}
void MetalDriver::updateBufferObjectAsyncR(AsyncCallId jobId, Handle<HwBufferObject> boh,
BufferDescriptor&& data, uint32_t byteOffset, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
// TODO: implement this.
}
void MetalDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> boh,
BufferDescriptor&& data, uint32_t byteOffset) {
auto* bo = handle_cast<MetalBufferObject>(boh);
@@ -1332,6 +1429,12 @@ void MetalDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t ind
vertexBuffer->buffers[index] = bufferObject->getBuffer();
}
void MetalDriver::setVertexBufferObjectAsyncR(AsyncCallId jobId, Handle<HwVertexBuffer> vbh,
uint32_t index, Handle<HwBufferObject> boh, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
// TODO: implement this.
}
void MetalDriver::update3DImage(Handle<HwTexture> th, uint32_t level,
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
@@ -1348,6 +1451,14 @@ void MetalDriver::update3DImage(Handle<HwTexture> th, uint32_t level,
th.getId(), level, xoffset, yoffset, zoffset, width, height, depth);
}
void MetalDriver::update3DImageAsyncR(AsyncCallId jobId, Handle<HwTexture> th,
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
PixelBufferDescriptor&& data, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
// TODO: implement this.
}
void MetalDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) {
// FIXME: implement setupExternalImage2
}
@@ -2300,6 +2411,16 @@ void MetalDriver::copyToMemoryMappedBuffer(MemoryMappedBufferHandle mmbh, size_t
mmb->copy(*this, offset, std::move(data));
}
void MetalDriver::queueCommandAsyncR(AsyncCallId jobId, utils::Invocable<void()>&& command,
CallbackHandler* handler, CallbackHandler::Callback const callback, void* user) {
// TODO: implement this.
}
bool MetalDriver::cancelAsyncJob(AsyncCallId jobId) {
// TODO: implement this.
return false;
}
// explicit instantiation of the Dispatcher
template class ConcreteDispatcher<MetalDriver>;
+1 -1
View File
@@ -510,7 +510,7 @@ class MetalDescriptorSetLayout : public HwDescriptorSetLayout {
public:
MetalDescriptorSetLayout(DescriptorSetLayout&& layout) noexcept;
const auto& getBindings() const noexcept { return mLayout.bindings; }
const auto& getBindings() const noexcept { return mLayout.descriptors; }
size_t getDynamicOffsetCount() const noexcept { return mDynamicOffsetCount; }
+9 -9
View File
@@ -544,7 +544,7 @@ MetalAttachment MetalSwapChain::acquireBaseDrawable() {
MetalBufferObject::MetalBufferObject(MetalContext& context, BufferObjectBinding bindingType,
BufferUsage usage, uint32_t byteCount)
: HwBufferObject(byteCount), buffer(context, bindingType, usage, byteCount) {}
: HwBufferObject(byteCount, false), buffer(context, bindingType, usage, byteCount) {}
void MetalBufferObject::updateBuffer(
void* data, size_t size, uint32_t byteOffset, TagResolver&& getHandleTag) {
@@ -635,7 +635,7 @@ MetalVertexBuffer::MetalVertexBuffer(MetalContext& context,
}
MetalIndexBuffer::MetalIndexBuffer(MetalContext& context, BufferUsage usage, uint8_t elementSize,
uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount),
uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount, false),
buffer(context, BufferObjectBinding::VERTEX, usage, elementSize * indexCount, true) { }
MetalProgram::MetalProgram(MetalContext& context, Program&& program) noexcept
@@ -664,7 +664,7 @@ void MetalProgram::initialize() {
MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
TextureUsage usage) noexcept
: HwTexture(target, levels, samples, width, height, depth, format, usage), context(context) {
: HwTexture(target, levels, samples, width, height, depth, format, usage, false), context(context) {
assert_invariant(target != SamplerType::SAMPLER_EXTERNAL);
devicePixelFormat = decidePixelFormat(&context, format);
@@ -756,7 +756,7 @@ MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t le
MetalTexture::MetalTexture(MetalContext& context, MetalTexture const* src, uint8_t baseLevel,
uint8_t levelCount) noexcept
: HwTexture(src->target, src->levels, src->samples, src->width, src->height, src->depth,
src->format, src->usage),
src->format, src->usage, false),
context(context),
devicePixelFormat(src->devicePixelFormat),
externalImage(src->externalImage) {
@@ -767,7 +767,7 @@ MetalTexture::MetalTexture(MetalContext& context, MetalTexture const* src, uint8
MetalTexture::MetalTexture(MetalContext& context, MetalTexture const* src, TextureSwizzle r,
TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) noexcept
: HwTexture(src->target, src->levels, src->samples, src->width, src->height, src->depth,
src->format, src->usage),
src->format, src->usage, false),
context(context),
devicePixelFormat(src->devicePixelFormat),
externalImage(src->externalImage) {
@@ -786,13 +786,13 @@ MetalTexture::MetalTexture(MetalContext& context, MetalTexture const* src, Textu
MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t levels, TextureFormat format,
uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
id<MTLTexture> metalTexture) noexcept
: HwTexture(target, levels, samples, width, height, depth, format, usage), context(context) {
: HwTexture(target, levels, samples, width, height, depth, format, usage, false), context(context) {
texture = metalTexture;
}
MetalTexture::MetalTexture(MetalContext& context, TextureFormat format, uint32_t width,
uint32_t height, TextureUsage usage, CVPixelBufferRef image) noexcept
: HwTexture(SamplerType::SAMPLER_EXTERNAL, 1, 1, width, height, 1, format, usage),
: HwTexture(SamplerType::SAMPLER_EXTERNAL, 1, 1, width, height, 1, format, usage, false),
context(context),
externalImage(std::make_shared<MetalExternalImage>(
MetalExternalImage::createFromImage(context, image))) {
@@ -801,7 +801,7 @@ MetalTexture::MetalTexture(MetalContext& context, TextureFormat format, uint32_t
MetalTexture::MetalTexture(MetalContext& context, TextureFormat format, uint32_t width,
uint32_t height, TextureUsage usage, CVPixelBufferRef image, uint32_t plane) noexcept
: HwTexture(SamplerType::SAMPLER_EXTERNAL, 1, 1, width, height, 1, format, usage),
: HwTexture(SamplerType::SAMPLER_EXTERNAL, 1, 1, width, height, 1, format, usage, false),
context(context),
externalImage(std::make_shared<MetalExternalImage>(
MetalExternalImage::createFromImagePlane(context, image, plane))) {
@@ -1441,7 +1441,7 @@ void MetalFence::cancel() {
MetalDescriptorSetLayout::MetalDescriptorSetLayout(DescriptorSetLayout&& l) noexcept
: mLayout(std::move(l)) {
size_t dynamicBindings = 0;
for (const auto& binding : mLayout.bindings) {
for (const auto& binding : mLayout.descriptors) {
if (any(binding.flags & DescriptorFlags::DYNAMIC_OFFSET)) {
dynamicBindings++;
}
+13 -2
View File
@@ -28,10 +28,13 @@
namespace filament::backend {
Driver* NoopDriver::create() {
return new NoopDriver();
Platform::DriverConfig driverConfig;
return new NoopDriver(driverConfig);
}
NoopDriver::NoopDriver() noexcept = default;
NoopDriver::NoopDriver(const Platform::DriverConfig& driverConfig) noexcept
: DriverBase(driverConfig) {
}
NoopDriver::~NoopDriver() noexcept = default;
@@ -247,6 +250,10 @@ bool NoopDriver::isDepthClampSupported() {
return false;
}
bool NoopDriver::isAsynchronousModeEnabled() {
return false;
}
bool NoopDriver::isWorkaroundNeeded(Workaround) {
return false;
}
@@ -465,4 +472,8 @@ bool NoopDriver::queryFrameTimestamps(SwapChainHandle swapChain, uint64_t frameI
return false;
}
bool NoopDriver::cancelAsyncJob(AsyncCallId jobId) {
return false;
}
} // namespace filament
+2 -2
View File
@@ -26,7 +26,7 @@
namespace filament::backend {
class NoopDriver final : public DriverBase {
NoopDriver() noexcept;
NoopDriver(const Platform::DriverConfig& driverConfig) noexcept;
~NoopDriver() noexcept override;
Dispatcher getDispatcher() const noexcept final;
@@ -55,7 +55,7 @@ private:
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
RetType methodName##S() noexcept override { \
return RetType((RetType::HandleId)nextFakeHandle++); } \
return RetType(nextFakeHandle++); } \
UTILS_ALWAYS_INLINE inline void methodName##R(RetType, paramsDecl) { }
#include "private/backend/DriverAPI.inc"
+1 -1
View File
@@ -70,7 +70,7 @@ public:
assert_invariant(binding < MAX_DESCRIPTOR_COUNT);
assert_invariant(entry.binding < 128); // we reserve 1 bit for the type right now
mStorage[set][binding] = { uint8_t(entry.binding),
DescriptorSetLayoutBinding::isSampler(entry.type) };
DescriptorSetLayoutDescriptor::isSampler(entry.type) };
mActiveDescriptors[set].set(binding);
}
+2 -2
View File
@@ -30,8 +30,8 @@ namespace filament::backend {
struct GLBufferObject : public HwBufferObject {
using HwBufferObject::HwBufferObject;
GLBufferObject(uint32_t size,
BufferObjectBinding bindingType, BufferUsage usage) noexcept
: HwBufferObject(size), usage(usage), bindingType(bindingType) {
BufferObjectBinding bindingType, BufferUsage usage, bool async) noexcept
: HwBufferObject(size, async), usage(usage), bindingType(bindingType) {
}
struct {
@@ -56,7 +56,7 @@ GLDescriptorSet::GLDescriptorSet(OpenGLContext& gl, DescriptorSetLayoutHandle ds
// We have allocated enough storage for all descriptors. Now allocate the empty descriptor
// themselves.
for (auto const& entry : layout->bindings) {
for (auto const& entry : layout->descriptors) {
size_t const index = entry.binding;
// now we'll initialize the alternative for each way we can handle this descriptor.
@@ -372,10 +372,10 @@ void GLDescriptorSet::validate(HandleAllocatorGL& allocator,
UTILS_UNUSED_IN_RELEASE
bool const pipelineLayoutMatchesDescriptorSetLayout = std::equal(
dsl->bindings.begin(), dsl->bindings.end(),
cur->bindings.begin(),
[](DescriptorSetLayoutBinding const& lhs,
DescriptorSetLayoutBinding const& rhs) {
dsl->descriptors.begin(), dsl->descriptors.end(),
cur->descriptors.begin(),
[](DescriptorSetLayoutDescriptor const& lhs,
DescriptorSetLayoutDescriptor const& rhs) {
return lhs.type == rhs.type &&
lhs.stageFlags == rhs.stageFlags &&
lhs.binding == rhs.binding &&
@@ -33,12 +33,12 @@ struct GLDescriptorSetLayout : public HwDescriptorSetLayout, public DescriptorSe
explicit GLDescriptorSetLayout(DescriptorSetLayout&& layout) noexcept
: DescriptorSetLayout(std::move(layout)) {
std::sort(bindings.begin(), bindings.end(),
std::sort(descriptors.begin(), descriptors.end(),
[](auto&& lhs, auto&& rhs){
return lhs.binding < rhs.binding;
});
auto p = std::max_element(bindings.cbegin(), bindings.cend(),
auto p = std::max_element(descriptors.cbegin(), descriptors.cend(),
[](auto const& lhs, auto const& rhs) {
return lhs.binding < rhs.binding;
});
+3 -3
View File
@@ -373,8 +373,8 @@ public:
FeatureLevel getFeatureLevel() const noexcept { return mFeatureLevel; }
// This is the index of the context in use. Must be 0 or 1. This is used to manange the
// OpenGL name of ContainerObjects within each context.
// This is the index of the context in use. Must be either 0 (Unprotected) or 1 (Protected).
// This is used to manage the OpenGL name of ContainerObjects within each context.
uint32_t contextIndex = 0;
// Try to keep the State structure sorted by data-access patterns
@@ -536,7 +536,7 @@ private:
TimerQueryFactoryInterface* mTimerQueryFactory = nullptr;
std::vector<std::function<void(OpenGLContext&)>> mDestroyWithNormalContext;
RenderPrimitive mDefaultVAO;
std::optional<GLuint> mDefaultFbo[2];
std::optional<GLuint> mDefaultFbo[2]; // 0:Unprotected, 1:Protected
mutable tsl::robin_map<SamplerParams, GLuint,
SamplerParams::Hasher, SamplerParams::EqualTo> mSamplerMap;
+504 -103
View File
@@ -17,8 +17,8 @@
#include "OpenGLDriver.h"
#include "CommandStreamDispatcher.h"
#include "GLTexture.h"
#include "GLMemoryMappedBuffer.h"
#include "GLTexture.h"
#include "GLUtils.h"
#include "OpenGLContext.h"
#include "OpenGLDriverFactory.h"
@@ -126,6 +126,7 @@
#if DEBUG_MARKER_LEVEL == DEBUG_MARKER_PROFILE
# define DEBUG_MARKER()
# define DEBUG_MARKER_NAME(name)
# define PROFILE_MARKER(marker) PROFILE_SCOPE(marker);
# if DEBUG_GROUP_MARKER_LEVEL != DEBUG_GROUP_MARKER_NONE
# error PROFILING is exclusive; group markers must be disabled.
@@ -135,12 +136,14 @@
# endif
#elif DEBUG_MARKER_LEVEL > DEBUG_MARKER_NONE
# define DEBUG_MARKER() DebugMarker _debug_marker(*this, __func__);
# define DEBUG_MARKER_NAME(name) DebugMarker _debug_marker(*this, name);
# define PROFILE_MARKER(marker) DEBUG_MARKER()
# if DEBUG_MARKER_LEVEL & DEBUG_MARKER_PROFILE
# error PROFILING is exclusive; all other debug features must be disabled.
# endif
#else
# define DEBUG_MARKER()
# define DEBUG_MARKER_NAME(name)
# define PROFILE_MARKER(marker)
#endif
@@ -286,14 +289,14 @@ OpenGLDriver::DebugMarker::~DebugMarker() noexcept {
// ------------------------------------------------------------------------------------------------
OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept
: mPlatform(*platform),
: OpenGLDriverBase(driverConfig),
mPlatform(*platform),
mContext(mPlatform, driverConfig),
mShaderCompilerService(*this),
mHandleAllocator("Handles",
driverConfig.handleArenaSize,
driverConfig.disableHandleUseAfterFreeCheck,
driverConfig.disableHeapHandleTags),
mDriverConfig(driverConfig),
mCurrentPushConstants(new(std::nothrow) PushConstantBundle{}) {
// set a reasonable default value for our stream array
mTexturesWithStreamsAttached.reserve(8);
@@ -312,6 +315,26 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi
#endif
mShaderCompilerService.init();
if (driverConfig.asynchronousMode != AsynchronousMode::NONE) {
mJobQueue = JobQueue::create();
bool const useThreadWorker =
(driverConfig.asynchronousMode == AsynchronousMode::THREAD_PREFERRED) &&
UTILS_HAS_THREADING;
if (useThreadWorker) {
ThreadWorker::Config threadWorkerConfig{
"JobQueueThreadWorker",
JobSystem::Priority::NORMAL,
[this]() { mPlatform.createContext(true); },
[this]() { mPlatform.releaseContext(); },
};
mJobWorker = ThreadWorker::create(mJobQueue, std::move(threadWorkerConfig));
} else {
mJobWorker = AmortizationWorker::create(mJobQueue);
}
}
}
OpenGLDriver::~OpenGLDriver() noexcept { // NOLINT(modernize-use-equals-default)
@@ -359,8 +382,19 @@ void OpenGLDriver::terminate() {
delete mCurrentPushConstants;
mCurrentPushConstants = nullptr;
mContext.terminate();
// Flush all pending asynchronous tasks. Some tasks may end up posting follow-up operations to
// the `ServiceThread` (e.g., via CountdownCallbackHandler or any user-provided handlers). So we
// early stop the ServiceThread to ensure these are processed as well. Tasks posted to the main
// thread (due to no user handler) during this process are handled later by `Driver::purge`
// within `FEngine::shutdown`.
if (getJobWorker()) {
getJobWorker()->terminate();
}
#if UTILS_HAS_THREADING
stopServiceThread();
#endif
mContext.terminate();
mPlatform.terminate();
}
@@ -412,7 +446,8 @@ void OpenGLDriver::setPushConstant(ShaderStage const stage, uint8_t const index,
if (std::holds_alternative<bool>(value)) {
assert_invariant(type == ConstantType::BOOL);
bool const bval = std::get<bool>(value);
glUniform1i(location, bval ? 1 : 0);
// This must be the 'ui' version of glUniform1 due to a crash on M-series macbooks.
glUniform1ui(location, bval ? 1 : 0);
} else if (std::holds_alternative<float>(value)) {
assert_invariant(type == ConstantType::FLOAT);
float const fval = std::get<float>(value);
@@ -576,10 +611,18 @@ Handle<HwIndexBuffer> OpenGLDriver::createIndexBufferS() noexcept {
return initHandle<GLIndexBuffer>();
}
Handle<HwIndexBuffer> OpenGLDriver::createIndexBufferAsyncS() noexcept {
return initHandle<GLIndexBuffer>();
}
Handle<HwBufferObject> OpenGLDriver::createBufferObjectS() noexcept {
return initHandle<GLBufferObject>();
}
Handle<HwBufferObject> OpenGLDriver::createBufferObjectAsyncS() noexcept {
return initHandle<GLBufferObject>();
}
Handle<HwRenderPrimitive> OpenGLDriver::createRenderPrimitiveS() noexcept {
return initHandle<GLRenderPrimitive>();
}
@@ -592,6 +635,10 @@ Handle<HwTexture> OpenGLDriver::createTextureS() noexcept {
return initHandle<GLTexture>();
}
Handle<HwTexture> OpenGLDriver::createTextureAsyncS() noexcept {
return initHandle<GLTexture>();
}
Handle<HwTexture> OpenGLDriver::createTextureViewS() noexcept {
return initHandle<GLTexture>();
}
@@ -600,6 +647,10 @@ Handle<HwTexture> OpenGLDriver::createTextureViewSwizzleS() noexcept {
return initHandle<GLTexture>();
}
Handle<HwTexture> OpenGLDriver::createTextureViewSwizzleAsyncS() noexcept {
return initHandle<GLTexture>();
}
Handle<HwTexture> OpenGLDriver::createTextureExternalImage2S() noexcept {
return initHandle<GLTexture>();
}
@@ -616,6 +667,30 @@ Handle<HwTexture> OpenGLDriver::importTextureS() noexcept {
return initHandle<GLTexture>();
}
Handle<HwTexture> OpenGLDriver::importTextureAsyncS() noexcept {
return initHandle<GLTexture>();
}
AsyncCallId OpenGLDriver::update3DImageAsyncS() noexcept {
assert_invariant(getJobQueue());
return getJobQueue()->issueJobId();
}
AsyncCallId OpenGLDriver::setVertexBufferObjectAsyncS() noexcept {
assert_invariant(getJobQueue());
return getJobQueue()->issueJobId();
}
AsyncCallId OpenGLDriver::updateBufferObjectAsyncS() noexcept {
assert_invariant(getJobQueue());
return getJobQueue()->issueJobId();
}
AsyncCallId OpenGLDriver::updateIndexBufferAsyncS() noexcept {
assert_invariant(getJobQueue());
return getJobQueue()->issueJobId();
}
Handle<HwRenderTarget> OpenGLDriver::createDefaultRenderTargetS() noexcept {
return initHandle<GLRenderTarget>();
}
@@ -656,6 +731,11 @@ MemoryMappedBufferHandle OpenGLDriver::mapBufferS() noexcept {
return initHandle<GLMemoryMappedBuffer>();
}
AsyncCallId OpenGLDriver::queueCommandAsyncS() noexcept {
assert_invariant(getJobQueue());
return getJobQueue()->issueJobId();
}
void OpenGLDriver::createVertexBufferInfoR(
Handle<HwVertexBufferInfo> vbih,
uint8_t bufferCount,
@@ -677,17 +757,11 @@ void OpenGLDriver::createVertexBufferR(
mHandleAllocator.associateTagToHandle(vbh.getId(), std::move(tag));
}
void OpenGLDriver::createIndexBufferR(
Handle<HwIndexBuffer> ibh,
ElementType const elementType,
uint32_t indexCount,
BufferUsage const usage,
ImmutableCString&& tag) {
DEBUG_MARKER()
void OpenGLDriver::createIndexBufferCommon(Handle<HwIndexBuffer> ibh, ElementType const elementType,
uint32_t indexCount, BufferUsage const usage, utils::ImmutableCString&& tag) {
auto& gl = mContext;
uint8_t const elementSize = static_cast<uint8_t>(getElementTypeSize(elementType));
GLIndexBuffer* ib = construct<GLIndexBuffer>(ibh, elementSize, indexCount);
GLIndexBuffer* ib = handle_cast<GLIndexBuffer*>(ibh);
glGenBuffers(1, &ib->gl.buffer);
GLsizeiptr const size = elementSize * GLsizeiptr(indexCount);
gl.bindVertexArray(nullptr);
@@ -697,9 +771,52 @@ void OpenGLDriver::createIndexBufferR(
mHandleAllocator.associateTagToHandle(ibh.getId(), std::move(tag));
}
void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, ImmutableCString&& tag) {
void OpenGLDriver::createIndexBufferR(
Handle<HwIndexBuffer> ibh,
ElementType const elementType,
uint32_t indexCount,
BufferUsage const usage,
ImmutableCString&& tag) {
DEBUG_MARKER()
uint8_t const elementSize = static_cast<uint8_t>(getElementTypeSize(elementType));
// For object creation, the object should be constructed first to determine the initial settings
// early. For example, the `asynchronous` field needs to be decided at this stage so that
// subsequent backend APIs can handle operations based on this setting.
construct<GLIndexBuffer>(ibh, elementSize, indexCount, false);
createIndexBufferCommon(ibh, elementType, indexCount, usage, std::move(tag));
}
void OpenGLDriver::createIndexBufferAsyncR(
Handle<HwIndexBuffer> ibh,
ElementType const elementType,
uint32_t indexCount,
BufferUsage const usage,
CallbackHandler* handler, CallbackHandler::Callback const callback, void* user,
ImmutableCString&& tag) {
uint8_t const elementSize = static_cast<uint8_t>(getElementTypeSize(elementType));
// For object creation, the object should be constructed first to determine the initial settings
// early. For example, the `asynchronous` field needs to be decided at this stage so that
// subsequent backend APIs can handle operations based on this setting.
construct<GLIndexBuffer>(ibh, elementSize, indexCount, true);
assert_invariant(getJobQueue());
getJobQueue()->push([this, ibh, elementType, indexCount, usage, handler, callback, user,
tag=std::move(tag)]() mutable {
DEBUG_MARKER_NAME("createIndexBufferAsyncR")
createIndexBufferCommon(ibh, elementType, indexCount, usage, std::move(tag));
// glFlush() should be called when using a shared context for this operation. Without it,
// the driver may delay submitting commands to the GPU, preventing other contexts from
// seeing the changes immediately. This ensures submitting the current commands right away.
glFlush();
scheduleCallback(handler, user, callback);
});
}
void OpenGLDriver::createBufferObjectCommon(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, utils::ImmutableCString&& tag) {
assert_invariant(byteCount > 0);
auto& gl = mContext;
@@ -707,7 +824,7 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
gl.bindVertexArray(nullptr);
}
GLBufferObject* bo = construct<GLBufferObject>(boh, byteCount, bindingType, usage);
GLBufferObject* bo = handle_cast<GLBufferObject*>(boh);
if (UTILS_UNLIKELY(bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
bo->gl.id = ++mLastAssignedEmulatedUboId;
bo->gl.buffer = malloc(byteCount);
@@ -723,6 +840,40 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
mHandleAllocator.associateTagToHandle(boh.getId(), std::move(tag));
}
void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, ImmutableCString&& tag) {
DEBUG_MARKER()
// For object creation, the object should be constructed first to determine the initial settings
// early. For example, the `asynchronous` field needs to be decided at this stage so that
// subsequent backend APIs can handle operations based on this setting.
construct<GLBufferObject>(boh, byteCount, bindingType, usage, false);
createBufferObjectCommon(boh, byteCount, bindingType, usage, std::move(tag));
}
void OpenGLDriver::createBufferObjectAsyncR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user, ImmutableCString&& tag) {
// For object creation, the object should be constructed first to determine the initial settings
// early. For example, the `asynchronous` field needs to be decided at this stage so that
// subsequent backend APIs can handle operations based on this setting.
construct<GLBufferObject>(boh, byteCount, bindingType, usage, true);
assert_invariant(getJobQueue());
getJobQueue()->push([this, boh, byteCount, bindingType, usage, handler, callback, user,
tag=std::move(tag)]() mutable {
DEBUG_MARKER_NAME("createBufferObjectAsyncR")
createBufferObjectCommon(boh, byteCount, bindingType, usage, std::move(tag));
// glFlush() should be called when using a shared context for this operation. Without it,
// the driver may delay submitting commands to the GPU, preventing other contexts from
// seeing the changes immediately. This ensures submitting the current commands right away.
glFlush();
scheduleCallback(handler, user, callback);
});
}
void OpenGLDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
PrimitiveType const pt, ImmutableCString&& tag) {
@@ -870,11 +1021,9 @@ void OpenGLDriver::textureStorage(GLTexture* t,
t->depth = depth;
}
void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
void OpenGLDriver::createTextureCommon(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
TextureUsage usage, ImmutableCString&& tag) {
DEBUG_MARKER()
GLenum internalFormat = getInternalFormat(format);
assert_invariant(internalFormat);
@@ -895,7 +1044,11 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
auto const& gl = mContext;
samples = std::clamp(samples, uint8_t(1u), uint8_t(gl.gets.max_samples));
GLTexture* t = construct<GLTexture>(th, target, levels, samples, width, height, depth, format, usage);
GLTexture* t = handle_cast<GLTexture*>(th);
// Overwrite the updated `usage`.
t->usage = usage;
if (UTILS_LIKELY(usage & TextureUsage::SAMPLEABLE)) {
if (UTILS_UNLIKELY(gl.isES2())) {
@@ -964,6 +1117,44 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
TextureUsage usage, ImmutableCString&& tag) {
DEBUG_MARKER()
// For object creation, the object should be constructed first to determine the initial settings
// early. For example, the `asynchronous` field needs to be decided at this stage so that
// subsequent backend APIs can handle operations based on this setting.
construct<GLTexture>(th, target, levels, samples, width, height, depth, format, usage, false);
createTextureCommon(th, target, levels, format, samples, width, height, depth, usage,
std::move(tag));
}
void OpenGLDriver::createTextureAsyncR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
TextureUsage usage, CallbackHandler* handler, CallbackHandler::Callback const callback,
void* user, ImmutableCString&& tag) {
// For object creation, the object should be constructed first to determine the initial settings
// early. For example, the `asynchronous` field needs to be decided at this stage so that
// subsequent backend APIs can handle operations based on this setting.
construct<GLTexture>(th, target, levels, samples, width, height, depth, format, usage, true);
assert_invariant(getJobQueue());
getJobQueue()->push([this, th, target, levels, format, samples, width, height, depth, usage,
handler, callback, user, tag=std::move(tag)]() mutable {
DEBUG_MARKER_NAME("createTextureAsyncR")
createTextureCommon(th, target, levels, format, samples, width, height, depth, usage,
std::move(tag));
// glFlush() should be called when using a shared context for this operation. Without it,
// the driver may delay submitting commands to the GPU, preventing other contexts from
// seeing the changes immediately. This ensures submitting the current commands right away.
glFlush();
scheduleCallback(handler, user, callback);
});
}
void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
Handle<HwTexture> srch, uint8_t const baseLevel, uint8_t const levelCount, ImmutableCString&& tag) {
DEBUG_MARKER()
@@ -986,7 +1177,8 @@ void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
src->samples,
src->width, src->height, src->depth,
src->format,
src->usage);
src->usage,
src->asynchronous);
t->gl = src->gl;
t->gl.sidecarRenderBufferMS = 0;
@@ -1011,11 +1203,9 @@ void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
TextureSwizzle const r, TextureSwizzle const g, TextureSwizzle const b, TextureSwizzle const a,
ImmutableCString&& tag) {
DEBUG_MARKER()
void OpenGLDriver::createTextureViewSwizzleCommon(Handle<HwTexture> th, Handle<HwTexture> srch,
TextureSwizzle const r, TextureSwizzle const g, TextureSwizzle const b,
TextureSwizzle const a, ImmutableCString&& tag) {
GLTexture const* const src = handle_cast<GLTexture const*>(srch);
FILAMENT_CHECK_PRECONDITION(any(src->usage & TextureUsage::SAMPLEABLE))
@@ -1029,14 +1219,7 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
src->ref = initHandle<GLTextureRef>();
}
GLTexture* t = construct<GLTexture>(th,
src->target,
src->levels,
src->samples,
src->width, src->height, src->depth,
src->format,
src->usage);
GLTexture* t = handle_cast<GLTexture*>(th);
t->gl = src->gl;
t->gl.baseLevel = src->gl.baseLevel;
t->gl.maxLevel = src->gl.maxLevel;
@@ -1077,6 +1260,46 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
TextureSwizzle const r, TextureSwizzle const g, TextureSwizzle const b, TextureSwizzle const a,
ImmutableCString&& tag) {
DEBUG_MARKER()
// For object creation, the object should be constructed first to determine the initial settings
// early. For example, the `asynchronous` field needs to be decided at this stage so that
// subsequent backend APIs can handle operations based on this setting.
GLTexture const* const src = handle_cast<GLTexture const*>(srch);
construct<GLTexture>(th, src->target, src->levels, src->samples, src->width, src->height,
src->depth, src->format, src->usage, src->asynchronous);
createTextureViewSwizzleCommon(th, srch, r, g, b, a, std::move(tag));
}
void OpenGLDriver::createTextureViewSwizzleAsyncR(Handle<HwTexture> th, Handle<HwTexture> srch,
TextureSwizzle const r, TextureSwizzle const g, TextureSwizzle const b, TextureSwizzle const a,
CallbackHandler* handler, CallbackHandler::Callback const callback, void* user,
ImmutableCString&& tag) {
// For object creation, the object should be constructed first to determine the initial settings
// early. For example, the `asynchronous` field needs to be decided at this stage so that
// subsequent backend APIs can handle operations based on this setting.
GLTexture const* const src = handle_cast<GLTexture const*>(srch);
construct<GLTexture>(th, src->target, src->levels, src->samples, src->width, src->height,
src->depth, src->format, src->usage, src->asynchronous);
assert_invariant(getJobQueue());
getJobQueue()->push([this, th, srch, r, g, b, a, handler, callback, user,
tag=std::move(tag)]() mutable {
DEBUG_MARKER_NAME("createTextureViewSwizzleAsyncR")
createTextureViewSwizzleCommon(th, srch, r, g, b, a, std::move(tag));
// glFlush() should be called when using a shared context for this operation. Without it,
// the driver may delay submitting commands to the GPU, preventing other contexts from
// seeing the changes immediately. This ensures submitting the current commands right away.
glFlush();
scheduleCallback(handler, user, callback);
});
}
void OpenGLDriver::createTextureExternalImage2R(Handle<HwTexture> th, SamplerType target,
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage,
Platform::ExternalImageHandleRef image, ImmutableCString&& tag) {
@@ -1094,7 +1317,7 @@ void OpenGLDriver::createTextureExternalImage2R(Handle<HwTexture> th, SamplerTyp
}
assert_invariant(internalFormat);
GLTexture* const t = construct<GLTexture>(th, target, 1, 1, width, height, 1, format, usage);
GLTexture* const t = construct<GLTexture>(th, target, 1, 1, width, height, 1, format, usage, false);
assert_invariant(t);
t->externalTexture = mPlatform.createExternalImageTexture();
@@ -1146,7 +1369,7 @@ void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, SamplerType
}
assert_invariant(internalFormat);
GLTexture* const t = construct<GLTexture>(th, target, 1, 1, width, height, 1, format, usage);
GLTexture* const t = construct<GLTexture>(th, target, 1, 1, width, height, 1, format, usage, false);
assert_invariant(t);
t->externalTexture = mPlatform.createExternalImageTexture();
@@ -1186,14 +1409,12 @@ void OpenGLDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
// not relevant for the OpenGL backend
}
void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t const id,
void OpenGLDriver::importTextureCommon(Handle<HwTexture> th, intptr_t const id,
SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage, ImmutableCString&& tag) {
DEBUG_MARKER()
auto const& gl = mContext;
samples = std::clamp(samples, uint8_t(1u), uint8_t(gl.gets.max_samples));
GLTexture* t = construct<GLTexture>(th, target, levels, samples, width, height, depth, format, usage);
GLTexture* t = handle_cast<GLTexture*>(th);
t->gl.id = GLuint(id);
t->gl.imported = true;
@@ -1244,6 +1465,46 @@ void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t const id,
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t const id,
SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage, ImmutableCString&& tag) {
DEBUG_MARKER()
// For object creation, the object should be constructed first to determine the initial settings
// early. For example, the `asynchronous` field needs to be decided at this stage so that
// subsequent backend APIs can handle operations based on this setting.
construct<GLTexture>(th, target, levels, samples, width, height, depth, format, usage, false);
importTextureCommon(th, id, target, levels, format, samples, width, height, depth, usage,
std::move(tag));
}
void OpenGLDriver::importTextureAsyncR(Handle<HwTexture> th, intptr_t const id,
SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
CallbackHandler* handler, CallbackHandler::Callback const callback, void* user,
ImmutableCString&& tag) {
// For object creation, the object should be constructed first to determine the initial settings
// early. For example, the `asynchronous` field needs to be decided at this stage so that
// subsequent backend APIs can handle operations based on this setting.
construct<GLTexture>(th, target, levels, samples, width, height, depth, format, usage, true);
assert_invariant(getJobQueue());
getJobQueue()->push([this, th, id, target, levels, format, samples, width, height, depth, usage,
handler, callback, user, tag=std::move(tag)]() mutable {
DEBUG_MARKER_NAME("importTextureAsyncR")
importTextureCommon(th, id, target, levels, format, samples, width, height, depth, usage,
std::move(tag));
// glFlush() should be called when using a shared context for this operation. Without it,
// the driver may delay submitting commands to the GPU, preventing other contexts from
// seeing the changes immediately. This ensures submitting the current commands right away.
glFlush();
scheduleCallback(handler, user, callback);
});
}
void OpenGLDriver::updateVertexArrayObject(GLRenderPrimitive* rp, GLVertexBuffer const* vb) {
// NOTE: this is called often and must be as efficient as possible.
@@ -1931,30 +2192,53 @@ void OpenGLDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
}
}
void OpenGLDriver::destroyIndexBufferCommon(Handle<HwIndexBuffer> ibh) {
GLIndexBuffer const* ib = handle_cast<const GLIndexBuffer*>(ibh);
auto& gl = mContext;
gl.deleteBuffer(ib->gl.buffer, GL_ELEMENT_ARRAY_BUFFER);
destruct(ibh, ib);
}
void OpenGLDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
DEBUG_MARKER()
if (ibh) {
auto& gl = mContext;
GLIndexBuffer const* ib = handle_cast<const GLIndexBuffer*>(ibh);
gl.deleteBuffer(ib->gl.buffer, GL_ELEMENT_ARRAY_BUFFER);
destruct(ibh, ib);
if (ib->asynchronous) {
getJobQueue()->push([this, ibh]() {
destroyIndexBufferCommon(ibh);
});
} else {
destroyIndexBufferCommon(ibh);
}
}
}
void OpenGLDriver::destroyBufferObjectCommon(Handle<HwBufferObject> boh) {
GLBufferObject const* bo = handle_cast<const GLBufferObject*>(boh);
auto& gl = mContext;
// check we're not destroying a buffer that has active mappings
assert_invariant(bo->mappingCount == 0);
if (UTILS_UNLIKELY(bo->bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
free(bo->gl.buffer);
} else {
gl.deleteBuffer(bo->gl.id, bo->gl.binding);
}
destruct(boh, bo);
}
void OpenGLDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
DEBUG_MARKER()
if (boh) {
auto& gl = mContext;
GLBufferObject const* bo = handle_cast<const GLBufferObject*>(boh);
// check we're not destroying a buffer that has active mappings
assert_invariant(bo->mappingCount == 0);
if (UTILS_UNLIKELY(bo->bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
free(bo->gl.buffer);
if (bo->asynchronous) {
getJobQueue()->push([this, boh]() {
destroyBufferObjectCommon(boh);
});
} else {
gl.deleteBuffer(bo->gl.id, bo->gl.binding);
destroyBufferObjectCommon(boh);
}
destruct(boh, bo);
}
}
@@ -1990,53 +2274,63 @@ void OpenGLDriver::destroyProgram(Handle<HwProgram> ph) {
}
}
void OpenGLDriver::destroyTextureCommon(Handle<HwTexture> th) {
GLTexture* t = handle_cast<GLTexture*>(th);
auto& gl = mContext;
if (UTILS_LIKELY(!t->gl.imported)) {
if (UTILS_LIKELY(t->usage & TextureUsage::SAMPLEABLE)) {
// drop a reference
uint16_t count = 0;
if (UTILS_UNLIKELY(t->ref)) {
// the common case is that we don't have a ref handle
GLTextureRef* const ref = handle_cast<GLTextureRef*>(t->ref);
count = --(ref->count);
if (count == 0) {
destruct(t->ref, ref);
}
}
if (count == 0) {
// if this was the last reference, we destroy the refcount as well as
// the GL texture name itself.
gl.unbindTexture(t->gl.target, t->gl.id);
if (UTILS_UNLIKELY(t->hwStream)) {
detachStream(t);
}
if (UTILS_UNLIKELY(t->externalTexture)) {
mPlatform.destroyExternalImageTexture(t->externalTexture);
} else {
glDeleteTextures(1, &t->gl.id);
}
} else {
// The Handle<HwTexture> is always destroyed. For extra precaution we also
// check that the GLTexture has a trivial destructor.
static_assert(std::is_trivially_destructible_v<GLTexture>);
}
} else {
assert_invariant(t->gl.target == GL_RENDERBUFFER);
glDeleteRenderbuffers(1, &t->gl.id);
}
if (t->gl.sidecarRenderBufferMS) {
glDeleteRenderbuffers(1, &t->gl.sidecarRenderBufferMS);
}
} else {
gl.unbindTexture(t->gl.target, t->gl.id);
}
destruct(th, t);
}
void OpenGLDriver::destroyTexture(Handle<HwTexture> th) {
DEBUG_MARKER()
if (th) {
auto& gl = mContext;
GLTexture* t = handle_cast<GLTexture*>(th);
if (UTILS_LIKELY(!t->gl.imported)) {
if (UTILS_LIKELY(t->usage & TextureUsage::SAMPLEABLE)) {
// drop a reference
uint16_t count = 0;
if (UTILS_UNLIKELY(t->ref)) {
// the common case is that we don't have a ref handle
GLTextureRef* const ref = handle_cast<GLTextureRef*>(t->ref);
count = --(ref->count);
if (count == 0) {
destruct(t->ref, ref);
}
}
if (count == 0) {
// if this was the last reference, we destroy the refcount as well as
// the GL texture name itself.
gl.unbindTexture(t->gl.target, t->gl.id);
if (UTILS_UNLIKELY(t->hwStream)) {
detachStream(t);
}
if (UTILS_UNLIKELY(t->externalTexture)) {
mPlatform.destroyExternalImageTexture(t->externalTexture);
} else {
glDeleteTextures(1, &t->gl.id);
}
} else {
// The Handle<HwTexture> is always destroyed. For extra precaution we also
// check that the GLTexture has a trivial destructor.
static_assert(std::is_trivially_destructible_v<GLTexture>);
}
} else {
assert_invariant(t->gl.target == GL_RENDERBUFFER);
glDeleteRenderbuffers(1, &t->gl.id);
}
if (t->gl.sidecarRenderBufferMS) {
glDeleteRenderbuffers(1, &t->gl.sidecarRenderBufferMS);
}
if (t->asynchronous) {
getJobQueue()->push([this, th]() {
destroyTextureCommon(th);
});
} else {
gl.unbindTexture(t->gl.target, t->gl.id);
destroyTextureCommon(th);
}
destruct(th, t);
}
}
@@ -2577,7 +2871,7 @@ bool OpenGLDriver::isStereoSupported() {
if (UTILS_UNLIKELY(mContext.isES2())) {
return false;
}
switch (mDriverConfig.stereoscopicType) {
switch (getDriverConfig().stereoscopicType) {
case StereoscopicType::INSTANCED:
return mContext.ext.EXT_clip_cull_distance;
case StereoscopicType::MULTIVIEW:
@@ -2596,7 +2890,7 @@ bool OpenGLDriver::isParallelShaderCompileSupported() {
// GL-specific. It would also be nice to inform the engine that they're working with this fake
// amortized system, but this fact will become implicit when we generalize this feature for all
// backends.
if (mDriverConfig.disableAmortizedShaderCompile) {
if (getDriverConfig().disableAmortizedShaderCompile) {
return mShaderCompilerService.isParallelShaderCompileSupported();
}
return true;
@@ -2618,6 +2912,10 @@ bool OpenGLDriver::isDepthClampSupported() {
return getContext().ext.EXT_depth_clamp;
}
bool OpenGLDriver::isAsynchronousModeEnabled() {
return getJobQueue() != nullptr;
}
bool OpenGLDriver::isWorkaroundNeeded(Workaround const workaround) {
switch (workaround) {
case Workaround::SPLIT_EASU:
@@ -2799,10 +3097,8 @@ void OpenGLDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain>
// Updating driver objects
// ------------------------------------------------------------------------------------------------
void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
void OpenGLDriver::setVertexBufferObjectCommon(Handle<HwVertexBuffer> vbh,
uint32_t const index, Handle<HwBufferObject> boh) {
DEBUG_MARKER()
GLVertexBuffer* vb = handle_cast<GLVertexBuffer *>(vbh);
GLBufferObject const* bo = handle_cast<GLBufferObject *>(boh);
@@ -2822,10 +3118,28 @@ void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
CHECK_GL_ERROR()
}
void OpenGLDriver::updateIndexBuffer(
Handle<HwIndexBuffer> ibh, BufferDescriptor&& p, uint32_t const byteOffset) {
void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
uint32_t const index, Handle<HwBufferObject> boh) {
DEBUG_MARKER()
setVertexBufferObjectCommon(vbh, index, boh);
}
void OpenGLDriver::setVertexBufferObjectAsyncR(AsyncCallId jobId, Handle<HwVertexBuffer> vbh,
uint32_t const index, Handle<HwBufferObject> boh, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
getJobQueue()->push([this, vbh, index, boh, handler, callback, user]() mutable {
DEBUG_MARKER_NAME("setVertexBufferObjectAsyncR")
setVertexBufferObjectCommon(vbh, index, boh);
// glFlush() should be called when using a shared context for this operation. Without it,
// the driver may delay submitting commands to the GPU, preventing other contexts from
// seeing the changes immediately. This ensures submitting the current commands right away.
glFlush();
scheduleCallback(handler, user, callback);
}, jobId);
}
void OpenGLDriver::updateIndexBufferCommon(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
uint32_t const byteOffset) {
auto& gl = mContext;
GLIndexBuffer const* ib = handle_cast<GLIndexBuffer *>(ibh);
assert_invariant(ib->elementSize == 2 || ib->elementSize == 4);
@@ -2839,9 +3153,29 @@ void OpenGLDriver::updateIndexBuffer(
CHECK_GL_ERROR()
}
void OpenGLDriver::updateBufferObject(
Handle<HwBufferObject> boh, BufferDescriptor&& bd, uint32_t const byteOffset) {
void OpenGLDriver::updateIndexBuffer(
Handle<HwIndexBuffer> ibh, BufferDescriptor&& p, uint32_t const byteOffset) {
DEBUG_MARKER()
updateIndexBufferCommon(ibh, std::move(p), byteOffset);
}
void OpenGLDriver::updateIndexBufferAsyncR(AsyncCallId jobId, Handle<HwIndexBuffer> ibh,
BufferDescriptor&& p, uint32_t const byteOffset, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
getJobQueue()->push([this, ibh, p=std::move(p), byteOffset, handler, callback,
user]() mutable {
DEBUG_MARKER_NAME("updateIndexBufferAsyncR")
updateIndexBufferCommon(ibh, std::move(p), byteOffset);
// glFlush() should be called when using a shared context for this operation. Without it,
// the driver may delay submitting commands to the GPU, preventing other contexts from
// seeing the changes immediately. This ensures submitting the current commands right away.
glFlush();
scheduleCallback(handler, user, callback);
}, jobId);
}
void OpenGLDriver::updateBufferObjectCommon(
Handle<HwBufferObject> boh, BufferDescriptor&& bd, uint32_t const byteOffset) {
auto& gl = mContext;
GLBufferObject* bo = handle_cast<GLBufferObject *>(boh);
@@ -2874,6 +3208,27 @@ void OpenGLDriver::updateBufferObject(
CHECK_GL_ERROR()
}
void OpenGLDriver::updateBufferObject(
Handle<HwBufferObject> boh, BufferDescriptor&& bd, uint32_t const byteOffset) {
DEBUG_MARKER()
updateBufferObjectCommon(boh, std::move(bd), byteOffset);
}
void OpenGLDriver::updateBufferObjectAsyncR(AsyncCallId jobId, Handle<HwBufferObject> boh,
BufferDescriptor&& bd, uint32_t const byteOffset, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
getJobQueue()->push([this, boh, bd=std::move(bd), byteOffset, handler, callback,
user]() mutable {
DEBUG_MARKER_NAME("updateBufferObjectAsyncR")
updateBufferObjectCommon(boh, std::move(bd), byteOffset);
// glFlush() should be called when using a shared context for this operation. Without it,
// the driver may delay submitting commands to the GPU, preventing other contexts from
// seeing the changes immediately. This ensures submitting the current commands right away.
glFlush();
scheduleCallback(handler, user, callback);
}, jobId);
}
void OpenGLDriver::updateBufferObjectUnsynchronized(
Handle<HwBufferObject> boh, BufferDescriptor&& bd, uint32_t const byteOffset) {
DEBUG_MARKER()
@@ -2937,12 +3292,10 @@ void OpenGLDriver::resetBufferObject(Handle<HwBufferObject> boh) {
}
}
void OpenGLDriver::update3DImage(Handle<HwTexture> th,
void OpenGLDriver::update3DImageCommon(Handle<HwTexture> th,
uint32_t const level, uint32_t const xoffset, uint32_t const yoffset, uint32_t const zoffset,
uint32_t const width, uint32_t const height, uint32_t const depth,
PixelBufferDescriptor&& data) {
DEBUG_MARKER()
GLTexture const* t = handle_cast<GLTexture *>(th);
if (data.type == PixelDataType::COMPRESSED) {
setCompressedTextureData(t,
@@ -2953,6 +3306,33 @@ void OpenGLDriver::update3DImage(Handle<HwTexture> th,
}
}
void OpenGLDriver::update3DImage(Handle<HwTexture> th,
uint32_t const level, uint32_t const xoffset, uint32_t const yoffset, uint32_t const zoffset,
uint32_t const width, uint32_t const height, uint32_t const depth,
PixelBufferDescriptor&& data) {
DEBUG_MARKER()
update3DImageCommon(th, level, xoffset, yoffset, zoffset, width, height, depth,
std::move(data));
}
void OpenGLDriver::update3DImageAsyncR(AsyncCallId jobId, Handle<HwTexture> th,
uint32_t const level, uint32_t const xoffset, uint32_t const yoffset, uint32_t const zoffset,
uint32_t const width, uint32_t const height, uint32_t const depth,
PixelBufferDescriptor&& data, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
getJobQueue()->push([this, th, level, xoffset, yoffset, zoffset, width, height, depth,
data=std::move(data), handler, callback, user]() mutable {
DEBUG_MARKER_NAME("update3DImageAsync")
update3DImageCommon(th, level, xoffset, yoffset, zoffset, width, height, depth,
std::move(data));
// glFlush() should be called when using a shared context for this operation. Without it,
// the driver may delay submitting commands to the GPU, preventing other contexts from
// seeing the changes immediately. This ensures submitting the current commands right away.
glFlush();
scheduleCallback(handler, user, callback);
}, jobId);
}
void OpenGLDriver::generateMipmaps(Handle<HwTexture> th) {
DEBUG_MARKER()
@@ -3852,6 +4232,10 @@ void OpenGLDriver::tick(int) {
#endif
executeEveryNowAndThenOps();
getShaderCompilerService().tick();
if (getJobWorker()) {
// This number is randomly/heuristically chosen. Consider making the number optional.
getJobWorker()->process(5);
}
}
void OpenGLDriver::beginFrame(
@@ -4472,6 +4856,23 @@ void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, uint3 const workGr
#endif
}
void OpenGLDriver::queueCommandAsyncR(AsyncCallId jobId, Invocable<void()>&& command, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
assert_invariant(getJobQueue());
getJobQueue()->push([this, command=std::move(command), handler, callback, user]() {
DEBUG_MARKER_NAME("queueCommandAsync")
if (command) {
command();
}
scheduleCallback(handler, user, callback);
}, jobId);
}
bool OpenGLDriver::cancelAsyncJob(AsyncCallId jobId) {
assert_invariant(getJobQueue());
return getJobQueue()->cancel(jobId);
}
// explicit instantiation of the Dispatcher
template class ConcreteDispatcher<OpenGLDriver>;
+35 -3
View File
@@ -26,6 +26,7 @@
#include "GLDescriptorSetLayout.h"
#include "GLMemoryMappedBuffer.h"
#include "GLTexture.h"
#include "JobQueue.h"
#include "ShaderCompilerService.h"
#include <backend/AcquiredImage.h>
@@ -248,6 +249,9 @@ private:
return utils::CString{ mContext.state.renderer };
}
JobQueue* getJobQueue() const noexcept { return mJobQueue.get(); }
JobWorker* getJobWorker() const noexcept { return mJobWorker.get(); }
template<typename T>
friend class ConcreteDispatcher;
@@ -358,6 +362,34 @@ private:
static GLsizei getAttachments(AttachmentArray& attachments, TargetBufferFlags buffers,
bool isDefaultFramebuffer) noexcept;
// Common methods
void createTextureCommon(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
TextureUsage usage, utils::ImmutableCString&& tag);
void update3DImageCommon(Handle<HwTexture> th,
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
PixelBufferDescriptor&& data);
void createTextureViewSwizzleCommon(Handle<HwTexture> th, Handle<HwTexture> srch,
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b,
TextureSwizzle a, utils::ImmutableCString&& tag);
void importTextureCommon(Handle<HwTexture> th, intptr_t id, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
TextureUsage usage, utils::ImmutableCString&& tag);
void createBufferObjectCommon(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, utils::ImmutableCString&& tag);
void setVertexBufferObjectCommon(Handle<HwVertexBuffer> vbh, uint32_t index,
Handle<HwBufferObject> boh);
void updateBufferObjectCommon(Handle<HwBufferObject> boh, BufferDescriptor&& bd,
uint32_t byteOffset);
void createIndexBufferCommon(Handle<HwIndexBuffer> ibh, ElementType const elementType,
uint32_t indexCount, BufferUsage const usage, utils::ImmutableCString&& tag);
void updateIndexBufferCommon(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
uint32_t const byteOffset);
void destroyTextureCommon(Handle<HwTexture> th);
void destroyBufferObjectCommon(Handle<HwBufferObject> boh);
void destroyIndexBufferCommon(Handle<HwIndexBuffer> ibh);
// state required to represent the current render pass
Handle<HwRenderTarget> mRenderPassTarget;
RenderPassParams mRenderPassParams;
@@ -413,15 +445,15 @@ private:
void executeEveryNowAndThenOps() noexcept;
std::vector<std::function<bool()>> mEveryNowAndThenOps;
const Platform::DriverConfig mDriverConfig;
Platform::DriverConfig const& getDriverConfig() const noexcept { return mDriverConfig; }
// for ES2 sRGB support
GLSwapChain* mCurrentDrawSwapChain = nullptr;
bool mRec709OutputColorspace = false;
PushConstantBundle* mCurrentPushConstants = nullptr;
PipelineLayout::SetLayout mCurrentSetLayout;
JobQueue::Ptr mJobQueue;
JobWorker::Ptr mJobWorker;
};
// ------------------------------------------------------------------------------------------------
@@ -19,12 +19,16 @@
#include "DriverBase.h"
#include <backend/Platform.h>
#include <utils/CString.h>
namespace filament::backend {
class OpenGLDriverBase : public DriverBase {
protected:
explicit OpenGLDriverBase(const Platform::DriverConfig& driverConfig)
: DriverBase(driverConfig) {}
~OpenGLDriverBase() override;
public:
@@ -254,8 +254,14 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
mPushConstants.reserve(totalConstantCount);
mPushConstantFragmentStageOffset = vertexConstants.size();
auto const transformAndAdd = [&](Program::PushConstant const& constant) {
GLint const loc = glGetUniformLocation(program, constant.name.c_str());
mPushConstants.push_back({loc, constant.type});
if (!constant.name.empty()) {
GLint const loc = glGetUniformLocation(program, constant.name.c_str());
mPushConstants.push_back({loc, constant.type});
} else {
// If the constant is not named, then we assume it will not be referenced in this
// program.
mPushConstants.push_back({ -1, constant.type });
}
};
std::for_each(vertexConstants.cbegin(), vertexConstants.cend(), transformAndAdd);
std::for_each(fragmentConstants.cbegin(), fragmentConstants.cend(), transformAndAdd);
@@ -79,6 +79,7 @@ static void process_GOOGLE_cpp_style_line_directive(OpenGLContext const& context
static void process_OVR_multiview2(OpenGLContext const& context, int32_t eyeCount, char* source,
size_t len) noexcept;
static std::string_view process_ARB_shading_language_packing(OpenGLContext& context) noexcept;
static std::string_view process_countBits(OpenGLContext& context) noexcept;
static std::array<std::string_view, 3> splitShaderSource(std::string_view source);
// ------------------------------------------------------------------------------------------------
@@ -779,6 +780,7 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
// add support for ARB_shading_language_packing if needed
auto const packingFunctions = process_ARB_shading_language_packing(context);
auto const countBitsFunctions = process_countBits(context);
// split shader source, so we can insert the specialization constants and the packing
// functions
@@ -789,10 +791,10 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
version = "#version 310 es\n";
}
std::array<std::string_view, 5> sources = {
std::array<std::string_view, 6> sources = {
version, prolog,
{ specializationConstantString.data(), specializationConstantString.size() },
packingFunctions,
packingFunctions, countBitsFunctions,
{ body.data(), body.size() - 1 } // null-terminated
};
@@ -803,8 +805,8 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
[](std::string_view s) { return !s.empty(); });
size_t const count = std::distance(sources.begin(), partitionPoint);
std::array<const char*, 5> shaderStrings;
std::array<GLint, 5> lengths;
std::array<const char*, 6> shaderStrings;
std::array<GLint, 6> lengths;
for (size_t j = 0; j < count; j++) {
shaderStrings[j] = sources[j].data();
lengths[j] = GLint(sources[j].size());
@@ -1085,6 +1087,22 @@ UTILS_NOINLINE
}
}
/* static */ std::string_view process_countBits(OpenGLContext& context) noexcept {
using namespace std::literals;
if (context.isAtLeastGL<4, 0>() || context.isAtLeastGLES<3, 1>()) {
return ""sv;
}
return R"(
// https://graphics.stanford.edu/%7Eseander/bithacks.html
int bitCount(highp uint value) {
value = value - ((value >> 1u) & 0x55555555u);
value = (value & 0x33333333u) + ((value >> 2u) & 0x33333333u);
return int(((value + (value >> 4u) & 0xF0F0F0Fu) * 0x1010101u) >> 24u);
}
)"sv;
}
// Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 (appeared in 4.2) and
// macOS doesn't support GL_ARB_shading_language_packing
// Also GLES3.0 didn't have the full set of packing/unpacking functions
@@ -267,8 +267,6 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext,
eglDupNativeFenceFDANDROID =
PFNEGLDUPNATIVEFENCEFDANDROIDPROC(eglGetProcAddress(
"eglDupNativeFenceFDANDROID"));
} else {
LOG(ERROR) << "EGL_ANDROID_native_fence_sync not supported!";
}
mAssertNativeWindowIsValid = driverConfig.assertNativeWindowIsValid;
@@ -298,9 +296,18 @@ bool PlatformEGLAndroid::queryCompositorTiming(SwapChain const* swapchain,
AndroidFrameCallback::Timeline const preferredTimeline{
mAndroidDetails.androidFrameCallback.getPreferredTimeline() };
outCompositorTiming->frameTime = preferredTimeline.frameTime;
outCompositorTiming->expectedPresentTime = preferredTimeline.expectedPresentTime;
outCompositorTiming->frameTimelineDeadline = preferredTimeline.frameTimelineDeadline;
// FIXME: expectedPresentLatency might reflect the previous frame's value because
// the choreographer's callback can happen before (good) or after (bad) us.
// This problem is mitigated by storing the latency instead of the deadline,
// because it generally is constant frame to frame.
if (UTILS_LIKELY(preferredTimeline.expectedPresentTime > preferredTimeline.frameTime)) {
// latency can never be negative, let's be safe
outCompositorTiming->expectedPresentLatency =
preferredTimeline.expectedPresentTime - preferredTimeline.frameTime;
} else {
// fake a reasonable value (33ms)
outCompositorTiming->expectedPresentLatency = 33'000'000;
}
outCompositorTiming->compositeDeadline = CompositorTiming::INVALID;
outCompositorTiming->compositeInterval = CompositorTiming::INVALID;
outCompositorTiming->compositeToPresentLatency = CompositorTiming::INVALID;
@@ -54,17 +54,12 @@ void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* c
// Check if we can just memcpy directly to the GPU memory.
bool const isMemcopyable = mBuffer->getGpuBuffer()->allocationInfo.pMappedData != nullptr;
// In the case of UNIFORMS, check that is available to see to know if a memcpy is possible.
// This works regardless if it's a full or partial update of the buffer.
bool const isUniformAndAvailable = getBinding() == VulkanBufferBinding::UNIFORM && isAvailable;
// In the case the content is marked as memory mapped or static, is guaranteed to be safe to do
// a memcpy if its available.
bool const isStaticOrShared =
any(mUsage & (BufferUsage::STATIC | BufferUsage::SHARED_WRITE_BIT));
bool const useMemcpy =
((isUniformAndAvailable && mStagingBufferBypassEnabled) || isStaticOrShared) &&
isMemcopyable;
((isAvailable && mStagingBufferBypassEnabled) || isStaticOrShared) && isMemcopyable;
if (useMemcpy) {
char* dest = static_cast<char*>(mBuffer->getGpuBuffer()->allocationInfo.pMappedData) +
byteOffset;
@@ -76,5 +76,4 @@ VkImageSubresourceRange VulkanAttachment::getSubresourceRange() const {
};
}
} // namespace filament::backend
+67 -6
View File
@@ -22,8 +22,9 @@
#include "vulkan/memory/ResourcePointer.h"
#include <vector>
#include <utils/bitset.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Mutex.h>
#include <utils/Slice.h>
@@ -90,6 +91,19 @@ public:
return selectMemoryType(mMemoryProperties, types, reqs);
}
/**
* For pipeline cache prewarming, if external samplers are present, we need to build
* the fake pipeline using the proper formats specified. Since there's no way to
* get these at material build time, we allow the app to register them before
* creating materials.
*
* @param format The format, containing the external format value which should be
* extracted from an AHardwareBuffer.
*/
inline void addPipelineCachePrewarmExternalFormat(const VulkanPlatform::ExternalYcbcrFormat& format) {
mPipelineCachePrewarmExternalFormats.push_back(format);
}
inline fvkutils::VkFormatList const& getAttachmentDepthStencilFormats() const {
return mDepthStencilFormats;
}
@@ -106,6 +120,18 @@ public:
return mPhysicalDeviceProperties.properties.vendorID;
}
/**
* Fetches a list of pre-registered external formats for prewarming the Vulkan
* pipeline cache.
*
* @return A list containing an external format number, YCbCr color model conversion,
* and YCbCr color range.
*/
inline const std::vector<VulkanPlatform::ExternalYcbcrFormat>&
getPipelineCachePrewarmExternalFormats() const noexcept {
return mPipelineCachePrewarmExternalFormats;
}
inline VkExternalFenceHandleTypeFlags getFenceExportFlags() const noexcept {
return mFenceExportFlags;
}
@@ -126,6 +152,10 @@ public:
return mDebugUtilsSupported;
}
inline bool isDynamicRenderingSupported() const noexcept {
return mDynamicRenderingFeatures.dynamicRendering == VK_TRUE;
}
inline bool isMultiviewEnabled() const noexcept {
return mPhysicalDeviceVk11Features.multiview == VK_TRUE;
}
@@ -150,14 +180,33 @@ public:
return mIsUnifiedMemoryArchitecture;
}
inline bool stagingBufferBypassEnabled() const noexcept {
return mStagingBufferBypassEnabled;
inline bool isVertexInputDynamicStateSupported() const noexcept {
return mVertexInputDynamicStateSupported;
}
inline bool pipelineCreationFeedbackSupported() const noexcept {
return mPipelineCreationFeedbackSupported;
}
inline bool asyncPipelineCachePrewarmingEnabled() const noexcept {
return mAsyncPipelineCachePrewarmingEnabled;
}
inline bool parallelShaderCompilationDisabled() const noexcept {
return mParallelShaderCompileDisabled;
}
inline bool stagingBufferBypassEnabled() const noexcept {
return mStagingBufferBypassEnabled;
}
inline bool shouldUsePipelineCachePrewarming() const noexcept {
return asyncPipelineCachePrewarmingEnabled() &&
!parallelShaderCompilationDisabled() &&
isVertexInputDynamicStateSupported() &&
isDynamicRenderingSupported();
}
private:
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
@@ -169,6 +218,9 @@ private:
VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
};
VkPhysicalDeviceDynamicRenderingFeaturesKHR mDynamicRenderingFeatures = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR,
};
VkPhysicalDevicePortabilitySubsetFeaturesKHR mPortabilitySubsetFeatures = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
// By default, on platforms where we don't have portability subset, then this feature must
@@ -179,17 +231,26 @@ private:
VkExternalFenceHandleTypeFlags mFenceExportFlags = {};
// These are options that are either supported or not supported in the current
// device and instance.
bool mDebugMarkersSupported = false;
bool mDebugUtilsSupported = false;
bool mLazilyAllocatedMemorySupported = false;
bool mProtectedMemorySupported = false;
bool mIsUnifiedMemoryArchitecture = false;
bool mStagingBufferBypassEnabled = false;
bool mLazilyAllocatedMemorySupported = false;
bool mPipelineCreationFeedbackSupported = false;
bool mProtectedMemorySupported = false;
bool mVertexInputDynamicStateSupported = false;
// These are options that can be enabled or disabled at an application level.
bool mAsyncPipelineCachePrewarmingEnabled = false;
bool mParallelShaderCompileDisabled = false;
bool mStagingBufferBypassEnabled = false;
fvkutils::VkFormatList mDepthStencilFormats;
fvkutils::VkFormatList mBlittableDepthStencilFormats;
std::vector<VulkanPlatform::ExternalYcbcrFormat> mPipelineCachePrewarmExternalFormats;
// For convenience so that VulkanPlatform can initialize the private fields.
friend class VulkanPlatform;
};
+270 -18
View File
@@ -41,6 +41,7 @@
#include <utils/CString.h>
#include <utils/ImmutableCString.h>
#include <utils/Panic.h>
#include <private/utils/FeatureFlagManager.h>
#ifndef NDEBUG
#include <set> // For VulkanDriver::debugCommandBegin
@@ -151,6 +152,28 @@ static CallbackHandler::Callback syncCallbackWrapper = [](void* userData) {
cbData->cb(cbData->sync, cbData->userData);
};
/**
* Shorthand for converting a description for an external YCbCr format used for
* pipeline cache prewarming to the params for the actual YCbCr conversion.
*/
inline VulkanYcbcrConversionCache::Params getYcbcrConversionParams(const VulkanPlatform::ExternalYcbcrFormat& format) {
return VulkanYcbcrConversionCache::Params {
.conversion = {
.ycbcrModel = fvkutils::getYcbcrModelConversionFilament(format.ycbcrModelConversion),
.r = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_R, 0),
.g = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_G, 1),
.b = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_B, 2),
.a = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_A, 3),
.ycbcrRange = fvkutils::getYcbcrRangeFilament(format.ycbcrRange),
.xChromaOffset = fvkutils::getChromaLocationFilament(VK_CHROMA_LOCATION_MIDPOINT),
.yChromaOffset = fvkutils::getChromaLocationFilament(VK_CHROMA_LOCATION_MIDPOINT),
.chromaFilter = SamplerMagFilter::NEAREST,
},
.format = VK_FORMAT_UNDEFINED,
.externalFormat = format.externalFormat,
};
}
}// anonymous namespace
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
@@ -217,7 +240,8 @@ Dispatcher VulkanDriver::getDispatcher() const noexcept {
VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context,
Platform::DriverConfig const& driverConfig)
: mPlatform(platform),
: DriverBase(driverConfig),
mPlatform(platform),
mResourceManager(driverConfig.handleArenaSize, driverConfig.disableHandleUseAfterFreeCheck,
driverConfig.disableHeapHandleTags),
// Note that we always create the default rendertarget before createDefaultRenderTarget(). We
@@ -233,7 +257,7 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context,
mPlatform->getGraphicsQueueFamilyIndex(), mPlatform->getProtectedGraphicsQueue(),
mPlatform->getProtectedGraphicsQueueFamilyIndex(), mContext, &mSemaphoreManager),
mPipelineLayoutCache(mPlatform->getDevice()),
mPipelineCache(mPlatform->getDevice(), mContext),
mPipelineCache(*this, mPlatform->getDevice(), mContext),
mStagePool(mAllocator, &mResourceManager, &mCommands, &mContext.getPhysicalDeviceLimits()),
mBufferCache(mContext, mResourceManager, mAllocator),
mFramebufferCache(mPlatform->getDevice()),
@@ -249,7 +273,13 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context,
mStreamedImageManager(&mExternalImageManager),
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
mIsMSAASwapChainSupported(false), // TODO: support MSAA swapchain
mStereoscopicType(driverConfig.stereoscopicType) {
mAcquireSwapChainInMakeCurrent(
driverConfig.featureFlagManager ?
driverConfig.featureFlagManager->features.backend.vulkan.enable_acquire_swapchain_in_make_current :
false),
mStereoscopicType(driverConfig.stereoscopicType),
mStereoscopicEyeCount(driverConfig.stereoscopicEyeCount),
mAsynchronousMode(driverConfig.asynchronousMode) {
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
DebugUtils::mSingleton =
@@ -601,6 +631,12 @@ void VulkanDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType ele
mResourceManager.associateHandle(ibh.getId(), std::move(tag));
}
void VulkanDriver::createIndexBufferAsyncR(Handle<HwIndexBuffer> ibh, ElementType elementType,
uint32_t indexCount, BufferUsage usage, CallbackHandler* handler,
CallbackHandler::Callback callback, void* user, utils::ImmutableCString&& tag) {
// TODO: implement this.
}
void VulkanDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
if (!ibh) {
return;
@@ -619,6 +655,12 @@ void VulkanDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
mResourceManager.associateHandle(boh.getId(), std::move(tag));
}
void VulkanDriver::createBufferObjectAsyncR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, CallbackHandler* handler,
CallbackHandler::Callback callback, void* user, utils::ImmutableCString&& tag) {
// TODO: implement this.
}
void VulkanDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
if (!boh) {
return;
@@ -646,6 +688,13 @@ void VulkanDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
mResourceManager.associateHandle(th.getId(), std::move(tag));
}
void VulkanDriver::createTextureAsyncR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage, CallbackHandler* handler, CallbackHandler::Callback callback,
void* user, utils::ImmutableCString&& tag) {
// TODO: implement this.
}
void VulkanDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
uint8_t baseLevel, uint8_t levelCount, utils::ImmutableCString&& tag) {
auto src = resource_ptr<VulkanTexture>::cast(&mResourceManager, srch);
@@ -668,6 +717,13 @@ void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
mResourceManager.associateHandle(th.getId(), std::move(tag));
}
void VulkanDriver::createTextureViewSwizzleAsyncR(Handle<HwTexture> th, Handle<HwTexture> srch,
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
backend::TextureSwizzle a, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user, utils::ImmutableCString&& tag) {
// TODO: implement this.
}
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
Platform::ExternalImageHandleRef externalImage, utils::ImmutableCString&& tag) {
@@ -742,6 +798,16 @@ void VulkanDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
mResourceManager.associateHandle(th.getId(), std::move(tag));
}
void VulkanDriver::importTextureAsyncR(Handle<HwTexture> th, intptr_t id,
SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage, CallbackHandler* handler, CallbackHandler::Callback callback,
void* user, utils::ImmutableCString&& tag) {
// not supported in this backend
assert_invariant(false && "Not supported in Vulkan backend");
mResourceManager.associateHandle(th.getId(), std::move(tag));
}
void VulkanDriver::destroyTexture(Handle<HwTexture> th) {
if (!th) {
return;
@@ -758,6 +824,76 @@ void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils
program);
vprogram.inc();
mResourceManager.associateHandle(ph.getId(), std::move(tag));
if (!mContext.shouldUsePipelineCachePrewarming()) {
return;
}
// If async prewarming is enabled, let's find the proper layout and build the pipeline.
std::array<resource_ptr<VulkanDescriptorSetLayout>, MAX_DESCRIPTOR_SET_COUNT> layouts {};
VulkanDescriptorSetLayout::DescriptorSetLayoutArray vkLayouts {};
bool hasExternalSamplers = false;
for (const auto& layoutBinding : program.getDescriptorSetLayouts()) {
DescriptorSetLayout layoutDescription = layoutBinding.layout;
auto layoutHandle = mResourceManager.allocHandle<VulkanDescriptorSetLayout>();
auto layout = mDescriptorSetLayoutCache.createLayout(layoutHandle, std::move(layoutDescription));
layouts[layoutBinding.set] = layout;
vkLayouts[layoutBinding.set] = layout->getVkLayout();
if (layout->bitmask.externalSampler.count() > 0) {
hasExternalSamplers = true;
}
}
StereoscopicType stereoscopicType = mStereoscopicType;
if (stereoscopicType == StereoscopicType::MULTIVIEW && !program.isMultiview()) {
stereoscopicType = StereoscopicType::NONE;
}
// Base case - build the pipeline without any external samplers.
mPipelineCache.asyncPrewarmCache(
*vprogram.get(),
mPipelineLayoutCache.getLayout(vkLayouts, vprogram),
stereoscopicType,
mStereoscopicEyeCount,
program.getPriorityQueue());
if (!hasExternalSamplers) {
return;
}
// If we have external samplers, let's do this again with the external samplers
// specified.
for (const auto& format : mContext.getPipelineCachePrewarmExternalFormats()) {
// The values that seem to matter in terms of cache hits here are the model conversion,
// and model range. We need some value for externalFormat that is known to support that
// pair of values, but we need not find every possible externalFormat. As we test on
// more devices, this may change.
VkSamplerYcbcrConversion vkConversion = mYcbcrConversionCache.getConversion(
getYcbcrConversionParams(format));
VkSampler externalSampler = mSamplerCache.getSampler({.sampler = {}, .conversion = vkConversion});
// Update all layouts to use the external samplers.
for (size_t i = 0; i < MAX_DESCRIPTOR_SET_COUNT; ++i) {
if (!layouts[i]) {
continue;
}
// For cache prewarming, we don't need every single possible combination of external sampler
// formats. It seems to be enough, in practicce, to simply run through a list of the types of
// samplers that *might* appear. As long as the real pipeline is close enough to something that
// the driver has seen before, we are able to get a cache hit.
utils::FixedCapacityVector<VkSampler> externalSamplers (layouts[i]->bitmask.externalSampler.count(), externalSampler);
vkLayouts[i] = mDescriptorSetLayoutCache.getVkLayout(
layouts[i]->bitmask, layouts[i]->bitmask.externalSampler, externalSamplers);
}
mPipelineCache.asyncPrewarmCache(
*vprogram.get(),
mPipelineLayoutCache.getLayout(vkLayouts, vprogram),
stereoscopicType,
mStereoscopicEyeCount,
program.getPriorityQueue());
}
}
void VulkanDriver::destroyProgram(Handle<HwProgram> ph) {
@@ -772,7 +908,7 @@ void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils:
assert_invariant(mDefaultRenderTarget); // Default render target should already exist.
auto renderTarget = resource_ptr<VulkanRenderTarget>::make(&mResourceManager, rth,
std::move(std::move(*mDefaultRenderTarget.get())));
std::move(*mDefaultRenderTarget.get()));
mDefaultRenderTarget = renderTarget;
mResourceManager.associateHandle(rth.getId(), std::move(tag));
@@ -1000,14 +1136,26 @@ Handle<HwIndexBuffer> VulkanDriver::createIndexBufferS() noexcept {
return mResourceManager.allocHandle<VulkanIndexBuffer>();
}
Handle<HwIndexBuffer> VulkanDriver::createIndexBufferAsyncS() noexcept {
return mResourceManager.allocHandle<VulkanIndexBuffer>();
}
Handle<HwBufferObject> VulkanDriver::createBufferObjectS() noexcept {
return mResourceManager.allocHandle<VulkanBufferObject>();
}
Handle<HwBufferObject> VulkanDriver::createBufferObjectAsyncS() noexcept {
return mResourceManager.allocHandle<VulkanBufferObject>();
}
Handle<HwTexture> VulkanDriver::createTextureS() noexcept {
return mResourceManager.allocHandle<VulkanTexture>();
}
Handle<HwTexture> VulkanDriver::createTextureAsyncS() noexcept {
return mResourceManager.allocHandle<VulkanTexture>();
}
Handle<HwTexture> VulkanDriver::createTextureViewS() noexcept {
return mResourceManager.allocHandle<VulkanTexture>();
}
@@ -1016,6 +1164,10 @@ Handle<HwTexture> VulkanDriver::createTextureViewSwizzleS() noexcept {
return mResourceManager.allocHandle<VulkanTexture>();
}
Handle<HwTexture> VulkanDriver::createTextureViewSwizzleAsyncS() noexcept {
return mResourceManager.allocHandle<VulkanTexture>();
}
Handle<HwTexture> VulkanDriver::createTextureExternalImage2S() noexcept {
return mResourceManager.allocHandle<VulkanTexture>();
}
@@ -1032,6 +1184,30 @@ Handle<HwTexture> VulkanDriver::importTextureS() noexcept {
return mResourceManager.allocHandle<VulkanTexture>();
}
Handle<HwTexture> VulkanDriver::importTextureAsyncS() noexcept {
return mResourceManager.allocHandle<VulkanTexture>();
}
AsyncCallId VulkanDriver::update3DImageAsyncS() noexcept {
// TODO: implement this.
return InvalidAsyncCallId;
}
AsyncCallId VulkanDriver::setVertexBufferObjectAsyncS() noexcept {
// TODO: implement this.
return InvalidAsyncCallId;
}
AsyncCallId VulkanDriver::updateBufferObjectAsyncS() noexcept {
// TODO: implement this.
return InvalidAsyncCallId;
}
AsyncCallId VulkanDriver::updateIndexBufferAsyncS() noexcept {
// TODO: implement this.
return InvalidAsyncCallId;
}
Handle<HwRenderPrimitive> VulkanDriver::createRenderPrimitiveS() noexcept {
return mResourceManager.allocHandle<VulkanRenderPrimitive>();
}
@@ -1090,6 +1266,11 @@ MemoryMappedBufferHandle VulkanDriver::mapBufferS() noexcept {
return mResourceManager.allocHandle<VulkanMemoryMappedBuffer>();
}
AsyncCallId VulkanDriver::queueCommandAsyncS() noexcept {
// TODO: implement this.
return InvalidAsyncCallId;
}
void VulkanDriver::unmapBuffer(MemoryMappedBufferHandle mmbh) {
if (!mmbh) {
return;
@@ -1417,7 +1598,7 @@ bool VulkanDriver::isStereoSupported() {
}
bool VulkanDriver::isParallelShaderCompileSupported() {
return false;
return mContext.shouldUsePipelineCachePrewarming();
}
bool VulkanDriver::isDepthStencilResolveSupported() {
@@ -1437,6 +1618,10 @@ bool VulkanDriver::isDepthClampSupported() {
return mContext.isDepthClampSupported();
}
bool VulkanDriver::isAsynchronousModeEnabled() {
return false;
}
bool VulkanDriver::isWorkaroundNeeded(Workaround workaround) {
switch (workaround) {
case Workaround::SPLIT_EASU: {
@@ -1545,6 +1730,12 @@ void VulkanDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t in
vb->setBuffer(bo, index);
}
void VulkanDriver::setVertexBufferObjectAsyncR(AsyncCallId jobId, Handle<HwVertexBuffer> vbh,
uint32_t index, Handle<HwBufferObject> boh, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
// TODO: implement this.
}
void VulkanDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
uint32_t byteOffset) {
VulkanCommandBuffer& commands = mCommands.get();
@@ -1555,6 +1746,12 @@ void VulkanDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor
scheduleDestroy(std::move(p));
}
void VulkanDriver::updateIndexBufferAsyncR(AsyncCallId jobId, Handle<HwIndexBuffer> ibh,
BufferDescriptor&& p, uint32_t byteOffset, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
// TODO: implement this.
}
void VulkanDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescriptor&& bd,
uint32_t byteOffset) {
VulkanCommandBuffer& commands = mCommands.get();
@@ -1567,6 +1764,12 @@ void VulkanDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescript
scheduleDestroy(std::move(bd));
}
void VulkanDriver::updateBufferObjectAsyncR(AsyncCallId jobId, Handle<HwBufferObject> boh,
BufferDescriptor&& bd, uint32_t byteOffset, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
// TODO: implement this.
}
void VulkanDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> boh,
BufferDescriptor&& bd, uint32_t byteOffset) {
VulkanCommandBuffer& commands = mCommands.get();
@@ -1594,6 +1797,13 @@ void VulkanDriver::update3DImage(Handle<HwTexture> th, uint32_t level, uint32_t
scheduleDestroy(std::move(data));
}
void VulkanDriver::update3DImageAsyncR(AsyncCallId jobId, Handle<HwTexture> th,
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t width,
uint32_t height, uint32_t depth, PixelBufferDescriptor&& data, CallbackHandler* handler,
CallbackHandler::Callback const callback, void* user) {
// TODO: implement this.
}
void VulkanDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) {
}
@@ -1688,7 +1898,11 @@ void VulkanDriver::generateMipmaps(Handle<HwTexture> th) {
void VulkanDriver::compilePrograms(CompilerPriorityQueue priority,
CallbackHandler* handler, CallbackHandler::Callback callback, void* user) {
if (callback) {
scheduleCallback(handler, user, callback);
if (mContext.shouldUsePipelineCachePrewarming()) {
mPipelineCache.addCachePrewarmCallback(handler, callback, user);
} else {
scheduleCallback(handler, user, callback);
}
}
}
@@ -1696,9 +1910,6 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
FVK_SYSTRACE_SCOPE();
auto rt = resource_ptr<VulkanRenderTarget>::cast(&mResourceManager, rth);
VkExtent2D const extent = rt->getExtent();
assert_invariant(rt == mDefaultRenderTarget || extent.width > 0 && extent.height > 0);
VulkanCommandBuffer* commandBuffer = rt->isProtected() ?
&mCommands.getProtected() : &mCommands.get();
@@ -1713,9 +1924,16 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
if (sc->isFirstRenderPass()) {
discardStart |= TargetBufferFlags::COLOR;
sc->markFirstRenderPass();
acquireNextSwapchainImage();
}
}
// Note that retrieving the extent must come after the acquireNextSwapchainImage() above;
// otherwise it might be 0.
VkExtent2D const extent = rt->getExtent();
assert_invariant(rt == mDefaultRenderTarget || extent.width > 0 && extent.height > 0);
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
if (rt->hasDepth()) {
auto depth = rt->getDepth();
@@ -1926,19 +2144,16 @@ void VulkanDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain>
ASSERT_PRECONDITION_NON_FATAL(drawSch == readSch,
"Vulkan driver does not support distinct draw/read swap chains.");
// Before we can render into the new swapchain, we need to make sure the default render target
// releases its old bound swapchain image.
mDefaultRenderTarget->releaseSwapchain();
resource_ptr<VulkanSwapChain> swapChain =
resource_ptr<VulkanSwapChain>::cast(&mResourceManager, drawSch);
mCurrentSwapChain = swapChain;
bool resized = false;
swapChain->acquire(resized);
if (resized) {
mFramebufferCache.resetFramebuffers();
}
if (UTILS_LIKELY(mDefaultRenderTarget)) {
mDefaultRenderTarget->bindToSwapChain(swapChain);
if (mAcquireSwapChainInMakeCurrent) {
acquireNextSwapchainImage();
}
}
@@ -2110,6 +2325,14 @@ void VulkanDriver::blitDEPRECATED(TargetBufferFlags buffers,
auto dstTarget = resource_ptr<VulkanRenderTarget>::cast(&mResourceManager, dst);
auto srcTarget = resource_ptr<VulkanRenderTarget>::cast(&mResourceManager, src);
// This is a valid use of the api. We need to make sure that the swapchain image has been
// acquired and associated with the default render target. It's okay to call
// acquireNextSwapchainImage() even if a swapchain image has already been bound to the default
// render target.
if (dstTarget == mDefaultRenderTarget) {
acquireNextSwapchainImage();
}
VkFilter const vkfilter = (filter == SamplerMagFilter::NEAREST) ?
VK_FILTER_NEAREST : VK_FILTER_LINEAR;
@@ -2397,6 +2620,16 @@ void VulkanDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
mQueryManager.endQuery(&(mCommands.get()), vtq);
}
void VulkanDriver::queueCommandAsyncR(AsyncCallId jobId, utils::Invocable<void()>&& command,
CallbackHandler* handler, CallbackHandler::Callback const callback, void* user) {
// TODO: implement this.
}
bool VulkanDriver::cancelAsyncJob(AsyncCallId jobId) {
// TODO: implement this.
return false;
}
void VulkanDriver::debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept {
DriverBase::debugCommandBegin(cmds, synchronous, methodName);
#ifndef NDEBUG
@@ -2431,6 +2664,25 @@ void VulkanDriver::endCommandRecording() {
mDescriptorSetCache.resetCachedState();
}
void VulkanDriver::acquireNextSwapchainImage() {
assert_invariant(mCurrentSwapChain);
assert_invariant(mDefaultRenderTarget);
// Swapchain has already been bound to the default render target. We just return.
if (mDefaultRenderTarget->isSwapchainBound()) {
return;
}
bool resized = false;
mCurrentSwapChain->acquire(resized);
if (resized) {
mFramebufferCache.resetFramebuffers();
}
// Note that ordering this after the above lines is necessary since we set the swapchain image
// to the render target in bindSwapChain().
mDefaultRenderTarget->bindSwapChain(mCurrentSwapChain);
}
// explicit instantiation of the Dispatcher
template class ConcreteDispatcher<VulkanDriver>;
+5 -1
View File
@@ -132,6 +132,8 @@ private:
// Flush the current command buffer and reset the pipeline state.
void endCommandRecording();
void acquireNextSwapchainImage();
VulkanPlatform* mPlatform = nullptr;
fvkmemory::ResourceManager mResourceManager;
@@ -160,7 +162,6 @@ private:
VulkanExternalImageManager mExternalImageManager;
VulkanStreamedImageManager mStreamedImageManager;
// This maps a VulkanSwapchain to a native swapchain. VulkanSwapchain should have a copy of the
// Platform::Swapchain pointer, but queryFrameTimestamps() and queryCompositorTiming() are
// synchronous calls, making access to VulkanSwapchain unsafe (this difference vs other backends
@@ -204,7 +205,10 @@ private:
bool const mIsSRGBSwapChainSupported;
bool const mIsMSAASwapChainSupported;
bool const mAcquireSwapChainInMakeCurrent;
backend::StereoscopicType const mStereoscopicType;
uint8_t const mStereoscopicEyeCount;
backend::AsynchronousMode const mAsynchronousMode;
// setAcquiredImage is a DECL_DRIVER_API_SYNCHRONOUS_N which means we don't necessarily have the
// data to process it at call time. So we store it and process it during updateStreams.
+39 -21
View File
@@ -100,18 +100,18 @@ inline VkShaderStageFlags getVkStage(backend::ShaderStage stage) {
using BitmaskGroup = VulkanDescriptorSetLayout::Bitmask;
BitmaskGroup fromBackendLayout(DescriptorSetLayout const& layout) {
BitmaskGroup mask;
for (auto const& binding: layout.bindings) {
switch (binding.type) {
for (auto const& descriptor: layout.descriptors) {
switch (descriptor.type) {
case DescriptorType::UNIFORM_BUFFER: {
if ((binding.flags & DescriptorFlags::DYNAMIC_OFFSET) != DescriptorFlags::NONE) {
fromStageFlags(binding.stageFlags, binding.binding, mask.dynamicUbo);
if ((descriptor.flags & DescriptorFlags::DYNAMIC_OFFSET) != DescriptorFlags::NONE) {
fromStageFlags(descriptor.stageFlags, descriptor.binding, mask.dynamicUbo);
} else {
fromStageFlags(binding.stageFlags, binding.binding, mask.ubo);
fromStageFlags(descriptor.stageFlags, descriptor.binding, mask.ubo);
}
break;
}
case DescriptorType::SAMPLER_EXTERNAL:
fromStageFlags(binding.stageFlags, binding.binding, mask.externalSampler);
fromStageFlags(descriptor.stageFlags, descriptor.binding, mask.externalSampler);
UTILS_FALLTHROUGH;
case DescriptorType::SAMPLER_2D_FLOAT:
@@ -139,11 +139,11 @@ BitmaskGroup fromBackendLayout(DescriptorSetLayout const& layout) {
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT: {
fromStageFlags(binding.stageFlags, binding.binding, mask.sampler);
fromStageFlags(descriptor.stageFlags, descriptor.binding, mask.sampler);
break;
}
case DescriptorType::INPUT_ATTACHMENT: {
fromStageFlags(binding.stageFlags, binding.binding, mask.inputAttachment);
fromStageFlags(descriptor.stageFlags, descriptor.binding, mask.inputAttachment);
break;
}
case DescriptorType::SHADER_STORAGE_BUFFER:
@@ -265,24 +265,31 @@ void VulkanDescriptorSet::addNewSet(VkDescriptorSet vkSet, OnRecycle&& onRecycle
PushConstantDescription::PushConstantDescription(backend::Program const& program) {
mRangeCount = 0;
for (auto stage : { ShaderStage::VERTEX, ShaderStage::FRAGMENT, ShaderStage::COMPUTE }) {
uint32_t offset = 0;
// The range is laid out so that the vertex constants are defined as the first set of bytes,
// followed by fragment and compute. This means we need to keep track of the offset for each
// stage. We do the bookeeping in mDescriptions.
for (auto stage: { ShaderStage::VERTEX, ShaderStage::FRAGMENT, ShaderStage::COMPUTE }) {
auto const& constants = program.getPushConstants(stage);
if (constants.empty()) {
continue;
}
auto& description = mDescriptions[(uint8_t) stage];
// We store the type of the constant for type-checking when writing.
auto& types = mTypes[(uint8_t) stage];
types.reserve(constants.size());
std::for_each(constants.cbegin(), constants.cend(), [&types] (Program::PushConstant t) {
types.push_back(t.type);
});
description.types.reserve(constants.size());
std::for_each(constants.cbegin(), constants.cend(),
[&description](Program::PushConstant t) { description.types.push_back(t.type); });
uint32_t const constantsSize = (uint32_t) constants.size() * ENTRY_SIZE;
mRanges[mRangeCount++] = {
.stageFlags = getVkStage(stage),
.offset = 0,
.size = (uint32_t) constants.size() * ENTRY_SIZE,
.offset = offset,
.size = constantsSize,
};
description.offset = offset;
offset += constantsSize;
}
}
@@ -290,7 +297,10 @@ void PushConstantDescription::write(VkCommandBuffer cmdbuf, VkPipelineLayout lay
backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant const& value) {
uint32_t binaryValue = 0;
UTILS_UNUSED_IN_RELEASE auto const& types = mTypes[(uint8_t) stage];
auto const& description = mDescriptions[(uint8_t) stage];
UTILS_UNUSED_IN_RELEASE auto const& types = description.types;
uint32_t const offset = description.offset;
if (std::holds_alternative<bool>(value)) {
assert_invariant(types[index] == ConstantType::BOOL);
bool const bval = std::get<bool>(value);
@@ -304,7 +314,8 @@ void PushConstantDescription::write(VkCommandBuffer cmdbuf, VkPipelineLayout lay
int const ival = std::get<int>(value);
binaryValue = *reinterpret_cast<uint32_t const*>(&ival);
}
vkCmdPushConstants(cmdbuf, layout, getVkStage(stage), index * ENTRY_SIZE, ENTRY_SIZE,
vkCmdPushConstants(cmdbuf, layout, getVkStage(stage), offset + index * ENTRY_SIZE, ENTRY_SIZE,
&binaryValue);
}
@@ -387,8 +398,9 @@ VulkanRenderTarget::VulkanRenderTarget()
VulkanRenderTarget::~VulkanRenderTarget() = default;
void VulkanRenderTarget::bindToSwapChain(fvkmemory::resource_ptr<VulkanSwapChain> swapchain) {
void VulkanRenderTarget::bindSwapChain(fvkmemory::resource_ptr<VulkanSwapChain> swapchain) {
assert_invariant(!mOffscreen);
assert_invariant(!mInfo->colors[0]);
VkExtent2D const extent = swapchain->getExtent();
width = extent.width;
@@ -396,7 +408,8 @@ void VulkanRenderTarget::bindToSwapChain(fvkmemory::resource_ptr<VulkanSwapChain
mProtected = swapchain->isProtected();
VulkanAttachment color = createSwapchainAttachment(swapchain->getCurrentColor());
mInfo->attachments = {color};
assert_invariant(mInfo->attachments.size() == 0);
mInfo->attachments.push_back(color);
auto& fbkey = mInfo->fbkey;
auto& rpkey = mInfo->rpkey;
@@ -422,6 +435,11 @@ void VulkanRenderTarget::bindToSwapChain(fvkmemory::resource_ptr<VulkanSwapChain
mInfo->colors.set(0);
}
void VulkanRenderTarget::releaseSwapchain() {
mInfo->colors = {};
mInfo->attachments.clear();
}
VulkanRenderTarget::VulkanRenderTarget(VkDevice device, VkPhysicalDevice physicalDevice,
VulkanContext const& context, fvkmemory::ResourceManager* resourceManager,
VmaAllocator allocator, VulkanCommands* commands, uint32_t width, uint32_t height,
@@ -675,7 +693,7 @@ void VulkanVertexBuffer::setBuffer(fvkmemory::resource_ptr<VulkanBufferObject> b
VulkanBufferObject::VulkanBufferObject(VulkanContext const& context, VmaAllocator allocator,
VulkanStagePool& stagePool, VulkanBufferCache& bufferCache, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage)
: HwBufferObject(byteCount),
: HwBufferObject(byteCount, false),
bindingType(bindingType),
mBuffer(context, allocator, stagePool, bufferCache, getBufferObjectBinding(bindingType),
usage, byteCount) {}
+15 -3
View File
@@ -245,7 +245,13 @@ struct PushConstantDescription {
private:
static constexpr uint32_t ENTRY_SIZE = sizeof(uint32_t);
utils::FixedCapacityVector<backend::ConstantType> mTypes[Program::SHADER_TYPE_COUNT];
struct ConstantDescription {
utils::FixedCapacityVector<backend::ConstantType> types;
uint32_t offset = 0;
};
// Describes the constants in each shader stage.
ConstantDescription mDescriptions[Program::SHADER_TYPE_COUNT];
VkPushConstantRange mRanges[Program::SHADER_TYPE_COUNT];
uint32_t mRangeCount;
};
@@ -366,7 +372,13 @@ struct VulkanRenderTarget : private HwRenderTarget, fvkmemory::Resource {
inline bool isSwapChain() const { return !mOffscreen; }
inline bool isProtected() const { return mProtected; }
void bindToSwapChain(fvkmemory::resource_ptr<VulkanSwapChain> swapchain);
void bindSwapChain(fvkmemory::resource_ptr<VulkanSwapChain> swapchain);
void releaseSwapchain();
bool isSwapchainBound() const {
return isSwapChain() && mInfo->colors[0];
}
void emitBarriersBeginRenderPass(VulkanCommandBuffer& commands);
@@ -470,7 +482,7 @@ struct VulkanIndexBuffer : public HwIndexBuffer, fvkmemory::Resource {
VulkanIndexBuffer(VulkanContext const& context, VmaAllocator allocator,
VulkanStagePool& stagePool, VulkanBufferCache& bufferCache, uint8_t elementSize,
uint32_t indexCount)
: HwIndexBuffer(elementSize, indexCount),
: HwIndexBuffer(elementSize, indexCount, false),
indexType(elementSize == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32),
mBuffer(context, allocator, stagePool, bufferCache, VulkanBufferBinding::INDEX,
BufferUsage::STATIC, elementSize * indexCount) {}
@@ -16,6 +16,7 @@
#include "VulkanPipelineCache.h"
#include <utils/JobSystem.h>
#include <utils/Log.h>
#include <utils/Panic.h>
@@ -36,6 +37,8 @@ namespace filament::backend {
namespace {
using utils::JobSystem;
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
void printPipelineFeedbackInfo(VkPipelineCreationFeedbackCreateInfo const& feedbackInfo) {
VkPipelineCreationFeedback const& pipelineInfo = *feedbackInfo.pPipelineCreationFeedback;
@@ -66,13 +69,26 @@ void printPipelineFeedbackInfo(VkPipelineCreationFeedbackCreateInfo const& feedb
} // namespace
VulkanPipelineCache::VulkanPipelineCache(VkDevice device, VulkanContext const& context)
VulkanPipelineCache::VulkanPipelineCache(DriverBase& driver, VkDevice device, VulkanContext const& context)
: mDevice(device),
mCallbackManager(driver),
mContext(context) {
VkPipelineCacheCreateInfo createInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
};
bluevk::vkCreatePipelineCache(mDevice, &createInfo, VKALLOC, &mPipelineCache);
if (mContext.shouldUsePipelineCachePrewarming()) {
mCompilerThreadPool.init(
/*threadCount=*/1,
[]() {
JobSystem::setThreadName("CompilerThreadPool");
// This thread should be lower priority than the main thread.
JobSystem::setThreadPriority(JobSystem::Priority::DISPLAY);
}, []() {
// No cleanup required.
});
}
}
void VulkanPipelineCache::bindLayout(VkPipelineLayout layout) noexcept {
@@ -87,9 +103,12 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::getOrCreatePipelin
pipeline.lastUsed = mCurrentTime;
return &pipeline;
}
auto ret = createPipeline();
ret->lastUsed = mCurrentTime;
return ret;
PipelineCacheEntry cacheEntry {
.handle = createPipeline(mPipelineRequirements),
.lastUsed = mCurrentTime,
};
assert_invariant(cacheEntry.handle != VK_NULL_HANDLE && "Pipeline handle is VK_NULL_HANDLE");
return &mPipelines.emplace(mPipelineRequirements, cacheEntry).first.value();
}
void VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) {
@@ -107,70 +126,144 @@ void VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) {
}
}
VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() noexcept {
assert_invariant(mPipelineRequirements.shaders[0] && "Vertex shader is not bound.");
assert_invariant(mPipelineRequirements.layout && "No pipeline layout specified");
void VulkanPipelineCache::asyncPrewarmCache(const VulkanProgram& program,
VkPipelineLayout layout,
StereoscopicType stereoscopicType,
uint8_t stereoscopicViewCount, CompilerPriorityQueue priority) {
PipelineKey key {
.shaders = {
program.getVertexShader(),
program.getFragmentShader(),
},
// We're using dynamic rendering, so this should be empty.
.renderPass = VK_NULL_HANDLE,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.subpassIndex = 0,
// We're using vertex input dynamic state, so these should be empty.
.vertexAttributes = {},
.vertexBuffers = {},
// Create a reasonable default raster state; we're assuming this is not cached.
.rasterState = {
.cullMode = VK_CULL_MODE_NONE,
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
.depthBiasEnable = VK_FALSE,
.blendEnable = VK_FALSE,
.depthWriteEnable = VK_FALSE,
.alphaToCoverageEnable = VK_FALSE,
.srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE,
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
.colorWriteMask = 0,
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
.depthClamp = VK_FALSE,
.colorTargetCount = 1,
.colorBlendOp = BlendEquation::SUBTRACT,
.alphaBlendOp = BlendEquation::SUBTRACT,
.depthCompareOp = SamplerCompareFunc::L,
.depthBiasConstantFactor = 0.f,
.depthBiasSlopeFactor = 0.f,
},
.layout = layout,
};
PipelineDynamicOptions dynamicOptions {
.useDynamicVertexInputState = true,
.useDynamicRenderPasses = true,
.stereoscopicType = stereoscopicType,
.stereoscopicViewCount = stereoscopicViewCount,
};
CallbackManager::Handle cmh = mCallbackManager.get();
auto token = std::make_shared<ProgramToken>();
mCompilerThreadPool.queue(priority, token, [this, key, dynamicOptions, cmh]() mutable {
VkPipeline pipeline = createPipeline(key, dynamicOptions);
mCallbackManager.put(cmh);
// We don't actually need this pipeline, we just wanted to force the driver to cache
// the pipeline's information.
if (pipeline != VK_NULL_HANDLE) {
vkDestroyPipeline(mDevice, pipeline, VKALLOC);
} else {
FVK_LOGW << "Failed to create a pipeline during prewarming, draw-time pipeline "
"creation may fail.";
}
});
}
VkPipeline VulkanPipelineCache::createPipeline(
const PipelineKey& key, const PipelineDynamicOptions& dynamicOptions) noexcept {
assert_invariant(key.shaders[0] && "Vertex shader is not bound.");
assert_invariant(key.layout && "No pipeline layout specified");
VkPipelineShaderStageCreateInfo shaderStages[SHADER_MODULE_COUNT];
shaderStages[0] = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = mPipelineRequirements.shaders[0],
.module = key.shaders[0],
.pName = "main",
};
shaderStages[1] = shaderStages[0];
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
shaderStages[1].module = mPipelineRequirements.shaders[1];
shaderStages[1].module = key.shaders[1];
bool const hasFragmentShader = shaderStages[1].module != VK_NULL_HANDLE;
VkPipelineColorBlendAttachmentState colorBlendAttachments[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT];
VkPipelineColorBlendStateCreateInfo colorBlendState = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.attachmentCount = mPipelineRequirements.rasterState.colorTargetCount,
.attachmentCount = key.rasterState.colorTargetCount,
.pAttachments = colorBlendAttachments,
};
// Expand our size-optimized structs into the proper Vk structs.
uint32_t numVertexAttribs = 0;
uint32_t numVertexBuffers = 0;
VkPipelineVertexInputStateCreateInfo vertexInputState;
VkVertexInputAttributeDescription vertexAttributes[VERTEX_ATTRIBUTE_COUNT];
VkVertexInputBindingDescription vertexBuffers[VERTEX_ATTRIBUTE_COUNT];
for (uint32_t i = 0; i < VERTEX_ATTRIBUTE_COUNT; i++) {
if (mPipelineRequirements.vertexAttributes[i].format > 0) {
vertexAttributes[numVertexAttribs++] = mPipelineRequirements.vertexAttributes[i];
}
if (mPipelineRequirements.vertexBuffers[i].stride > 0) {
vertexBuffers[numVertexBuffers++] = mPipelineRequirements.vertexBuffers[i];
if (!dynamicOptions.useDynamicVertexInputState) {
uint32_t numVertexAttribs = 0;
uint32_t numVertexBuffers = 0;
for (uint32_t i = 0; i < VERTEX_ATTRIBUTE_COUNT; i++) {
if (key.vertexAttributes[i].format > 0) {
vertexAttributes[numVertexAttribs++] = key.vertexAttributes[i];
}
if (key.vertexBuffers[i].stride > 0) {
vertexBuffers[numVertexBuffers++] = key.vertexBuffers[i];
}
}
vertexInputState = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = numVertexBuffers,
.pVertexBindingDescriptions = vertexBuffers,
.vertexAttributeDescriptionCount = numVertexAttribs,
.pVertexAttributeDescriptions = vertexAttributes,
};
}
VkPipelineVertexInputStateCreateInfo vertexInputState = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = numVertexBuffers,
.pVertexBindingDescriptions = vertexBuffers,
.vertexAttributeDescriptionCount = numVertexAttribs,
.pVertexAttributeDescriptions = vertexAttributes,
};
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = (VkPrimitiveTopology) mPipelineRequirements.topology,
.topology = (VkPrimitiveTopology) key.topology,
};
VkPipelineViewportStateCreateInfo viewportState = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 1,
.scissorCount = 1,
};
VkDynamicState dynamicStateEnables[] = {
constexpr size_t maxDynamicStates = 3;
size_t numDynamicStates = 2;
VkDynamicState enabledDynamicStates[maxDynamicStates] = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
};
if (dynamicOptions.useDynamicVertexInputState) {
enabledDynamicStates[numDynamicStates++] = VK_DYNAMIC_STATE_VERTEX_INPUT_EXT;
}
VkPipelineDynamicStateCreateInfo dynamicState = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = 2,
.pDynamicStates = dynamicStateEnables,
.dynamicStateCount = static_cast<uint32_t>(numDynamicStates),
.pDynamicStates = enabledDynamicStates,
};
auto const& raster = mPipelineRequirements.rasterState;
auto const& raster = key.rasterState;
VkPipelineRasterizationStateCreateInfo vkRaster = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = raster.depthClamp,
@@ -218,7 +311,7 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = hasFragmentShader ? SHADER_MODULE_COUNT : 1,
.pStages = shaderStages,
.pVertexInputState = &vertexInputState,
.pVertexInputState = dynamicOptions.useDynamicVertexInputState ? nullptr : &vertexInputState,
.pInputAssemblyState = &inputAssemblyState,
.pViewportState = &viewportState,
.pRasterizationState = &vkRaster,
@@ -226,9 +319,9 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
.pDepthStencilState = &vkDs,
.pColorBlendState = &colorBlendState,
.pDynamicState = &dynamicState,
.layout = mPipelineRequirements.layout,
.renderPass = mPipelineRequirements.renderPass,
.subpass = mPipelineRequirements.subpassIndex,
.layout = key.layout,
.renderPass = key.renderPass,
.subpass = key.subpassIndex,
};
// There are no color attachments if there is no bound fragment shader. (e.g. shadow map gen)
@@ -252,6 +345,27 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
}
}
VkPipelineRenderingCreateInfoKHR renderingInfo {};
VkFormat pipelineRenderingColorFormats[] = {VK_FORMAT_UNDEFINED};
if (dynamicOptions.useDynamicRenderPasses) {
renderingInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR;
renderingInfo.pNext = pipelineCreateInfo.pNext;
// Fill values in with empty values where we do not already have values.
renderingInfo.depthAttachmentFormat = VK_FORMAT_UNDEFINED;
renderingInfo.stencilAttachmentFormat = VK_FORMAT_UNDEFINED;
// If multiview, create a bitmask with bits representing each enabled view set to 1;
// otherwise, set the view mask to 0.
renderingInfo.viewMask = dynamicOptions.stereoscopicType == StereoscopicType::MULTIVIEW ?
(1 << dynamicOptions.stereoscopicViewCount) - 1 : 0;
if (hasFragmentShader) {
renderingInfo.colorAttachmentCount = 1;
renderingInfo.pColorAttachmentFormats = pipelineRenderingColorFormats;
}
pipelineCreateInfo.pNext = &renderingInfo;
}
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
FVK_LOGD << "vkCreateGraphicsPipelines with shaders = (" << shaderStages[0].module << ", "
<< shaderStages[1].module << ")";
@@ -271,11 +385,9 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
pipelineCreateInfo.pNext = &feedbackInfo;
}
#endif
PipelineCacheEntry cacheEntry = {
.lastUsed = mCurrentTime,
};
VkPipeline pipeline;
VkResult error = vkCreateGraphicsPipelines(mDevice, mPipelineCache, 1, &pipelineCreateInfo,
VKALLOC, &cacheEntry.handle);
VKALLOC, &pipeline);
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
FVK_LOGD << "vkCreateGraphicsPipelines with shaders = (" << shaderStages[0].module << ", "
@@ -289,9 +401,9 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
assert_invariant(error == VK_SUCCESS);
if (error != VK_SUCCESS) {
FVK_LOGE << "vkCreateGraphicsPipelines error " << error;
return nullptr;
return VK_NULL_HANDLE;
}
return &mPipelines.emplace(mPipelineRequirements, cacheEntry).first.value();
return pipeline;
}
void VulkanPipelineCache::bindProgram(fvkmemory::resource_ptr<VulkanProgram> program) noexcept {
@@ -334,6 +446,14 @@ void VulkanPipelineCache::bindVertexArray(VkVertexInputAttributeDescription cons
}
}
void VulkanPipelineCache::addCachePrewarmCallback(CallbackHandler* handler,
const CallbackHandler::Callback callback,
void* user) {
if (callback) {
mCallbackManager.setCallback(handler, callback, user);
}
}
void VulkanPipelineCache::resetBoundPipeline() {
mBoundPipeline = {};
}
@@ -345,6 +465,9 @@ void VulkanPipelineCache::terminate() noexcept {
mPipelines.clear();
resetBoundPipeline();
mCallbackManager.terminate();
mCompilerThreadPool.terminate();
vkDestroyPipelineCache(mDevice, mPipelineCache, VKALLOC);
}
@@ -17,6 +17,8 @@
#ifndef TNT_FILAMENT_BACKEND_VULKANPIPELINECACHE_H
#define TNT_FILAMENT_BACKEND_VULKANPIPELINECACHE_H
#include "CallbackManager.h"
#include "CompilerThreadPool.h"
#include "VulkanCommands.h"
#include <backend/DriverEnums.h>
@@ -86,14 +88,38 @@ public:
static_assert(sizeof(RasterState) == 16, "RasterState must not have implicit padding.");
VulkanPipelineCache(VkDevice device, VulkanContext const& context);
/**
* Creates a new instance of a pipeline cache for graphics pipelines.
*
* @param driver The driver this is being instantiated for. This is used only for construction of
* the callback manager, which references the driver for scheduling callbacks.
* @param device The device that the pipelines will be created and run on.
* @param context Information about the current instance of Vulkan, such as supported extensions,
* and enabled features.
*/
VulkanPipelineCache(DriverBase& driver, VkDevice device, VulkanContext const& context);
void bindLayout(VkPipelineLayout layout) noexcept;
// Loads a fake pipeline into memory on a separate thread, with the intent of
// preloading the Vulkan cache with enough information to have a cache hit when
// compiling the pipeline on the main thread at draw time. This is very dependent
// on the implementation of the driver on the current device; it's expected to work
// on devices with VK_EXT_vertex_input_dynamic_state and VK_KHR_dynamic_rendering.
void asyncPrewarmCache(const VulkanProgram& program, VkPipelineLayout layout,
StereoscopicType stereoscopicType, uint8_t stereoscopicViewCount,
CompilerPriorityQueue priority);
// Notifies the callback once all in-flight async cache prewarm jobs are complete.
// This typically signals that it is safe to use a material at draw time without
// hitching.
void addCachePrewarmCallback(CallbackHandler* handler,
const CallbackHandler::Callback callback,
void* user);
// Creates a new pipeline if necessary and binds it using vkCmdBindPipeline.
void bindPipeline(VulkanCommandBuffer* commands);
// Each of the following methods are fast and do not make Vulkan calls.
void bindLayout(VkPipelineLayout layout) noexcept;
void bindProgram(fvkmemory::resource_ptr<VulkanProgram> program) noexcept;
void bindRasterState(RasterState const& rasterState) noexcept;
void bindRenderPass(VkRenderPass renderPass, int subpassIndex) noexcept;
@@ -164,6 +190,19 @@ private:
VkPipelineLayout layout; // 8 : 304
};
// Provides information about any dynamic state that should be used in creation of the
// pipeline (if supported).
struct PipelineDynamicOptions {
// Requires `VK_EXT_vertex_input_dynamic_state` to enable.
bool useDynamicVertexInputState = false;
// Requires `VK_KHR_dynamic_rendering` to enable.
bool useDynamicRenderPasses = false;
// Only used if `useDynamicRenderPasses` is true.
StereoscopicType stereoscopicType = StereoscopicType::NONE;
// Only used if `stereoscopicType` is `StereoscopicType::MULTIVIEW`.
uint8_t stereoscopicViewCount = 2;
};
static_assert(sizeof(PipelineKey) == 312, "PipelineKey must not have implicit padding.");
using PipelineHashFn = utils::hash::MurmurHashFn<PipelineKey>;
@@ -195,8 +234,15 @@ private:
PipelineMap mPipelines;
// Creates a pipeline, with all optional dynamic pipeline states diabled.
// Note - because PipelineDynamicOptions is defined within VulkanPipelineCache,
// we cannot define the function with a default arg for it explicitly.
inline VkPipeline createPipeline(const PipelineKey& key) noexcept {
return createPipeline(key, {});
}
// These helpers all return unstable pointers that should not be stored.
PipelineCacheEntry* createPipeline() noexcept;
VkPipeline createPipeline(const PipelineKey& key, const PipelineDynamicOptions& dynamicOptions) noexcept;
// Immutable state.
VkDevice mDevice = VK_NULL_HANDLE;
@@ -211,6 +257,14 @@ private:
// Current bindings for the pipeline and descriptor sets.
PipelineKey mBoundPipeline = {};
// Thread pool that allows us to "prewarm" the pipeline cache, reducing draw-time
// pipeline compilation time.
CompilerThreadPool mCompilerThreadPool;
// Callback manager that allows us to notify the frontend when a set of pipelines have
// been prewarmed, signifying that it is safe to compile pipelines at draw time.
CallbackManager mCallbackManager;
[[maybe_unused]] VulkanContext const& mContext;
};
@@ -33,7 +33,7 @@ VkPipelineLayout VulkanPipelineLayoutCache::getLayout(
// build the push constant layout key
uint32_t const pushConstantRangeCount = program->getPushConstantRangeCount();
auto const& pushConstantRanges = program->getPushConstantRanges();
auto pushConstantRanges = program->getPushConstantRanges();
if (pushConstantRangeCount > 0) {
assert_invariant(pushConstantRangeCount <= Program::SHADER_TYPE_COUNT);
for (uint8_t i = 0; i < pushConstantRangeCount; ++i) {

Some files were not shown because too many files have changed in this diff Show More