Compare commits

..
Author SHA1 Message Date
Powei Feng edb77fe6a9 docs: add doxygen file for DriverAPI.inc
This has been mostly auto-generated by an AI assistant. But
the documentation looks correct and can serve as a base point
for improvements.
2025-07-02 13:15:45 -07:00
Sungun Park 954d1021c7 Add #include <cstdlib> to avoid compilation error (#8922) 2025-07-02 18:54:03 +00:00
Sungun Park bf598071a3 gl: move shader code instead of copy (#8918)
In Debug mode, remove unnecessary memory reallocation & copy by moving
shader code blob.
2025-07-02 17:41:43 +00:00
Powei Feng 5cbc2321c7 Add feature flag for attribute stride check (#8913)
We also add a define to log (instead of assert) failtures of
certain correctness checks.  This allows clients to gradually
fix their code.
2025-07-02 17:06:37 +00:00
Mathias Agopian 6bee5fb56f fix PixelBufferDescriptor overflow calculation
We simply compute the coordinate of the last pixel that need to be 
accessed and deduce its offset, which must be smaller than the 
buffer size.
2025-07-01 16:08:58 -07:00
Mathias Agopian eb0fcc065b workaround gcc permissive warning. Fixes #8883. 2025-07-01 16:08:26 -07:00
Andy Hovingh 117535364b webgpu: support auto-resolve render passes (render target samples != attached texture samples)
The solution resembles that of the other backends, to implement msaa sidecar textures.

Note: this solution does not resolve depth/stencil textures
2025-07-01 15:59:09 -05:00
Powei Feng b15ae15f39 No need for blending when upscaling (#8900)
The dst buffer is allocated and should not be blended against.
The blending code is a relic of a previous code path that's
no longer present [link].

[link]: https://github.com/google/filament/blame/c049a1bfff0851098bf640159fb6c5daab88d5d4/filament/src/PostProcessManager.cpp

FIXES=422593171
2025-07-01 05:43:23 +00:00
Powei Feng 74445904f2 Release Filament 1.62.0 2025-06-30 16:39:15 -07:00
Powei Feng 678ad4ff98 Fix assert in resolve for stencil buffer (#8908)
The assert in resolve() will trigger even if the pass is
ultimately not needed (culled out). So if a user has
 - disabled postprocessing
 - uses stencil buffer

They will still hit an assert in debug mode. Here we just delay
the assert until when we're actuallly setting up the pass.
2025-06-30 21:18:36 +00:00
Powei Feng b6d7ed2b35 Bump Material Version to 62 2025-06-29 22:34:35 -07:00
Jeremy Nelson 725e33763a remove 256 padding in WriteTexture 2025-06-27 13:30:51 -07:00
Juan Caldas f24146c169 webgpu: Solve black issue screen (#8907)
Solve black issue screen
2025-06-27 15:15:43 -04:00
Ben Doherty 67288d483f materials: Add VARIANT_DEPTH define for depth shader variants (#8905) 2025-06-27 14:23:37 -04:00
Anish GoyalandSerge Metral c80c504a2a Fix adjustedMemcpy for compressed formats (#8902)
Right now, the way we calculate 'bytes per pixel' returns 0 in the case
of compressed texture formats. The easy solution in these cases is to
simply fall back to the full buffer size.

Co-authored-by: Serge Metral <sergemetral@google.com>
2025-06-27 08:28:55 -07:00
Ben Doherty 1f8cacdd70 matinfo: Report if a material has custom depth (#8904) 2025-06-26 17:30:01 -04:00
Andy Hovingh a3ae9431f1 webgpu: update pipeline cache key to include render target 2025-06-26 14:56:45 -05:00
Powei Feng 3d0653604f android: add static, default model for gltf-viewer (#8898)
The default gltf for android's gltf-viewer is the buster drone,
which uses skinning.

We add an additional model (damaged helmet) as an alternative
default. This will be useful for debugging WebGPU, where skinnning is
not yet supported. This alternate path can only be invoke by starting
the app through adb:

  `adb shell am start -n com.google.android.filament.gltf/.MainActivity --ez "use-static-model" true`
2025-06-26 19:15:54 +00:00
Powei Feng 42a0a41be0 webgpu: remove float filterable requirement (#8895)
This will enable webgpu for devices such as pixel 4, which does
not support this feature.
2025-06-26 18:15:41 +00:00
Powei Feng 468d9cccb7 Add Engine config for gpu priority (#8893) 2025-06-26 17:47:57 +00:00
Powei Feng 6cfd058e3d docs: fix commit hash parsing bug (#8882)
- Re-enable docs presbumit check (checks if there has been direct
    edits of /docs).
 - Fix script to download and install mdbook
 - Update Materials.md.html and re-run the build script
    (build/run.py).
2025-06-26 17:31:03 +00:00
Andy Hovingh 8234549cb9 webgpu: implement render pass based mipmap generation (supports more texture formats than compute pass based mipmap generation) 2025-06-26 08:25:23 -05:00
Benjamin Doherty c84d04254e Release Filament 1.61.2 2025-06-25 12:29:24 -07:00
Ben Doherty 573a51c430 Fix segfault in matinfo (#8896) 2025-06-25 12:25:19 -07:00
Ben Doherty b4d26bd32b Fix ASAN use-after-stack-free in VulkanPlatform (#8897) 2025-06-25 19:06:36 +00:00
Ben Doherty 5227ea36ce Fix error in PBD size check (#8886) 2025-06-25 11:49:21 -07:00
Doris Wu 6f29ff988c Fix the inconsistent comment (#8887) 2025-06-25 03:05:45 +00:00
Sungun Park 3424222d6e Add flag to control the GPU priority (#8892)
Add a knob to control the priority of the GPU work submitted to the
application. Currently it's only supported for EGL.

BUGS=[416589006]
2025-06-24 15:10:07 -07:00
Anish Goyal a9ab9b6cd4 Fix staging buffer alignment (#8872)
* Fix staging buffer alignment

Note: we were not aligning texture copies properly, so this broke
certain use cases on the Pixel 4.

* Address PR comment

Convert optional type to a simple int type with a default value, for
the alignment arg for acquiring a staging buffer.
2025-06-24 13:47:21 -07:00
Jeremy Nelson 5d11dd653a only use depthstencil for setuprenderpassattachments 2025-06-23 14:30:04 -07:00
Jeremy Nelson 7d1cb3ee85 add requestedDepth 2025-06-23 14:30:04 -07:00
Jeremy Nelson 8304cd9c32 simplified attachment logic 2025-06-23 14:30:04 -07:00
Jeremy Nelson 6d1c337363 use Target Buffer Flags for Depth and Stencil 2025-06-23 14:30:04 -07:00
rafadevaiandSerge Metral e59036c731 VK: Simple staging bypass for free uniform buffers (#8852)
* VK: Simple staging bypass for free uniform buffers

When the uniform VulkanBuffer is currently not in
use and under UMA, just perform a direct memcpy to
GPU memory.

Add a flag to control disable this flow and always
use staging to update buffers.

* Addressing review comments

Use a constant instead of a custommization option
to known if we always use staging for updates or not.

---------

Co-authored-by: Serge Metral <sergemetral@google.com>
2025-06-23 09:26:26 -07:00
Juan Caldas dd7d78b2a6 webgpu: Set Load and Store Ops (#8889) 2025-06-23 15:27:36 +00:00
Powei Feng f096c4d8de Add unfilterable to Material sampler definition (#8873)
`unfiterable : true` indicates that the sampling of the texture
will not apply filtering.

This is mainly to satisfy the webgpu requirement for
bindGroupLayouts.

 - Documentation has been updated for both `unfilterable` and
   `multisample`.
 - Internal materials have been updated where necessary (depth
   samplers have to be marked as `unfilterable`.)
 - webgpu code has been changed appropriately.

BUGS=420745987
2025-06-18 21:14:42 +00:00
Juan Caldas da5ea821a8 webgpu: Add alphaToCoverage (#8885) 2025-06-18 20:56:55 +00:00
Powei Feng 1b944a6582 webgpu: fix two things wrt linux build (#8881)
- Added an explicit link flag for libxcb in backend/CMakeLists.txt
 - Made a string func inline, otherwise we'd get duplicate
   definition error during linking.

FIXES=419788369
2025-06-18 19:58:56 +00:00
Andy Hovingh 318a9002e7 webgpu: implement fence 2025-06-18 12:47:17 -05:00
utzcoz eb5d9ac15d android: Update gradlew files to the upstream version (#8802)
Run twice:

./gradlew wrapper --gradle-version 8.8 --distribution-type bin
2025-06-18 05:22:59 +00:00
Benjamin Doherty 5cae0ee082 Switch instance of slog.w to Abseil-style logging 2025-06-17 17:00:02 -07:00
Powei Feng 75d641ae8a renderdiff: fix artifact upload (#8879)
- Fix a problem where the output directory's name  has been
   changed
- Add git commit hash to the golden directory
2025-06-17 23:20:45 +00:00
Konrad Piascik c2c744b06d webgpu: Implement driver limits 2025-06-17 09:23:40 -04:00
Konrad Piascik 1e246d1332 webgpu: Remove warning since most samples are now functional 2025-06-17 09:23:40 -04:00
Matthew Hoffman 7d242341f2 Let backend test binary run from anywhere. (#8864) 2025-06-16 20:49:05 +00:00
bridgewaterrobbie e625c7024c webgpu: fix max uniform buffer size not being set properly. This resolves a validation error seen with TransmissionSuzanne.gltf 2025-06-16 16:15:06 -04:00
bridgewaterrobbie 192a61a06b Wait for work of first frame to be done before any presenting 2025-06-16 11:21:27 -04:00
Powei Feng 6a93e3a765 vk: clean-up ycbcr conversion enums (#8859)
Moved them out of DriverEnums because only the vk backend needs
them.
2025-06-16 05:58:48 +00:00
Powei Feng e1fb1391f9 ds: emit undefined param warning once per descriptorset (#8862) 2025-06-16 05:42:45 +00:00
Sungun Park a3922ac3a9 Bump MATERIAL_VERSION to 61 2025-06-13 15:39:09 -07:00
Sungun Park 5f1112d85e Update RELEASE_NOTES for the revert 2025-06-13 15:26:56 -07:00
Sungun Park 09545690bf Revert "materials: introduce mutable spec constants (#8795)"
This reverts commit 8a1a0b0fd2.
2025-06-13 15:02:55 -07:00
Powei Feng 3ce752c47b gltfio: enable passing in variant filters (#8851)
This enables filtering variants when using the JitMaterialProvider.
2025-06-13 21:06:22 +00:00
bridgewaterrobbie 1f9f3ddb91 Use the mipmap generator to properly generate mipmaps. 2025-06-13 16:46:18 -04:00
bridgewaterrobbie 8e94688fbf Request higher maxStorageTexturesPerShaderStage if the device supports it. 2025-06-13 16:46:18 -04:00
bridgewaterrobbie 438ee40f40 Account for array layers, utilizing maxStorageTexturesPerShaderStage to configure 2025-06-13 16:46:18 -04:00
bridgewaterrobbie 7f22d733d7 webgpu: Significant cleanup of mipmap generator interface and logic. Now properly queries and uses device limits of maxMipsPerPass. Still fairly hacky though 2025-06-13 16:46:18 -04:00
Andy Hovingh 77d77f0a5c webgpu: fix logging 2025-06-13 07:23:56 -05:00
Sungun Park 0aabd3dd6a Fix: Prevent deadlock when loading programs from cache (#8849)
When a program was created directly from a cached blob in
`ShaderCompilerService`, its associated token was not signaled as ready
in the THREAD_POOL mode. This oversight caused a deadlock at the
`token->wait()` call during program destruction.

This commit resolves the issue by skipping the token's readiness check
upon destruction if the program was created from the cache blob.

BUGS=[423221474]
2025-06-12 21:05:59 +00:00
Benjamin Doherty 72a54b30f9 Temporary workaround for PlatformMetal 2025-06-12 13:23:49 -07:00
bridgewaterrobbie 00b2ab7ac4 webgpu: Use C++ converted mipmap generator. First pass, likely to be tweaked substantially in the future 2025-06-12 15:13:10 -04:00
dependabot[bot]andPowei Feng 39e15d67fc Bump brace-expansion (#8855)
Bumps the npm_and_yarn group with 1 update in the /build/common/upload-release-assets directory: [brace-expansion](https://github.com/juliangruber/brace-expansion).


Updates `brace-expansion` from 1.1.11 to 1.1.12
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/1.1.11...v1.1.12)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.12
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Powei Feng <powei@google.com>
2025-06-12 17:55:35 +00:00
Juan Caldas 921dbddad9 webgpu: add condition to sample (#8860)
* Add option for enabling MSAA
2025-06-12 12:14:54 -04:00
Andy Hovingh 6406d4602c webgpu: texture changes to better support mipmap generation later 2025-06-11 22:35:42 -05:00
Sungun Park 880cd66166 Release Filament 1.61.1 2025-06-12 00:31:33 +00:00
Juan Caldas f27ff203cf webgpu: Enable multisampling in the sample (#8854) 2025-06-11 23:09:59 +00:00
Ben Doherty 3ea8e529cc Switch filament and backend to Abseil logging (#8691) 2025-06-11 10:08:52 -07:00
Jeremy Nelson 572dd233d7 adding check for Stencil8 2025-06-10 20:06:00 -07:00
Jeremy Nelson c19070e477 better default cases for loadOp and storeOp 2025-06-10 20:06:00 -07:00
Jeremy Nelson 64328b7388 pass through defaultDepthStencilFormat 2025-06-10 20:06:00 -07:00
Powei Feng 1414fdcd38 github: fix commit message action (#8846)
Checkout sha instead of the branch
2025-06-10 22:55:48 +00:00
Matthew Hoffman e607a035ae Add TODOs for backend test features that shouldn't be made yet. (#8829)
Some edge case handling features are possibly needed, but should only be made
once they have use cases that exercise that behavior. So for now just
leave TODOs explaining where to add it in the future.

BUGS=[422804941,422803382]
2025-06-10 21:43:47 +00:00
Ben Doherty 0496e089c1 Remove old screenshot output for readPixels backend test (#8840) 2025-06-10 13:30:00 -07:00
Juan Caldas b310e3d24a webgpu: Add missing WEBGPU cases (#8839) 2025-06-10 13:56:48 -04:00
Juan Caldas b359d77669 webgpu: Adjust the wrap modes (#8844)
* Change the WebGPU wrap modes
2025-06-10 11:09:37 -04:00
Sungun Park e57a4061cc Add missing header (#8842) 2025-06-09 21:01:29 +00:00
Powei Feng 53f82e6b71 vk: rename selectMemory params (#8835)
Use more accurate parameter names. 'types' indicate the types
of memory we are considering.  'reqs' indicate the requirements
each type must meet.

BUGS=401579988
2025-06-09 20:33:08 +00:00
rafadevaiandSerge Metral e88bba5940 VK: Disable VMA internal synchronization (#8836)
The vulkan backend is currently single threads, so there's
no need for VMA to use synchronization internally. This
will improve the CPU performance when going through VMA.

Co-authored-by: Serge Metral <sergemetral@google.com>
2025-06-09 20:05:02 +00:00
Matthew Hoffman 0b83454d08 Fix backend tests on macos vulkan. (#8815) 2025-06-09 19:05:03 +00:00
Matthew Hoffman 1ef0d36f79 Improve and document the backend test helper script. (#8816) 2025-06-09 18:19:30 +00:00
Powei Feng e350737d1e Remove texture pbd check for compressed textures (#8837)
This will also fix the failing ktx test.
2025-06-09 17:47:55 +00:00
Andy Hovingh cb203b13de webgpu: refactor: sort CMake source files 2025-06-09 11:05:15 -05:00
Andy Hovingh 92a0d7bfc3 webgpu: refactor: move WebGPU render target class to its own source+header files. 2025-06-09 11:05:15 -05:00
Andy Hovingh c1a7ed2799 webgpu: refactor: move WebGPU texture class to its own source+header files. 2025-06-09 11:05:15 -05:00
Andy Hovingh 692301bdf1 webgpu: refactor: move WebGPU descriptor set related classes to their own source+header files. 2025-06-09 11:05:15 -05:00
Andy Hovingh 05b87b3c42 webgpu: refactor: move WebGPU buffer classes to their own source+header files. 2025-06-09 11:05:15 -05:00
Andy Hovingh 9825297e70 webgpu: refactor: move WebGPUProgram to its own source+header files. 2025-06-09 11:05:15 -05:00
Powei Feng 6a59c887de vk: implement proper offset when uploading to texture (#8830)
We didn't take into account the top/left/stride parameters of the
PixelBufferDescriptor.
2025-06-06 20:46:45 +00:00
bridgewaterrobbie 33b4b46220 Create simple gltf viewer based on gltf_instances, primarily to facilitate webgpu development 2025-06-06 14:51:17 -04:00
Powei Feng 06170a25f7 Fix PBD size check in Texture (#8826)
Bug found when running ./samples/heightfield and press add pixel
buffer padding.
2025-06-06 18:20:05 +00:00
Konrad Piascik 418dad883d webgpu: Fix Android material compilation
Instead of requiring GL_EXT_shader_non_constant_global_initializers
we can just make the new variables const

BUGS=[421457710]
2025-06-06 13:46:37 -04:00
Jeremy Nelson 447661efed Use colorInfos.layer 2025-06-05 22:18:34 -07:00
Jeremy Nelson bd61ab691c add Default miplevel and array layer 2025-06-05 22:18:34 -07:00
Jeremy Nelson 2a04cee97f rename member variables 2025-06-05 22:18:34 -07:00
Jeremy Nelson 5ae7760752 fix samplerType check 2025-06-05 22:18:34 -07:00
Jeremy Nelson 56b8bf5b4b noexcept to makeTextureView 2025-06-05 22:18:34 -07:00
Jeremy Nelson 6af38fa47f renaming param to samplerType 2025-06-05 22:18:34 -07:00
Jeremy Nelson 0c01799c50 overload getTextureView 2025-06-05 22:18:34 -07:00
Jeremy Nelson e2519e0eed Update WebGPUHandles.cpp 2025-06-05 22:18:34 -07:00
Jeremy Nelson 6178ae0459 Use colorInfos.layer
# Conflicts:
#	filament/backend/src/webgpu/WebGPUHandles.cpp
2025-06-05 22:18:34 -07:00
Eliza 8a1a0b0fd2 materials: introduce mutable spec constants (#8795)
* materials: introduce mutable spec constants

Rationale & design of this feature has been discussed internally.

The current implementation uses a `FixedCapacityVector` to store the new program
handles, but I wouldn't object to replacing it with a hasmap as discussed
offline.

I have compiled but not tested this yet on Android, so I'm not certain that the
API bindings are correctly wired up.

* materials: mutable spec constant feedback

* materials: address mutable spec constant comments
2025-06-06 03:52:20 +00:00
Powei Feng a7c3cf4173 Ensure maximum number of vertex buffer does not exceed 8 (#8824) 2025-06-05 21:16:38 +00:00
bridgewaterrobbie 57b68eeba3 webgpu: Add required feature RG11B10UfloatRenderable for gltf_viewer, with comment on why 2025-06-05 15:08:03 -04:00
Juan Caldas ad8c9ce4e0 Add common CLI Args parser for the samples (#8819) 2025-06-05 18:18:41 +00:00
Powei Feng 7dc0f2cc86 vk: fix two validation error (#8825)
On starting gltf_viewer on mac, there were validation errors on

 1) copying to a depth texture using the aspect COLOR.
 2) querying formats that required extensions without enabling those
    extensions.
2025-06-05 17:50:40 +00:00
bridgewaterrobbie 37110799ef webgpu: Correct stencil state handling for depth-only formats 2025-06-05 13:22:26 -04:00
Anish GoyalandSerge Metral 88a06ec8e7 Switch to block-based stage-pool for Vulkan (#8742)
* Switch to block-based stage-pool for Vulkan

Instead of allocating a staging buffer every time one is needed,
allocate a large (8mb) block of memory, and divvy it up as needed.
We will make this configurable in the future, to allow for tuning
for different apps as needed.

* Address PR comments: use fvkmemory::Resource

Instead of having the child block be a unique_ptr that we create a
separate container for within the command buffers, just have the
stage block segments be fvkmemory::Resource instances.

* Address PR comments for staging buff change

- As per discussion with @poweifeng, change the name of a variable
  called "stage" to "stageSegment" for clarity
- As per discussion with @rafadevai, change the order of terminate
  calls in VulkanDriver to better reflect cleanup order of some
  objects.

* Align stage pool to nonCoherentAtomSize

In order to prevent flushing more atoms than were modified when writing
data to host-mapped memory in a staging buffer, ensure that all segments
allocated are aligned to nonCoherentAtomSize.

Also - fix merge conflict compile errors.

---------

Co-authored-by: Serge Metral <sergemetral@google.com>
2025-06-05 09:15:26 -07:00
bridgewaterrobbie 38705d6226 Add todos for unimplemented funcs that we haven't yet started on 2025-06-05 10:48:59 -04:00
bridgewaterrobbie d325bb43cf Add destroy texture implementation 2025-06-05 10:48:59 -04:00
Sungun Park 0c52d3c9bf Fix: Submit callback handle on completion (#8818)
This reverts a behavioral regression introduced in commit c3542b135e,
which deferred callback submission until the program was first used.

This commit restores the correct behavior by submitting the callback
handle as soon as the token's work is complete. This occurs either upon
successful `gl.program` population or via cancellation, ensuring the
caller is properly notified that the resource loading operation has
concluded.
2025-06-04 16:44:48 +00:00
Konrad Piascik 770176a1e3 Fix Windows build error C2512 2025-06-04 11:17:05 -04:00
bridgewaterrobbie 672603f9b4 Generate mipmaps when requested, deferring as needed 2025-06-03 17:45:35 -04:00
Powei Feng 0ecf6c46e2 github: Fix commit message parsing (#8817) 2025-06-03 14:24:29 -07:00
Andy Hovingh 8b87a54c1a webgpu: fix vertex buffer info for hellopbr 2025-06-03 16:08:12 -05:00
Powei Feng cd1d3e8749 github: update windows runner due to 2019 being "stuck" (#8814) 2025-06-03 13:27:31 -07:00
rafadevai e88072cec0 VK: Introduce VulkanBufferCache (#8757)
This class will allow better tracking of memory
allocations and recycling of buffers. Currently
only the uniform buffers are recycled.

It will eventually allow us to dynamically change
the underlying GPU buffer of a VulkanBuffer when
updating an UBO for uniforms and also keep track
which of those buffers are still inflight and which
ones are ready to be reuse for an UBO.

Its the first step on moving towards by passing
the staging buffer in UMA.
2025-06-03 12:36:50 -07:00
Powei Feng 1d2e165d99 Release Filament 1.61.0 2025-06-03 12:02:10 -07:00
Powei Feng cfc4ac5511 Add missing include in JobSystem.cpp (#8812) 2025-06-03 11:44:42 -07:00
Powei Feng 73a03d7af0 Flip conditional for fixing missing samplers (#8811) 2025-06-03 11:19:29 -07:00
Powei Feng 56dc348cc8 utils: add additional guards for Tracing (#8810)
The addition JobSystem.cpp allows for defining
FILAMENT_TRACING_ENABLED across targets.

Addingin FILAMENT_TRACING_ENABLED to the #if in Tracing.h prevents
perfetto from being included.
2025-06-03 11:18:11 -07:00
Juan Caldas 1b46ddd8b6 Webgpu: Check for Shadows (#8807)
BUGS=[397432947]
2025-06-03 11:57:34 +00:00
Powei Feng a68aaa114e renderdiff: fix breakage in parsing commit message (#8808) 2025-06-02 15:55:35 -07:00
Powei Feng 3da7dabb2a renderdiff: enable update goldens on commit merge (#8771) 2025-06-02 14:12:26 -07:00
bridgewaterrobbie 1e2311da3d Fix the fact that isSample might be combined with the other flags 2025-06-02 16:18:08 -04:00
bridgewaterrobbie a38c55c82d Fix use accidental use of uninitalized HwTexture::target 2025-06-02 16:18:08 -04:00
Powei Feng cd22478e4f renderdiff: add viewer for image differences (#8768)
- Modify the compare script to output more details of a
   comparison. This will include the source/golden directory,
   the comparison directory (the new renderings), and a file
   path to difference images if the golden does not match
   the rendered image.
 - The image_diff script can now output a TIFF that is the
   difference of two input TIFFs.
 - Add a viewer for examining the differences between rendered
   output and golden images.
 - The viewer consists of a simple server of web API endpoints
   for querying difference results (along with rendered images
   in TIFF).
 - And a web-based (html + lit-element) UI for looking at the
   rendered images and differences.
2025-06-02 19:37:46 +00:00
bridgewaterrobbie 60036c75fe Remove asserts that throw on shadowtest. Investigate them later 2025-06-02 14:17:39 -04:00
Powei Feng 044f2aeb7c gl: keep external texture id in sync (#8803)
(Attributed to @dsternfeld7)
2025-06-02 17:18:00 +00:00
Juan Caldas c73d11858e Webgpu: Move Filter mode check (#8804)
BUGS=[397432947]
2025-06-02 14:10:33 +00:00
Powei Feng 23b67be41a Fix always bind uniform logic in MaterialInstance (#8801)
The logic for duplicating UBO was omitted after #8739
2025-06-01 23:27:55 -07:00
bridgewaterrobbie 7d53baad5c Add float32 filtering feature, so that we can safely assume non-int non-depth types are filtering. 2025-05-30 17:53:04 -04:00
doriswu 1ae33a23fe Use highp for square distance 2025-05-30 13:52:44 -07:00
Rafael Dominguez 351d9287af Update the clang-format rule for comments
Make sure theres a space before the comment

So now instead of getting
 #endif// comment

it will be
 #endif // comment
2025-05-30 13:52:01 -07:00
Mathias Agopian e7e5004946 attempt to fix external streams with protected context
There was several issues:

1) when we're switching contexts (e.g. between protect and regular) we
   needed up reattach all SurfaceView (i.e. streams), because they need
   to be attached on currently active context.

2) reattaching, because it's implemented as detach + attach, would 
   destroy the current gl texture id and create a new one. However,
   because of the way descriptor-sets were implemented, that GL
   texture id was kept inside the descriptor, later leading to using
   a destroyed texture id.
   The fix here is to store texture handles in descriptors, so that
   we can update the id independently. 

3) we also needed to invalidate all bound descriptor sets because it's
   now possible for descriptor sets to have outdated descriptors
2025-05-30 13:15:40 -07:00
Juan Caldas b9be9b4f2d Set Render Pipeline 2025-05-30 15:06:50 -05:00
Powei Feng ce88a56579 Fix leaking dummy depth array texture (#8796) 2025-05-30 17:19:55 +00:00
Powei Feng 689e769f9a utils: Fix FixedCircularBufferTest.Exceptions (#8794)
Switching from assert_invariant to assert produced a different
error message.
2025-05-30 10:02:31 -07:00
Jeremy Nelson 2f0a8b19b5 use params in draw call 2025-05-30 11:49:05 -05:00
Andy Hovingh 1bed68afb7 webgpu: support user-defined spec constants in addition to native Filament ones 2025-05-30 11:33:14 -05:00
Konrad Piascik 130e02da5c Add helper script to linux documentation (#8783) 2025-05-30 14:16:36 +00:00
bridgewaterrobbie 8e06a68446 Relocate calling mRenderPassEncoder.SetBindGroup to draw call, deferring it to handle non-default render targets being used. 2025-05-29 20:23:06 -04:00
bridgewaterrobbie 656b50b304 Manually remove Tint annotations that Dawn complains about when consuming.
Dawn complains when consuming these lines with
WebGPU device error: ErrorType::Validation Error while parsing WGSL: :24:4 error: expected attribute
Did you mean 'size'?
Possible values: 'align', 'binding', 'blend_src', 'builtin', 'color', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'input_attachment_index', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size'
  @stride(16) @internal(disable_validation__ignore_stride)

And we don't see a better workaround at this time.
2025-05-29 17:59:12 -04:00
Mathias Agopian 880db4ec43 fix a buffer overflow during init
the default cubemap has RGBA pixels (4 bytes per pixel).
2025-05-29 14:27:38 -07:00
Syed Idris Shah 2ce294720d vertex buffer info hardening.
Implement vertexbufferinfo taking both interleaved and block attributes into account.
Handle the unused buffers by dedicating a slot for that.
Update the usage of vertexbufferinfo for setVertexBuffer call
2025-05-29 15:51:55 -05:00
Juan Caldas eb07decb4b wgpu: Ignore spec constants greater than 10 (#8789) 2025-05-29 15:58:35 -04:00
Mathias Agopian 47930edf70 don't use assert_invariant in public headers
this is to eventually suppress the dependency on utils/debug.h from
public headers
2025-05-29 09:56:52 -07:00
Mathias Agopian 05b89905d8 fix a use after free of texture data during init (#8786) 2025-05-28 22:32:24 -07:00
Powei Feng 3e0df36c1c Add option to disable GTAO (#8785) 2025-05-28 22:35:14 +00:00
Powei Feng c9ce384f14 vk: add missing header (#8781) 2025-05-28 22:17:55 +00:00
Sungun Park 6a6bdd5be7 Fix broken android samples (#8784)
that use DescriptorType::SAMPLER_EXTERNAL.
2025-05-28 20:56:20 +00:00
Sungun Park d56ade924e Add checks for MSAA (#8782) 2025-05-28 19:48:12 +00:00
Andy Hovingh fe561e3e27 webgpu: support selection from multiple adapters/graphics devices 2025-05-28 12:52:04 -05:00
Jeremy Nelson 1d98e350e4 Set stencil ops to undefined if nonexistent 2025-05-27 16:28:01 -07:00
Matthew Hoffman d34e018acb Replace 512 magic number in backend tests. (#8775) 2025-05-27 21:39:50 +00:00
Mathias Agopian 169c8d57ff assert vertex attribute alignment
offset and size must now be a multiple of 4
2025-05-27 10:19:53 -07:00
Mathias Agopian a1e0cfa33c fix a few noexcept through out the code base 2025-05-27 10:18:12 -07:00
Sungun Park 6d44db3ca0 Fix a compile error
This is a fix for the compile error caused by
https://github.com/google/filament/commit/86a500c8465cfac76cdc4dcc86ab184e9edeac19
2025-05-23 10:33:14 -07:00
Sungun Park a261429d06 Add multiview MSAA support for custom swapchain (#8767)
BUGS=[417311684]
2025-05-23 00:42:04 +00:00
Matthew Hoffman 69d0de3c6d In backend tests replace calls to draw with draw2. (#8765)
BUGS=[398199600]
2025-05-22 13:14:52 -05:00
bridgewaterrobbie 1305303f2e Fix typo in getVertexFormat 2025-05-20 18:13:19 -04:00
bridgewaterrobbie 8532511107 Add enforced check for compressed texture block width/height offset 2025-05-20 16:10:17 -04:00
bridgewaterrobbie b762ccb78c Use the aspect to skip drawing for depth only. TODO is why this is even coming up? 2025-05-20 16:10:17 -04:00
bridgewaterrobbie 3296eb153c If necessary, apply padding to uploaded texture. 2025-05-20 16:10:17 -04:00
bridgewaterrobbie ae6d1028f7 Initial update3DImage implementation for webgpu 2025-05-20 16:10:17 -04:00
bridgewaterrobbie 92579b6307 Expose bytes per pixel function separately from computeDataSize 2025-05-20 16:10:17 -04:00
352 changed files with 13539 additions and 4695 deletions
+1 -1
View File
@@ -57,7 +57,7 @@ SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 0
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
+45
View File
@@ -0,0 +1,45 @@
name: 'Get commit message'
outputs:
msg:
value: ${{ steps.action_output.outputs.msg }}
runs:
using: "composite"
steps:
- name: Find commit message (on push)
if: github.event_name == 'push'
shell: bash
run: |
AUTHOR_NAME="${{ github.event.head_commit.author.name }}"
AUTHOR_EMAIL="${{ github.event.head_commit.author.email }}"
TSTAMP="${{ github.event.head_commit.timestamp }}"
echo "commit ${{ github.event.head_commit.id }}" >> /tmp/commit_msg.txt
echo "Author: ${AUTHOR_NAME}<${AUTHOR_EMAIL}>" >> /tmp/commit_msg.txt
echo "Date: ${TSTAMP}" >> /tmp/commit_msg.txt
echo "" >> /tmp/commit_msg.txt
echo "${{ github.event.head_commit.message }}" >> /tmp/commit_msg.txt
- name: Find commit message (PR)
shell: bash
id: checkout_code
if: github.event_name == 'pull_request'
run: |
echo "+++++ head commit message +++++"
echo "$(git log -1 --no-merges)"
echo "+++++++++++++++++++++++++++++++"
echo "hash=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
git checkout ${{ github.event.pull_request.head.sha }}
echo "$(git log -1 --no-merges)" >> /tmp/commit_msg.txt
- shell: bash
id: action_output
run: |
DELIMITER="EOF_FILE_CONTENT_$(date +%s)" # Using timestamp to make it more unique
echo "msg<<$DELIMITER" >> "$GITHUB_OUTPUT"
cat /tmp/commit_msg.txt >> "$GITHUB_OUTPUT"
echo "$DELIMITER" >> "$GITHUB_OUTPUT"
echo "----- got commit message ---"
cat /tmp/commit_msg.txt
echo "----------------------------"
- name: Cleanup Find commit message (PR)
shell: bash
if: github.event_name == 'pull_request'
run: |
git checkout ${{ steps.checkout_code.outputs.hash }}
+35
View File
@@ -0,0 +1,35 @@
name: 'Post-submit 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 }}
run: |
GOLDEN_BRANCH=$(echo "${{ steps.get_commit_msg.outputs.msg }}" | python3 test/renderdiff/src/commit_msg.py)
COMMIT_HASH=$(echo "${{ steps.get_commit_msg.outputs.msg }}" | head -n 1 | tr -d 'commit ')
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
+11 -12
View File
@@ -3,10 +3,10 @@ name: Presubmit
on:
push:
branches:
- main
- main
pull_request:
branches:
- main
- main
jobs:
build-desktop-mac:
@@ -54,7 +54,6 @@ jobs:
build-android:
name: build-android
runs-on: 'ubuntu-24.04-16core'
steps:
- uses: actions/checkout@v4.1.6
with:
@@ -73,7 +72,6 @@ jobs:
build-ios:
name: build-iOS
runs-on: macos-14-xlarge
steps:
- uses: actions/checkout@v4.1.6
with:
@@ -89,7 +87,6 @@ jobs:
build-web:
name: build-web
runs-on: 'ubuntu-24.04-16core'
steps:
- uses: actions/checkout@v4.1.6
with:
@@ -107,11 +104,12 @@ jobs:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- id: get_commit_msg
uses: ./.github/actions/get-commit-msg
- name: Check for manual edits to /docs
run: |
echo "${{ github.event.pull_request.head.sha }} -- ${{ github.event.pull_request.head.sha }}"
# disable for now
# bash docs_src/build/presubmit_check.sh ${{ github.event.pull_request.head.sha }}
COMMIT_ID=$(echo "${{ steps.get_commit_msg.outputs.msg }}" | head -n 1 | sed "s/commit //g")
bash docs_src/build/presubmit_check.sh ${COMMIT_ID}
test-renderdiff:
name: test-renderdiff
@@ -120,24 +118,25 @@ jobs:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- id: get_commit_msg
uses: ./.github/actions/get-commit-msg
- uses: ./.github/actions/mac-prereq
- name: Cache Mesa and deps
id: mesa-cache
uses: actions/cache@v4
with:
path: mesa
key: ${{ runner.os }}-mesa-deps-2-${{ vars.MESA_VERSION }}
- name: Prerequisites
id: prereqs
run: |
bash build/common/get-mesa.sh
pip install tifffile numpy
- name: Run Test
run: bash test/renderdiff/test.sh
run: |
echo "${{ steps.get_commit_msg.outputs.msg }}" | bash test/renderdiff/test.sh
- uses: actions/upload-artifact@v4
with:
name: presubmit-renderdiff-result
path: ./out/renderdiff_tests
path: ./out/renderdiff
validate-wgsl-webgpu:
name: validate-wgsl-webgpu
+4
View File
@@ -97,6 +97,10 @@ Make sure you've installed the following dependencies:
- `libxcomposite-dev` (`libXcomposite-devel` on Fedora)
- `libxxf86vm-dev` (`libXxf86vm-devel` on Fedora)
```shell
sudo apt install clang-14 libglu1-mesa-dev libc++-14-dev libc++abi-14-dev ninja-build libxi-dev libxcomposite-dev libxxf86vm-dev -y
```
After dependencies have been installed, we highly recommend using the [easy build](#easy-build)
script.
+6
View File
@@ -49,6 +49,8 @@ option(FILAMENT_SUPPORTS_OSMESA "Enable OSMesa (headless GL context) for Filamen
option(FILAMENT_ENABLE_FGVIEWER "Enable the frame graph viewer" OFF)
option(FILAMENT_USE_ABSEIL_LOGGING "Use Abseil to log, may increase binary size" OFF)
# This is to disable GTAO for the short-term while we investigate a way to better manage size increases.
# On the regular filament build (where size is of less concern), we enable GTAO by default.
option(FILAMENT_DISABLE_GTAO "Disable GTAO" OFF)
@@ -591,6 +593,10 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT FILAMENT_BACKEND_DEBUG_FLAG STREQU
unset(FILAMENT_BACKEND_DEBUG_FLAG)
endif()
if (FILAMENT_USE_ABSEIL_LOGGING)
add_definitions(-DFILAMENT_USE_ABSEIL_LOGGING)
endif()
# ==================================================================================================
# Material compilation flags
# ==================================================================================================
+1 -1
View File
@@ -1,7 +1,7 @@
# Filament Release Notes log
**If you are merging a PR into main**: please add the release note below, under the *Release notes
for next branch cut* header.
We are chaning the way Vulkan buffers are handled. We need to switch over to a managed (or view-based) model where the data stored inside the object is a proxy to a Vulkan object that can dynamically be swapped around.
**If you are cherry-picking a commit into an rc/ branch**: add the release note under the
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.61.0'
implementation 'com.google.android.filament:filament-android:1.62.0'
}
```
@@ -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.61.0'
pod 'Filament', '~> 1.62.0'
```
## Documentation
+16
View File
@@ -7,6 +7,22 @@ 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.62.1
- Add new shader define `VARIANT_DEPTH`, defined when a material is compiled for depth variants
(e.g., shadows) [**Requires recompiling materials**]
## v1.62.0
- Add new `unfilterable` field to Filament Material's `sampler` [⚠️ **New Material Version**]
## v1.61.2
- samples: samples now have a CLI to select backend api
## v1.61.1
## v1.61.0
- materials: sampler now export their type in the material binary [⚠️ **New Material Version**]
+5
View File
@@ -59,6 +59,10 @@ add_library(smol-v STATIC IMPORTED)
set_target_properties(smol-v PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libsmol-v.a)
add_library(abseil STATIC IMPORTED)
set_target_properties(abseil PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libabseil.a)
if (FILAMENT_ENABLE_FGVIEWER)
add_library(fgviewer STATIC IMPORTED)
set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION
@@ -128,6 +132,7 @@ target_link_libraries(filament-jni
PRIVATE jnigraphics
PRIVATE utils
PRIVATE perfetto
PRIVATE abseil
# libgeometry is PUBLIC because gltfio uses it.
PUBLIC geometry
@@ -556,7 +556,8 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
jlong resourceAllocatorCacheSizeMB, jlong resourceAllocatorCacheMaxAge,
jboolean disableHandleUseAfterFreeCheck,
jint preferredShaderLanguage,
jboolean forceGLES2Context, jboolean assertNativeWindowIsValid) {
jboolean forceGLES2Context, jboolean assertNativeWindowIsValid,
jint gpuContextPriority) {
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
Engine::Config config = {
.commandBufferSizeMB = (uint32_t) commandBufferSizeMB,
@@ -574,6 +575,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
.preferredShaderLanguage = (Engine::Config::ShaderLanguage) preferredShaderLanguage,
.forceGLES2Context = (bool) forceGLES2Context,
.assertNativeWindowIsValid = (bool) assertNativeWindowIsValid,
.gpuContextPriority = (Engine::GpuContextPriority) gpuContextPriority,
};
builder->config(&config);
}
@@ -175,6 +175,36 @@ public class Engine {
MULTIVIEW,
};
/**
* This controls the priority level for GPU work scheduling, which helps prioritize the
* submitted GPU work and enables preemption.
*/
public enum GpuContextPriority {
/**
* Backend default GPU context priority (typically MEDIUM)
*/
DEFAULT,
/**
* For non-interactive, deferrable workloads. This should not interfere with standard
* applications.
*/
LOW,
/**
* The default priority level for standard applications.
*/
MEDIUM,
/**
* For high-priority, latency-sensitive workloads that are more important than standard
* applications.
*/
HIGH,
/**
* The highest priority, intended for system-critical, real-time applications where missing
* deadlines is unacceptable (e.g., VR/AR compositors or other system-critical tasks).
*/
REALTIME,
};
/**
* Constructs <code>Engine</code> objects using a builder pattern.
*/
@@ -233,7 +263,8 @@ public class Engine {
config.resourceAllocatorCacheSizeMB, config.resourceAllocatorCacheMaxAge,
config.disableHandleUseAfterFreeCheck,
config.preferredShaderLanguage.ordinal(),
config.forceGLES2Context, config.assertNativeWindowIsValid);
config.forceGLES2Context, config.assertNativeWindowIsValid,
config.gpuContextPriority.ordinal());
return this;
}
@@ -489,6 +520,11 @@ public class Engine {
* @Deprecated use "backend.opengl.assert_native_window_is_valid" feature flag instead
*/
public boolean assertNativeWindowIsValid = false;
/**
* GPU context priority level. Controls GPU work scheduling and preemption.
*/
public GpuContextPriority gpuContextPriority = GpuContextPriority.DEFAULT;
}
private Engine(long nativeEngine, Config config) {
@@ -1492,7 +1528,8 @@ public class Engine {
long resourceAllocatorCacheSizeMB, long resourceAllocatorCacheMaxAge,
boolean disableHandleUseAfterFreeCheck,
int preferredShaderLanguage,
boolean forceGLES2Context, boolean assertNativeWindowIsValid);
boolean forceGLES2Context, boolean assertNativeWindowIsValid,
int gpuContextPriority);
private static native void nSetBuilderFeatureLevel(long nativeBuilder, int ordinal);
private static native void nSetBuilderSharedContext(long nativeBuilder, long sharedContext);
private static native void nSetBuilderPaused(long nativeBuilder, boolean paused);
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.61.0
VERSION_NAME=1.62.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
Binary file not shown.
+2 -1
View File
@@ -1,6 +1,7 @@
#Wed Nov 17 10:40:18 PST 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
+179 -115
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,99 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +119,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,88 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
+19 -16
View File
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
@@ -18,6 +18,7 @@ package com.google.android.filament.gltf
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.*
@@ -50,6 +51,7 @@ class MainActivity : Activity() {
// Load the library for the utility layer, which in turn loads gltfio and the Filament core.
init { Utils.init() }
private const val TAG = "gltf-viewer"
private const val STATIC_MODEL_TAG = "use-static-model"
}
private lateinit var surfaceView: SurfaceView
@@ -69,6 +71,7 @@ class MainActivity : Activity() {
private var loadStartTime = 0L
private var loadStartFence: Fence? = null
private val viewerContent = AutomationEngine.ViewerContent()
private var useStaticModel = false
@SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
@@ -83,6 +86,12 @@ class MainActivity : Activity() {
doubleTapDetector = GestureDetector(applicationContext, doubleTapListener)
singleTapDetector = GestureDetector(applicationContext, singleTapListener)
val intent: Intent = intent
val bundle: Bundle? = intent.extras
bundle?.let {
useStaticModel = it.getBoolean(STATIC_MODEL_TAG, false)
}
modelViewer = ModelViewer(surfaceView)
viewerContent.view = modelViewer.view
viewerContent.sunlight = modelViewer.light
@@ -141,7 +150,16 @@ class MainActivity : Activity() {
}
private fun createDefaultRenderables() {
val buffer = assets.open("models/scene.gltf").use { input ->
// Sometimes it's useful to set to the default model to something static. You can enable
// the static model by launching the app from adb, as in
// `adb shell am start -n com.google.android.filament.gltf/.MainActivity --ez "use-static-model" true`
val modelPath = if (useStaticModel) {
"models/helmet.glb"
} else {
"models/scene.gltf"
}
val buffer = assets.open(modelPath).use { input ->
val bytes = ByteArray(input.available())
input.read(bytes)
ByteBuffer.wrap(bytes)
+9 -2
View File
@@ -41,6 +41,8 @@ for cmd in "${NEEDED_PYTHON_DEPS[@]}"; do
done
deactivate
LOCAL_PKG_CONFIG_PATH=
# Install system deps
if [[ "$OS_NAME" == "Linux" ]]; then
if [[ "$GITHUB_WORKFLOW" ]]; then
@@ -82,6 +84,9 @@ elif [[ "$OS_NAME" == "Darwin" ]]; then
fi
fi
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=true brew install autoconf automake libx11 libxext libxrandr llvm@${LLVM_VERSION} ninja meson pkg-config libxshmfence
# For reasons unknown, this is necessary for pkg-config to find homebrew's packages
LOCAL_PKG_CONFIG_PATH="/opt/homebrew/lib/pkgconfig:$PKG_CONFIG_PATH"
fi # [[ "$OS_NAME" == x ]]
LOCAL_LDFLAGS=${LDFLAGS}
@@ -134,9 +139,11 @@ fi
# -Dgallium-drivers=swrast => builds GL software rasterizer
# -Dvulkan-drivers=swrast => builds VK software rasterizer
# -Dgallium-drivers=llvmpipe is needed for GL >= 4.1 pipe-screen (see src/gallium/auxiliary/target-helpers/inline_sw_helper.h)
CXX=${LOCAL_CXX} CC=${LOCAL_CC} PATH=${LOCAL_PATH} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \
PKG_CONFIG_PATH=${LOCAL_PKG_CONFIG_PATH} PATH=${LOCAL_PATH} \
CXX=${LOCAL_CXX} CC=${LOCAL_CC} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \
meson setup --wipe builddir/ -Dprefix="${MESA_DIR}/out" -Dglx=xlib -Dosmesa=true -Dgallium-drivers=llvmpipe,swrast -Dvulkan-drivers=swrast
CXX=${LOCAL_CXX} CC=${LOCAL_CC} PATH=${LOCAL_PATH} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \
PKG_CONFIG_PATH=${LOCAL_PKG_CONFIG_PATH} PATH=${LOCAL_PATH} \
CXX=${LOCAL_CXX} CC=${LOCAL_CC} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \
meson install -C builddir/
# Disable python venv
+7 -6
View File
@@ -204,9 +204,10 @@
"license": "Apache-2.0"
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -409,9 +410,9 @@
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
+5 -2
View File
@@ -1027,8 +1027,11 @@ samplerCubemap | Cubemap texture
[Table [materialParamsTypes]: Material parameter types]
Samplers
: Sampler types can also specify a `format` which can be either `int` or `float` (defaults to
`float`).
: Sampler types can have the following fields:
- `format` : which can be either `int` or `float` (defaults to `float`).
- `multisample` : a boolean to indicate whether the sampler is meant for multisampling (defaults to `false`)
- `unfilterable` : a boolean to indicate whether the sampling is not filtered (defaults to `false`)
Arrays
: A parameter can define an array of values by appending `[size]` after the type name, where
-5
View File
@@ -30,11 +30,6 @@ from utils import execute, ArgParseImpl
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
ROOT_DIR = os.path.join(CUR_DIR, '../../')
def get_last_commit_hash():
res, ret = execute('git rev-parse HEAD', cwd=ROOT_DIR)
assert res == 0, 'Failed to get the last commit hash'
return ret.strip()
def get_edited_files(commit_hash):
INSERT = '#####?????'
res, ret = execute(f'git show --name-only --pretty=%b{INSERT} {commit_hash}')
+6 -5
View File
@@ -39,13 +39,13 @@ function download_mdbook() {
fi
local CHECK_UNAME="
import sys;
parts=[a.lower() for a in sys.stdin.read().strip().split(' ')];
import sys
parts=[a.lower() for a in sys.stdin.read().strip().split(' ')]
def get_type():
if 'darwin' in parts:
if 'x86_64' in parts:
return ${DARWIN_X86}
elif 'aarch' in parts:
elif 'aarch' in parts or 'arm64' in parts:
return ${DARWIN_ARM}
elif 'linux' in parts:
if 'x86_64' in parts:
@@ -63,11 +63,12 @@ print(get_type())
echo "*** Need to install Rust ***"
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
fi
source "${HOME}/.cargo/env"
if ! (command -v cargo >/dev/null 2>&1); then
echo "*** Still cannot find `cargo` ***"
echo "*** Still cannot find cargo ***"
exit 1
fi
cargo install mdbook
cargo install --force mdbook
else
# Download prebuilts from github
mkdir -p ${HOME}/.cargo/bin
+30 -23
View File
@@ -13,7 +13,7 @@ This document is part of the [Filament project](https://github.com/google/filame
## Authors
- [Romain Guy](https://github.com/romainguy), [@romainguy](https://twitter.com/romainguy)
- [Mathias Agopian](https://github.com/pixelflinger), [@darthmoosious](https://twitter.com/darthmoosious)
- [Mathias Agopian](https://github.com/pixelflinger), [@pixelflinger](https://bsky.app/profile/pixelflinger.bsky.social)
# Overview
@@ -78,26 +78,27 @@ in table [standardProperties].
Property | Definition
-----------------------:|:---------------------
**baseColor** | Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces
**metallic** | Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1)
**roughness** | Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections
**metallic** | Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1)
**reflectance** | Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections
**sheenColor** | Strength of the sheen layer
**sheenRoughness** | Perceived smoothness or roughness of the sheen layer
**ambientOcclusion** | Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0
**clearCoat** | Strength of the clear coat layer
**clearCoatRoughness** | Perceived smoothness or roughness of the clear coat layer
**clearCoatNormal** | A detail normal used to perturb the clear coat layer using _bump mapping_ (_normal mapping_)
**anisotropy** | Amount of anisotropy in either the tangent or bitangent direction
**anisotropyDirection** | Local surface direction in tangent space
**ambientOcclusion** | Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0
**normal** | A detail normal used to perturb the surface using _bump mapping_ (_normal mapping_)
**bentNormal** | A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality
**clearCoatNormal** | A detail normal used to perturb the clear coat layer using _bump mapping_ (_normal mapping_)
**emissive** | Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass
**postLightingColor** | Additional color that can be blended with the result of the lighting computations. See `postLightingBlending`
**ior** | Index of refraction, either for refractive objects or as an alternative to reflectance
**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
**absorption** | Absorption factor for refractive objects
**microThickness** | Thickness of the thin layer of refractive objects
**thickness** | Thickness of the solid volume of refractive objects
**sheenColor** | Strength of the sheen layer
**sheenRoughness** | Perceived smoothness or roughness of the sheen layer
**emissive** | Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass
**normal** | A detail normal used to perturb the surface using _bump mapping_ (_normal mapping_)
**postLightingColor** | Additional color that can be blended with the result of the lighting computations. See `postLightingBlending`
**absorption** | Absorption factor for refractive objects
**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
**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]
The type and range of each property is described in table [standardPropertiesTypes].
@@ -991,10 +992,13 @@ Type
Value
: Each entry is an object with the properties `name` and `type`, both of `string` type. The
name must be a valid GLSL identifier. Entries also have an optional `precision`, which can be
name must be a valid GLSL identifier. Entries have an optional `precision`, which can be
one of `default` (best precision for the platform, typically `high` on desktop, `medium` on
mobile), `low`, `medium`, `high`. The type must be one of the types described in
table [materialParamsTypes].
table [materialParamsTypes]. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
used to expose the transform matrix associated with the external sampler. In iOS and Vulkan,
this will always be identity.
Type | Description
:----------------------|:---------------------------------
@@ -1023,12 +1027,8 @@ samplerCubemap | Cubemap texture
[Table [materialParamsTypes]: Material parameter types]
Samplers
: Sampler types can specify additional options:
- `format`: either `int` or `float` (defaults to `float`).
- `stages`: array of strings containing the list of shader stages this
sampler can be accessed from. Each entry must be either `vertex` or
`fragment` (defaults to both).
: Sampler types can also specify a `format` which can be either `int` or `float` (defaults to
`float`).
Arrays
: A parameter can define an array of values by appending `[size]` after the type name, where
@@ -1273,6 +1273,9 @@ Description
when selecting any shading model that is not `unlit`. See the shader sections of this document
for more information on how to access these attributes from the shaders.
!!! Note: Interaction with custom variables
When the `color` attribute is specified, only four custom variables are available instead of five.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
parameters : [
@@ -1303,7 +1306,7 @@ Type
: array of `string`
Value
: Up to 4 strings, each must be a valid GLSL identifier.
: Up to 5 strings, each must be a valid GLSL identifier.
Description
: Defines custom interpolants (or variables) that are output by the material's vertex shader.
@@ -1319,6 +1322,10 @@ Description
particular if `default` is specified the default precision is used is the fragment shader
(`mediump`) and in the vertex shader (`highp`).
!!! Warning: Interaction with required attributes
If the `color` attribute is specified in the `required` list, then only four variables can be used
instead of five.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
name : Skybox,
+30 -19
View File
@@ -146,7 +146,7 @@ This document is part of the <a href="https://github.com/google/filament">Filame
<ul>
<li class="minus"><a href="https://github.com/romainguy">Romain Guy</a>, <a href="https://twitter.com/romainguy">@romainguy</a>
</li>
<li class="minus"><a href="https://github.com/pixelflinger">Mathias Agopian</a>, <a href="https://twitter.com/darthmoosious">@darthmoosious</a></li></ul>
<li class="minus"><a href="https://github.com/pixelflinger">Mathias Agopian</a>, <a href="https://bsky.app/profile/pixelflinger.bsky.social">@pixelflinger</a></li></ul>
</p>
<a class="target" name="overview">&nbsp;</a><a class="target" name="overview">&nbsp;</a><a class="target" name="toc2">&nbsp;</a><h1>Overview</h1>
<p>
@@ -217,26 +217,27 @@ in <a href="#table_standardproperties" target="_self">table&nbsp;1</a>.
<div class='table'>
<a class="target" name="table_standardproperties">&nbsp;</a><table class="table longtable"><tr><th style="text-align:right"> Property </th><th style="text-align:left"> Definition </th></tr>
<tr><td style="text-align:right"> <strong class="asterisk">baseColor</strong> </td><td style="text-align:left"> Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">metallic</strong> </td><td style="text-align:left"> Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1) </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">roughness</strong> </td><td style="text-align:left"> Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">metallic</strong> </td><td style="text-align:left"> Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1) </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">reflectance</strong> </td><td style="text-align:left"> Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">sheenColor</strong> </td><td style="text-align:left"> Strength of the sheen layer </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">sheenRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the sheen layer </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">ambientOcclusion</strong> </td><td style="text-align:left"> Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0 </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">clearCoat</strong> </td><td style="text-align:left"> Strength of the clear coat layer </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the clear coat layer </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatNormal</strong> </td><td style="text-align:left"> A detail normal used to perturb the clear coat layer using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">anisotropy</strong> </td><td style="text-align:left"> Amount of anisotropy in either the tangent or bitangent direction </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">anisotropyDirection</strong> </td><td style="text-align:left"> Local surface direction in tangent space </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">ambientOcclusion</strong> </td><td style="text-align:left"> Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0 </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">normal</strong> </td><td style="text-align:left"> A detail normal used to perturb the surface using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">bentNormal</strong> </td><td style="text-align:left"> A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatNormal</strong> </td><td style="text-align:left"> A detail normal used to perturb the clear coat layer using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">emissive</strong> </td><td style="text-align:left"> Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">postLightingColor</strong> </td><td style="text-align:left"> Additional color that can be blended with the result of the lighting computations. See <code>postLightingBlending</code> </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">ior</strong> </td><td style="text-align:left"> Index of refraction, either for refractive objects or as an alternative to reflectance </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">transmission</strong> </td><td style="text-align:left"> 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 </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">absorption</strong> </td><td style="text-align:left"> Absorption factor for refractive objects </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">microThickness</strong> </td><td style="text-align:left"> Thickness of the thin layer of refractive objects </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">thickness</strong> </td><td style="text-align:left"> Thickness of the solid volume of refractive objects </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">sheenColor</strong> </td><td style="text-align:left"> Strength of the sheen layer </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">sheenRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the sheen layer </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">emissive</strong> </td><td style="text-align:left"> Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">normal</strong> </td><td style="text-align:left"> A detail normal used to perturb the surface using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">postLightingColor</strong> </td><td style="text-align:left"> Additional color that can be blended with the result of the lighting computations. See <code>postLightingBlending</code> </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">absorption</strong> </td><td style="text-align:left"> Absorption factor for refractive objects </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">transmission</strong> </td><td style="text-align:left"> 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 </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">ior</strong> </td><td style="text-align:left"> Index of refraction, either for refractive objects or as an alternative to reflectance </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">microThickness</strong> </td><td style="text-align:left"> Thickness of the thin layer of refractive objects </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">bentNormal</strong> </td><td style="text-align:left"> A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">shadowStrength</strong> </td><td style="text-align:left"> Strength factor between 0 and 1 for all shadows received by this material </td></tr>
</table><center><div class="tablecaption"><b style="font-style:normal;">Table&nbsp;1:</b> Properties of the standard model</div></center></div>
</p><p>
The type and range of each property is described in <a href="#table_standardpropertiestypes" target="_self">table&nbsp;2</a>.
@@ -1097,10 +1098,13 @@ non-shader data.
<dl><dt>Type</dt><dd><p> array of parameter objects
</p></dd><dt>Value</dt><dd><p> Each entry is an object with the properties <code>name</code> and <code>type</code>, both of <code>string</code> type. The
name must be a valid GLSL identifier. Entries also have an optional <code>precision</code>, which can be
name must be a valid GLSL identifier. Entries have an optional <code>precision</code>, which can be
one of <code>default</code> (best precision for the platform, typically <code>high</code> on desktop, <code>medium</code> on
mobile), <code>low</code>, <code>medium</code>, <code>high</code>. The type must be one of the types described in
<a href="#table_materialparamstypes" target="_self">table&nbsp;14</a>.
<a href="#table_materialparamstypes" target="_self">table&nbsp;14</a>. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
used to expose the transform matrix associated with the external sampler. In iOS and Vulkan,
this will always be identity.
</p></dd></dl><div class='table'>
<a class="target" name="table_materialparamstypes">&nbsp;</a><table class="table longtable"><tr><th style="text-align:left"> Type </th><th style="text-align:left"> Description </th></tr>
<tr><td style="text-align:left"> bool </td><td style="text-align:left"> Single boolean </td></tr>
@@ -1322,7 +1326,10 @@ non-shader data.
required and does not need to be specified. The <code>tangents</code> attribute is automatically required
when selecting any shading model that is not <code>unlit</code>. See the shader sections of this document
for more information on how to access these attributes from the shaders.
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
</p></dd></dl><div class="admonition note"><div class="admonition-title"> Interaction with custom variables</div>
</p><p>
When the <code>color</code> attribute is specified, only four custom variables are available instead of five.</div>
</p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> parameters <span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
<span class="line"></span> <span class="hljs-punctuation">{</span>
<span class="line"></span> type <span class="hljs-punctuation">:</span> sampler2d<span class="hljs-punctuation">,</span>
@@ -1347,7 +1354,7 @@ non-shader data.
<p>
<dl><dt>Type</dt><dd><p> array of <code>string</code>
</p></dd><dt>Value</dt><dd><p> Up to 4 strings, each must be a valid GLSL identifier.
</p></dd><dt>Value</dt><dd><p> Up to 5 strings, each must be a valid GLSL identifier.
</p></dd><dt>Description</dt><dd><p> Defines custom interpolants (or variables) that are output by the material's vertex shader.
Each entry of the array defines the name of an interpolant. The full name in the fragment
shader is the name of the interpolant with the <code>variable_</code> prefix. For instance, if you
@@ -1360,7 +1367,11 @@ non-shader data.
In this case the specified precision is used as-is in both fragment and vertex stages, in
particular if <code>default</code> is specified the default precision is used is the fragment shader
(<code>mediump</code>) and in the vertex shader (<code>highp</code>).
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
</p></dd></dl><div class="admonition warning"><div class="admonition-title"> Interaction with required attributes</div>
</p><p>
If the <code>color</code> attribute is specified in the <code>required</code> list, then only four variables can be used
instead of five.</div>
</p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> name <span class="hljs-punctuation">:</span> Skybox<span class="hljs-punctuation">,</span>
<span class="line"></span> parameters <span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
<span class="line"></span> <span class="hljs-punctuation">{</span>
+4
View File
@@ -601,6 +601,10 @@ target_link_libraries(${TARGET} PUBLIC filaflat)
target_link_libraries(${TARGET} PUBLIC filabridge)
target_link_libraries(${TARGET} PUBLIC ibl-lite)
if (FILAMENT_USE_ABSEIL_LOGGING)
target_link_libraries(${TARGET} PUBLIC absl::log)
endif()
if (FILAMENT_ENABLE_FGVIEWER)
target_link_libraries(${TARGET} PUBLIC fgviewer)
add_definitions(-DFILAMENT_ENABLE_FGVIEWER=1)
+5 -4
View File
@@ -92,7 +92,7 @@ Copy your platform's Makefile below into a `Makefile` inside the same directory.
### Linux
```make
FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl
FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl -labseil
CC=clang++
main: main.o
@@ -110,12 +110,13 @@ clean:
### macOS
```make
FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl
FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl -labseil
FRAMEWORKS=-framework Cocoa -framework Metal -framework CoreVideo
CC=clang++
ARCH ?= $(shell uname -m)
main: main.o
$(CC) -Llib/x86_64/ main.o $(FILAMENT_LIBS) $(FRAMEWORKS) -o main
$(CC) -Llib/$(ARCH)/ main.o $(FILAMENT_LIBS) $(FRAMEWORKS) -o main
main.o: main.cpp
$(CC) -Iinclude/ -std=c++17 -c main.cpp
@@ -139,7 +140,7 @@ used to change the run-time library version.
```make
FILAMENT_LIBS=filament.lib backend.lib bluegl.lib bluevk.lib filabridge.lib filaflat.lib \
utils.lib geometry.lib smol-v.lib ibl.lib vkshaders.lib
utils.lib geometry.lib smol-v.lib ibl.lib vkshaders.lib abseil.lib
CC=cl.exe
main.exe: main.obj
+47 -5
View File
@@ -180,8 +180,11 @@ if (FILAMENT_SUPPORTS_VULKAN)
src/vulkan/VulkanAsyncHandles.h
src/vulkan/VulkanBlitter.cpp
src/vulkan/VulkanBlitter.h
src/vulkan/VulkanBuffer.cpp
src/vulkan/VulkanBuffer.h
src/vulkan/VulkanBufferCache.h
src/vulkan/VulkanBufferCache.cpp
src/vulkan/VulkanBufferProxy.h
src/vulkan/VulkanBufferProxy.cpp
src/vulkan/VulkanCommands.cpp
src/vulkan/VulkanCommands.h
src/vulkan/VulkanConstants.h
@@ -254,16 +257,42 @@ if (FILAMENT_SUPPORTS_WEBGPU)
list(APPEND SRCS
include/backend/platforms/WebGPUPlatform.h
src/webgpu/platform/WebGPUPlatform.cpp
src/webgpu/SpdMipmapGenerator/SpdMipmapGenerator.cpp
src/webgpu/WebGPUBufferBase.cpp
src/webgpu/WebGPUBufferBase.h
src/webgpu/WebGPUBufferObject.cpp
src/webgpu/WebGPUBufferObject.h
src/webgpu/WebGPUConstants.h
src/webgpu/WebGPUDescriptorSet.cpp
src/webgpu/WebGPUDescriptorSet.h
src/webgpu/WebGPUDescriptorSetLayout.cpp
src/webgpu/WebGPUDescriptorSetLayout.h
src/webgpu/WebGPUDriver.cpp
src/webgpu/WebGPUDriver.h
src/webgpu/WebGPUHandles.cpp
src/webgpu/WebGPUHandles.h
src/webgpu/WebGPUFence.cpp
src/webgpu/WebGPUFence.h
src/webgpu/WebGPUIndexBuffer.cpp
src/webgpu/WebGPUIndexBuffer.h
src/webgpu/WebGPUMsaaTextureResolver.cpp
src/webgpu/WebGPUMsaaTextureResolver.h
src/webgpu/WebGPUPipelineCreation.cpp
src/webgpu/WebGPUPipelineCreation.h
src/webgpu/WebGPUProgram.cpp
src/webgpu/WebGPUProgram.h
src/webgpu/WebGPURenderPassMipmapGenerator.cpp
src/webgpu/WebGPURenderPassMipmapGenerator.h
src/webgpu/WebGPURenderPrimitive.h
src/webgpu/WebGPURenderTarget.cpp
src/webgpu/WebGPURenderTarget.h
src/webgpu/WebGPUStrings.h
src/webgpu/WebGPUSwapChain.cpp
src/webgpu/WebGPUSwapChain.h
src/webgpu/WGPUProgram.cpp
src/webgpu/WebGPUTexture.cpp
src/webgpu/WebGPUTexture.h
src/webgpu/WebGPUVertexBuffer.cpp
src/webgpu/WebGPUVertexBuffer.h
src/webgpu/WebGPUVertexBufferInfo.cpp
src/webgpu/WebGPUVertexBufferInfo.h
)
if (WIN32)
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformWindows.cpp)
@@ -381,6 +410,10 @@ endif()
target_link_libraries(${TARGET} PUBLIC math)
target_link_libraries(${TARGET} PUBLIC utils)
if (FILAMENT_USE_ABSEIL_LOGGING)
target_link_libraries(${TARGET} PRIVATE absl::log)
endif()
# Android, iOS, and WebGL do not use bluegl.
if(FILAMENT_SUPPORTS_OPENGL AND NOT IOS AND NOT ANDROID AND NOT WEBGL)
target_link_libraries(${TARGET} PRIVATE bluegl)
@@ -476,11 +509,20 @@ if (FILAMENT_SUPPORTS_WEBGPU)
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>)
endif()
# ==================================================================================================
# Linker flags
# ==================================================================================================
target_link_libraries(${TARGET} PRIVATE
${OSMESA_LINKER_FLAGS}
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
)
if (LINUX AND FILAMENT_SUPPORTS_WEBGPU)
# Unclear why this needs to be explicit while other linux libs do not, but it is necessary for
# WebGPU to build on linux.
target_link_libraries(${TARGET} PRIVATE -lxcb)
endif()
# ==================================================================================================
# Installation
# ==================================================================================================
+6 -112
View File
@@ -474,7 +474,12 @@ constexpr std::string_view to_string(DescriptorType type) noexcept {
enum class DescriptorFlags : uint8_t {
NONE = 0x00,
DYNAMIC_OFFSET = 0x01
// Indicate a UNIFORM_BUFFER will have dynamic offsets.
DYNAMIC_OFFSET = 0x01,
// To indicate a texture/sampler type should be unfiltered.
UNFILTERABLE = 0x02,
};
using descriptor_set_t = uint8_t;
@@ -495,18 +500,12 @@ struct DescriptorSetLayoutBinding {
DescriptorFlags flags = DescriptorFlags::NONE;
uint16_t count = 0;
// TODO: uncomment when needed. Note that this class is used as hash key. We need to ensure
// no uninitialized padding bytes.
// uint8_t externalSamplerDataIndex = EXTERNAL_SAMPLER_DATA_INDEX_UNUSED;
friend bool operator==(DescriptorSetLayoutBinding const& lhs,
DescriptorSetLayoutBinding const& rhs) noexcept {
return lhs.type == rhs.type &&
lhs.flags == rhs.flags &&
lhs.count == rhs.count &&
lhs.stageFlags == rhs.stageFlags;
// lhs.stageFlags == rhs.stageFlags &&
// lhs.externalSamplerDataIndex == rhs.externalSamplerDataIndex;
}
};
@@ -1254,26 +1253,6 @@ enum class SamplerCompareFunc : uint8_t {
N //!< Never. The depth / stencil test always fails.
};
//! this API is copied from (and only applies to) the Vulkan spec.
//! These specify YUV to RGB conversions.
enum class SamplerYcbcrModelConversion : uint8_t {
RGB_IDENTITY = 0,
YCBCR_IDENTITY = 1,
YCBCR_709 = 2,
YCBCR_601 = 3,
YCBCR_2020 = 4,
};
enum class SamplerYcbcrRange : uint8_t {
ITU_FULL = 0,
ITU_NARROW = 1,
};
enum class ChromaLocation : uint8_t {
COSITED_EVEN = 0,
MIDPOINT = 1,
};
//! Sampler parameters
struct SamplerParams { // NOLINT
SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST)
@@ -1342,94 +1321,9 @@ static_assert(sizeof(SamplerParams) == 4);
static_assert(sizeof(SamplerParams) <= sizeof(uint64_t),
"SamplerParams must be no more than 64 bits");
//! Sampler parameters
struct SamplerYcbcrConversion {// NOLINT
SamplerYcbcrModelConversion ycbcrModel : 4;
TextureSwizzle r : 4;
TextureSwizzle g : 4;
TextureSwizzle b : 4;
TextureSwizzle a : 4;
SamplerYcbcrRange ycbcrRange : 1;
ChromaLocation xChromaOffset : 1;
ChromaLocation yChromaOffset : 1;
SamplerMagFilter chromaFilter : 1;
uint8_t padding;
struct Hasher {
size_t operator()(const SamplerYcbcrConversion p) const noexcept {
// we don't use std::hash<> here, so we don't have to include <functional>
return *reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&p));
}
};
struct EqualTo {
bool operator()(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) const noexcept {
assert_invariant(lhs.padding == 0);
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
return *pLhs == *pRhs;
}
};
struct LessThan {
bool operator()(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) const noexcept {
assert_invariant(lhs.padding == 0);
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
return *pLhs < *pRhs;
}
};
private:
friend bool operator == (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
noexcept {
return SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
}
friend bool operator != (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
noexcept {
return !SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
}
friend bool operator < (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
noexcept {
return SamplerYcbcrConversion::LessThan{}(lhs, rhs);
}
};
static_assert(sizeof(SamplerYcbcrConversion) == 4);
static_assert(sizeof(SamplerYcbcrConversion) <= sizeof(uint64_t),
"SamplerYcbcrConversion must be no more than 64 bits");
struct ExternalSamplerDatum {
ExternalSamplerDatum(SamplerYcbcrConversion ycbcr, SamplerParams spm, uint32_t extFmt)
: YcbcrConversion(ycbcr),
samplerParams(spm),
externalFormat(extFmt) {}
bool operator==(ExternalSamplerDatum const& rhs) const {
return (YcbcrConversion == rhs.YcbcrConversion && samplerParams == rhs.samplerParams &&
externalFormat == rhs.externalFormat);
}
struct EqualTo {
bool operator()(const ExternalSamplerDatum& lhs,
const ExternalSamplerDatum& rhs) const noexcept {
return (lhs.YcbcrConversion == rhs.YcbcrConversion &&
lhs.samplerParams == rhs.samplerParams &&
lhs.externalFormat == rhs.externalFormat);
}
};
SamplerYcbcrConversion YcbcrConversion;
SamplerParams samplerParams;
uint32_t externalFormat;
};
// No implicit padding allowed due to it being a hash key.
static_assert(sizeof(ExternalSamplerDatum) == 12);
struct DescriptorSetLayout {
std::variant<utils::StaticString, utils::CString, std::monostate> label;
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
// TODO: uncomment when needed
// utils::FixedCapacityVector<ExternalSamplerDatum> externalSamplerData;
};
//! blending equation function
@@ -204,23 +204,15 @@ public:
}, new T(std::forward<T>(functor))
};
}
// --------------------------------------------------------------------------------------------
/**
* Computes the size in bytes needed to fit an image of given dimensions and format
* Computes the size in bytes for a pixel of given dimensions and format
*
* @param format Format of the image pixels
* @param type Type of the image pixels
* @param stride Stride of a row in pixels
* @param height Height of the image in rows
* @param alignment Alignment in bytes of pixel rows
* @return The buffer size needed to fit this image in bytes
* @return The size of the specified pixel in bytes
*/
static constexpr size_t computeDataSize(PixelDataFormat format, PixelDataType type,
size_t stride, size_t height, size_t alignment) noexcept {
assert_invariant(alignment);
static constexpr size_t computePixelSize(PixelDataFormat format, PixelDataType type) noexcept {
if (type == PixelDataType::COMPRESSED) {
return 0;
}
@@ -242,7 +234,7 @@ public:
case PixelDataFormat::RGB_INTEGER:
n = 3;
break;
case PixelDataFormat::UNUSED: // shouldn't happen (used to be rgbm)
case PixelDataFormat::UNUSED:// shouldn't happen (used to be rgbm)
case PixelDataFormat::RGBA:
case PixelDataFormat::RGBA_INTEGER:
n = 4;
@@ -251,7 +243,7 @@ public:
size_t bpp = n;
switch (type) {
case PixelDataType::COMPRESSED: // Impossible -- to squash the IDE warnings
case PixelDataType::COMPRESSED:// Impossible -- to squash the IDE warnings
case PixelDataType::UBYTE:
case PixelDataType::BYTE:
// nothing to do
@@ -282,16 +274,35 @@ public:
bpp = 2;
break;
}
return bpp;
}
// --------------------------------------------------------------------------------------------
/**
* Computes the size in bytes needed to fit an image of given dimensions and format
*
* @param format Format of the image pixels
* @param type Type of the image pixels
* @param stride Stride of a row in pixels
* @param height Height of the image in rows
* @param alignment Alignment in bytes of pixel rows
* @return The buffer size needed to fit this image in bytes
*/
static constexpr size_t computeDataSize(PixelDataFormat format, PixelDataType type,
size_t stride, size_t height, size_t alignment) noexcept {
assert_invariant(alignment);
size_t bpp = computePixelSize(format, type);
size_t const bpr = bpp * stride;
size_t const bprAligned = (bpr + (alignment - 1)) & (~alignment + 1);
return bprAligned * height;
}
//! left coordinate in pixels
uint32_t left = 0;
uint32_t left = 0;
//! top coordinate in pixels
uint32_t top = 0;
uint32_t top = 0;
union {
struct {
//! stride in pixels
@@ -107,6 +107,36 @@ public:
MULTIVIEW,
};
/**
* This controls the priority level for GPU work scheduling, which helps prioritize the
* submitted GPU work and enables preemption.
*/
enum class GpuContextPriority : uint8_t {
/**
* Backend default GPU context priority (typically MEDIUM)
*/
DEFAULT,
/**
* For non-interactive, deferrable workloads. This should not interfere with standard
* applications.
*/
LOW,
/**
* The default priority level for standard applications.
*/
MEDIUM,
/**
* For high-priority, latency-sensitive workloads that are more important than standard
* applications.
*/
HIGH,
/**
* The highest priority, intended for system-critical, real-time applications where missing
* deadlines is unacceptable (e.g., VR/AR compositors or other system-critical tasks).
*/
REALTIME,
};
struct DriverConfig {
/**
* Size of handle arena in bytes. Setting to 0 indicates default value is to be used.
@@ -156,6 +186,13 @@ public:
* - PlatformMetal
*/
bool metalDisablePanicOnDrawableFailure = false;
/**
* GPU context priority level. Controls GPU work scheduling and preemption.
* This is only supported for:
* - PlatformEGL
*/
GpuContextPriority gpuContextPriority = GpuContextPriority::DEFAULT;
};
Platform() noexcept;
@@ -199,7 +199,7 @@ public:
*/
virtual bool makeCurrent(ContextType type,
SwapChain* UTILS_NONNULL drawSwapChain,
SwapChain* UTILS_NONNULL readSwapChain) noexcept = 0;
SwapChain* UTILS_NONNULL readSwapChain) = 0;
/**
* Called by the driver to make the OpenGL context active on the calling thread and bind
@@ -219,7 +219,7 @@ public:
SwapChain* UTILS_NONNULL drawSwapChain,
SwapChain* UTILS_NONNULL readSwapChain,
utils::Invocable<void()> preContextChange,
utils::Invocable<void(size_t index)> postContextChange) noexcept;
utils::Invocable<void(size_t index)> postContextChange);
/**
* Called by the backend just before calling commit()
@@ -58,7 +58,7 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) override;
void commit(SwapChain* swapChain) noexcept override;
ExternalTexture* createExternalImageTexture() noexcept override;
void destroyExternalImageTexture(ExternalTexture* texture) noexcept override;
@@ -55,7 +55,7 @@ public:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) override;
void commit(SwapChain* swapChain) noexcept override;
ExternalTexture* createExternalImageTexture() noexcept override;
@@ -109,11 +109,11 @@ protected:
bool makeCurrent(ContextType type,
SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept override;
SwapChain* readSwapChain) override;
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain,
utils::Invocable<void()> preContextChange,
utils::Invocable<void(size_t index)> postContextChange) noexcept override;
utils::Invocable<void(size_t index)> postContextChange) override;
void commit(SwapChain* swapChain) noexcept override;
@@ -128,7 +128,7 @@ protected:
bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override;
/**
* Logs glGetError() to slog.e
* Logs glGetError() to LOG(ERROR)
* @param name a string giving some context on the error. Typically __func__.
*/
static void logEglError(const char* name) noexcept;
@@ -148,12 +148,12 @@ protected:
EGLContext getContextForType(ContextType type) const noexcept;
// makes the draw and read surface current without changing the current context
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept {
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) {
return egl.makeCurrent(drawSurface, readSurface);
}
// makes context current and set draw and read surfaces to EGL_NO_SURFACE
EGLBoolean makeCurrent(EGLContext context) noexcept {
EGLBoolean makeCurrent(EGLContext context) {
return egl.makeCurrent(context, mEGLDummySurface, mEGLDummySurface);
}
@@ -211,9 +211,9 @@ private:
public:
explicit EGL(EGLDisplay& dpy) : mEGLDisplay(dpy) {}
EGLBoolean makeCurrent(EGLContext context,
EGLSurface drawSurface, EGLSurface readSurface) noexcept;
EGLSurface drawSurface, EGLSurface readSurface);
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept {
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) {
return makeCurrent(mCurrentContext, drawSurface, readSurface);
}
} egl{ mEGLDisplay };
@@ -127,7 +127,7 @@ protected:
protected:
bool makeCurrent(ContextType type,
SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept override;
SwapChain* readSwapChain) override;
private:
struct InitializeJvmForPerformanceManagerIfNeeded {
@@ -51,7 +51,7 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) override;
void commit(SwapChain* swapChain) noexcept override;
private:
@@ -56,7 +56,7 @@ protected:
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept override;
SwapChain* readSwapChain) override;
void commit(SwapChain* swapChain) noexcept override;
private:
@@ -53,7 +53,7 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) override;
void commit(SwapChain* swapChain) noexcept override;
protected:
@@ -46,7 +46,7 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) override;
void commit(SwapChain* swapChain) noexcept override;
};
@@ -22,6 +22,7 @@
#include <webgpu/webgpu_cpp.h>
#include <cstdint>
#include <vector>
namespace filament::backend {
@@ -56,6 +57,10 @@ protected:
const Platform::DriverConfig& driverConfig) noexcept override;
private:
// returns adapter request option variations applicable for the particular
// platform
[[nodiscard]] static std::vector<wgpu::RequestAdapterOptions> getAdapterOptions();
// we may consider having the driver own this in the future
wgpu::Instance mInstance;
};
@@ -72,7 +72,7 @@ public:
Range getBuffer() noexcept;
private:
void* alloc(size_t size) noexcept;
void* alloc(size_t size);
void dealloc() noexcept;
// pointer to the beginning of the circular buffer (constant)
@@ -76,7 +76,7 @@ public:
// all commands buffers (Slices) written to this point are returned by waitForCommand(). This
// call blocks until the CircularBuffer has at least mRequiredSize bytes available.
void flush() noexcept;
void flush();
// returns from waitForCommands() immediately.
void requestExit();
@@ -39,7 +39,7 @@
#define FILAMENT_DEBUG_COMMANDS_NONE 0x0
// Command debugging enabled. No logging by default.
#define FILAMENT_DEBUG_COMMANDS_ENABLE 0x1
// Command debugging enabled. Every command logged to slog.d
// Command debugging enabled. Every command logged to DLOG(INFO)
#define FILAMENT_DEBUG_COMMANDS_LOG 0x2
// Command debugging enabled. Every command logged to systrace
#define FILAMENT_DEBUG_COMMANDS_SYSTRACE 0x4
@@ -0,0 +1,764 @@
/** @file DriverAPI.dox
* @brief External documentation for the backend::Driver API.
*
* This file contains Doxygen documentation for the functions declared in DriverAPI.inc.
* This is used to keep the documentation separate from the macro-heavy header file.
*/
// General lifecycle and frame management
/** @fn Driver::tick()
* @brief Called periodically by the system to perform maintenance tasks.
*/
/** @fn Driver::beginFrame(int64_t monotonic_clock_ns, int64_t refreshIntervalNs, uint32_t frameId)
* @brief Signals the beginning of a new frame to the driver.
* @param monotonic_clock_ns The current monotonic clock time in nanoseconds.
* @param refreshIntervalNs The display's refresh interval in nanoseconds.
* @param frameId A unique identifier for the new frame.
*/
/** @fn Driver::setFrameScheduledCallback(backend::SwapChainHandle sch, backend::CallbackHandler* handler, backend::FrameScheduledCallback&& callback, uint64_t flags)
* @brief Schedules a callback to be executed when the frame associated with the given swap chain has been scheduled for presentation.
* @param sch The handle of the swap chain.
* @param handler The callback handler that will execute the callback.
* @param callback The function to be called.
* @param flags Flags to control the callback behavior.
*/
/** @fn Driver::setFrameCompletedCallback(backend::SwapChainHandle sch, backend::CallbackHandler* handler, utils::Invocable<void(void)>&& callback)
* @brief Sets a callback to be executed when rendering to the given swap chain is complete for the current frame.
* @param sch The handle of the swap chain.
* @param handler The callback handler that will execute the callback.
* @param callback The function to be called upon frame completion.
*/
/** @fn Driver::setPresentationTime(int64_t monotonic_clock_ns)
* @brief Informs the driver of the intended presentation time for the current frame.
* @param monotonic_clock_ns The desired presentation time in nanoseconds, based on the monotonic clock.
*/
/** @fn Driver::endFrame(uint32_t frameId)
* @brief Signals the end of a frame to the driver.
* @param frameId The unique identifier of the frame that is ending.
*/
/** @fn Driver::flush()
* @brief Submits all pending commands to the GPU for execution, without waiting for them to complete.
*/
/** @fn Driver::finish()
* @brief Submits all pending commands and waits for the GPU to finish executing them.
*/
/** @fn Driver::resetState()
* @brief Resets any cached or tracked driver state, forcing the driver to re-evaluate and set all states.
*/
/** @fn Driver::setDebugTag(backend::HandleBase::HandleId handleId, utils::CString tag)
* @brief Associates a user-provided string tag with a driver handle for debugging purposes.
* @param handleId The ID of the handle to tag.
* @param tag The debug string to associate with the handle.
*/
// Resource creation
/** @fn backend::VertexBufferInfoHandle Driver::createVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount, backend::AttributeArray attributes)
* @brief Creates a VertexBufferInfo object which describes the layout of a vertex buffer.
* @param bufferCount The number of buffer objects in the vertex buffer.
* @param attributeCount The number of attributes in the vertex buffer.
* @param attributes An array describing each vertex attribute.
* @return A handle to the new VertexBufferInfo object.
*/
/** @fn backend::VertexBufferHandle Driver::createVertexBuffer(uint32_t vertexCount, backend::VertexBufferInfoHandle vbih)
* @brief Creates a vertex buffer with a specified vertex count and layout.
* @param vertexCount The number of vertices in the buffer.
* @param vbih A handle to a VertexBufferInfo object describing the vertex layout.
* @return A handle to the new vertex buffer.
*/
/** @fn backend::IndexBufferHandle Driver::createIndexBuffer(backend::ElementType elementType, uint32_t indexCount, backend::BufferUsage usage)
* @brief Creates an index buffer for indexed drawing.
* @param elementType The data type of an index (e.g., USHORT, UINT).
* @param indexCount The number of indices in the buffer.
* @param usage The expected usage pattern of the buffer (e.g., STATIC, DYNAMIC).
* @return A handle to the new index buffer.
*/
/** @fn backend::BufferObjectHandle Driver::createBufferObject(uint32_t byteCount, backend::BufferObjectBinding bindingType, backend::BufferUsage usage)
* @brief Creates a generic buffer object for storing arbitrary data on the GPU.
* @param byteCount The size of the buffer in bytes.
* @param bindingType The purpose of the buffer object (e.g., VERTEX, UNIFORM).
* @param usage The expected usage pattern of the buffer.
* @return A handle to the new buffer object.
*/
/** @fn backend::TextureHandle Driver::createTexture(backend::SamplerType target, uint8_t levels, backend::TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, backend::TextureUsage usage)
* @brief Creates a new texture object.
* @param target The type of the texture (e.g. 2D, 3D, CUBEMAP).
* @param levels The number of mipmap levels.
* @param format The internal format of the texture's pixels.
* @param samples The number of samples for multisampling (1 for non-MSAA).
* @param width The width of the texture in texels.
* @param height The height of the texture in texels.
* @param depth The depth of the texture in texels (for 3D or array textures).
* @param usage A bitmask specifying the intended usage of the texture.
* @return A handle to the new texture.
*/
/** @fn backend::TextureHandle Driver::createTextureView(backend::TextureHandle texture, uint8_t baseLevel, uint8_t levelCount)
* @brief Creates a new texture view from an existing texture, allowing access to a subset of its mipmap levels.
* @param texture The handle of the original texture.
* @param baseLevel The first mipmap level to include in the view.
* @param levelCount The number of mipmap levels to include in the view.
* @return A handle to the new texture view.
*/
/** @fn backend::TextureHandle Driver::createTextureViewSwizzle(backend::TextureHandle texture, backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b, backend::TextureSwizzle a)
* @brief Creates a new texture view with remapped color channels (swizzling).
* @param texture The handle of the original texture.
* @param r The swizzle operation for the red channel.
* @param g The swizzle operation for the green channel.
* @param b The swizzle operation for the blue channel.
* @param a The swizzle operation for the alpha channel.
* @return A handle to the new texture view.
*/
/** @fn backend::TextureHandle Driver::createTextureExternalImage2(backend::SamplerType target, backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, backend::Platform::ExternalImageHandleRef image)
* @brief Creates a texture from a platform-specific external image handle.
* @param target The type of the texture.
* @param format The format of the texture's pixels.
* @param width The width of the texture.
* @param height The height of the texture.
* @param usage The expected usage of the texture.
* @param image A reference to the platform-specific external image.
* @return A handle to the new texture.
*/
/** @fn backend::TextureHandle Driver::createTextureExternalImage(backend::SamplerType target, backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, void* image)
* @brief Creates a texture from a platform-specific external image pointer.
* @param target The type of the texture.
* @param format The format of the texture's pixels.
* @param width The width of the texture.
* @param height The height of the texture.
* @param usage The expected usage of the texture.
* @param image A pointer to the external image data.
* @return A handle to the new texture.
*/
/** @fn backend::TextureHandle Driver::createTextureExternalImagePlane(backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, void* image, uint32_t plane)
* @brief Creates a texture from a single plane of a multi-planar external image.
* @param format The format of the texture's pixels.
* @param width The width of the texture.
* @param height The height of the texture.
* @param usage The expected usage of the texture.
* @param image A pointer to the external image data.
* @param plane The index of the plane to create the texture from.
* @return A handle to the new texture.
*/
/** @fn backend::TextureHandle Driver::importTexture(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)
* @brief Imports an existing backend-native texture into Filament.
* @param id The backend-specific texture ID or handle.
* @param target The type of the texture.
* @param levels The number of mipmap levels.
* @param format The format of the texture's pixels.
* @param samples The number of samples for multisampling.
* @param width The width of the texture.
* @param height The height of the texture.
* @param depth The depth of the texture.
* @param usage The expected usage of the texture.
* @return A handle to the imported texture.
*/
/** @fn backend::RenderPrimitiveHandle Driver::createRenderPrimitive(backend::VertexBufferHandle vbh, backend::IndexBufferHandle ibh, backend::PrimitiveType pt)
* @brief Creates a render primitive, which represents a piece of geometry to be rendered.
* @param vbh A handle to a vertex buffer.
* @param ibh A handle to an index buffer.
* @param pt The type of primitive to render (e.g., TRIANGLES, LINES).
* @return A handle to the new render primitive.
*/
/** @fn backend::ProgramHandle Driver::createProgram(backend::Program&& program)
* @brief Creates a shader program from a backend-specific program object.
* @param program A Program object containing the shader code and metadata.
* @return A handle to the new program.
*/
/** @fn backend::RenderTargetHandle Driver::createDefaultRenderTarget()
* @brief Creates a render target that represents the default framebuffer (e.g., the screen).
* @return A handle to the default render target.
*/
/** @fn backend::RenderTargetHandle Driver::createRenderTarget(backend::TargetBufferFlags targetBufferFlags, uint32_t width, uint32_t height, uint8_t samples, uint8_t layerCount, backend::MRT color, backend::TargetBufferInfo depth, backend::TargetBufferInfo stencil)
* @brief Creates an offscreen render target.
* @param targetBufferFlags A bitmask specifying which buffers (color, depth, stencil) are included.
* @param width The width of the render target in pixels.
* @param height The height of the render target in pixels.
* @param samples The number of samples for multisampling.
* @param layerCount The number of layers for layered rendering.
* @param color An array of color attachments.
* @param depth The depth attachment.
* @param stencil The stencil attachment.
* @return A handle to the new render target.
*/
/** @fn backend::FenceHandle Driver::createFence()
* @brief Creates a fence for synchronization between the CPU and GPU.
* @return A handle to the new fence.
*/
/** @fn backend::SwapChainHandle Driver::createSwapChain(void* nativeWindow, uint64_t flags)
* @brief Creates a swap chain for a native window, used for presenting rendered frames.
* @param nativeWindow A platform-specific pointer to the native window.
* @param flags Configuration flags for the swap chain.
* @return A handle to the new swap chain.
*/
/** @fn backend::SwapChainHandle Driver::createSwapChainHeadless(uint32_t width, uint32_t height, uint64_t flags)
* @brief Creates a headless swap chain for offscreen rendering without a native window.
* @param width The width of the swap chain.
* @param height The height of the swap chain.
* @param flags Configuration flags for the swap chain.
* @return A handle to the new swap chain.
*/
/** @fn backend::TimerQueryHandle Driver::createTimerQuery()
* @brief Creates a timer query object for measuring GPU execution time.
* @return A handle to the new timer query.
*/
/** @fn backend::DescriptorSetLayoutHandle Driver::createDescriptorSetLayout(backend::DescriptorSetLayout&& info)
* @brief Creates a descriptor set layout, which defines the layout of bindings in a descriptor set.
* @param info The layout information for the descriptor set.
* @return A handle to the new descriptor set layout.
*/
/** @fn backend::DescriptorSetHandle Driver::createDescriptorSet(backend::DescriptorSetLayoutHandle dslh)
* @brief Creates a descriptor set based on a given layout.
* @param dslh A handle to the descriptor set layout.
* @return A handle to the new descriptor set.
*/
/** @fn Driver::updateDescriptorSetBuffer(backend::DescriptorSetHandle dsh, backend::descriptor_binding_t binding, backend::BufferObjectHandle boh, uint32_t offset, uint32_t size)
* @brief Updates a buffer descriptor within a descriptor set.
* @param dsh The descriptor set to update.
* @param binding The binding point of the descriptor.
* @param boh The handle of the buffer object to bind.
* @param offset The offset into the buffer.
* @param size The size of the buffer region to bind.
*/
/** @fn Driver::updateDescriptorSetTexture(backend::DescriptorSetHandle dsh, backend::descriptor_binding_t binding, backend::TextureHandle th, SamplerParams params)
* @brief Updates a texture descriptor within a descriptor set.
* @param dsh The descriptor set to update.
* @param binding The binding point of the descriptor.
* @param th The handle of the texture to bind.
* @param params The sampler parameters for the texture.
*/
/** @fn Driver::bindDescriptorSet(backend::DescriptorSetHandle dsh, backend::descriptor_set_t set, backend::DescriptorSetOffsetArray&& offsets)
* @brief Binds a descriptor set to the current pipeline.
* @param dsh The descriptor set to bind.
* @param set The index of the descriptor set to bind.
* @param offsets An array of dynamic offsets for the descriptor set.
*/
// Resource destruction
/** @fn Driver::destroyVertexBuffer(backend::VertexBufferHandle vbh)
* @brief Destroys a vertex buffer and releases its resources.
* @param vbh The handle of the vertex buffer to destroy.
*/
/** @fn Driver::destroyVertexBufferInfo(backend::VertexBufferInfoHandle vbih)
* @brief Destroys a VertexBufferInfo object.
* @param vbih The handle of the VertexBufferInfo object to destroy.
*/
/** @fn Driver::destroyIndexBuffer(backend::IndexBufferHandle ibh)
* @brief Destroys an index buffer and releases its resources.
* @param ibh The handle of the index buffer to destroy.
*/
/** @fn Driver::destroyBufferObject(backend::BufferObjectHandle boh)
* @brief Destroys a buffer object and releases its resources.
* @param boh The handle of the buffer object to destroy.
*/
/** @fn Driver::destroyRenderPrimitive(backend::RenderPrimitiveHandle rph)
* @brief Destroys a render primitive.
* @param rph The handle of the render primitive to destroy.
*/
/** @fn Driver::destroyProgram(backend::ProgramHandle ph)
* @brief Destroys a shader program.
* @param ph The handle of the program to destroy.
*/
/** @fn Driver::destroyTexture(backend::TextureHandle th)
* @brief Destroys a texture and releases its resources.
* @param th The handle of the texture to destroy.
*/
/** @fn Driver::destroyRenderTarget(backend::RenderTargetHandle rth)
* @brief Destroys a render target.
* @param rth The handle of the render target to destroy.
*/
/** @fn Driver::destroySwapChain(backend::SwapChainHandle sch)
* @brief Destroys a swap chain.
* @param sch The handle of the swap chain to destroy.
*/
/** @fn Driver::destroyStream(backend::StreamHandle sh)
* @brief Destroys a stream.
* @param sh The handle of the stream to destroy.
*/
/** @fn Driver::destroyTimerQuery(backend::TimerQueryHandle tqh)
* @brief Destroys a timer query object.
* @param tqh The handle of the timer query to destroy.
*/
/** @fn Driver::destroyFence(backend::FenceHandle fh)
* @brief Destroys a fence.
* @param fh The handle of the fence to destroy.
*/
/** @fn Driver::destroyDescriptorSetLayout(backend::DescriptorSetLayoutHandle dslh)
* @brief Destroys a descriptor set layout.
* @param dslh The handle of the descriptor set layout to destroy.
*/
/** @fn Driver::destroyDescriptorSet(backend::DescriptorSetHandle dsh)
* @brief Destroys a descriptor set.
* @param dsh The handle of the descriptor set to destroy.
*/
// Synchronous APIs
/** @fn void Driver::terminate()
* @brief Terminates the driver and releases all associated resources. This is a synchronous operation.
*/
/** @fn backend::StreamHandle Driver::createStreamNative(void* stream)
* @brief Creates a stream from a native stream object (e.g., a SurfaceTexture on Android).
* @param stream A pointer to the native stream object.
* @return A handle to the new stream.
*/
/** @fn backend::StreamHandle Driver::createStreamAcquired()
* @brief Creates a stream that will be populated with images acquired via `setAcquiredImage`.
* @return A handle to the new stream.
*/
/** @fn void Driver::setAcquiredImage(backend::StreamHandle stream, void* image, const math::mat3f& transform, backend::CallbackHandler* handler, backend::StreamCallback cb, void* userData)
* @brief Provides an image to an acquired stream, with a callback for when the image is no longer in use.
* @param stream The handle of the stream.
* @param image A pointer to the image data.
* @param transform The transformation matrix for the image.
* @param handler The callback handler.
* @param cb The callback function to be invoked when the image is released.
* @param userData User data for the callback.
*/
/** @fn void Driver::setStreamDimensions(backend::StreamHandle stream, uint32_t width, uint32_t height)
* @brief Sets the dimensions of a stream, which may be necessary for certain stream types.
* @param stream The handle of the stream.
* @param width The new width of the stream.
* @param height The new height of the stream.
*/
/** @fn int64_t Driver::getStreamTimestamp(backend::StreamHandle stream)
* @brief Gets the timestamp of the last frame from a stream, if available.
* @param stream The handle of the stream.
* @return The timestamp in nanoseconds, or 0 if not available.
*/
/** @fn void Driver::updateStreams(backend::DriverApi* driver)
* @brief Updates all active streams, typically called once per frame.
* @param driver The driver API pointer.
*/
/** @fn backend::FenceStatus Driver::getFenceStatus(backend::FenceHandle fh)
* @brief Gets the current status of a fence.
* @param fh The handle of the fence.
* @return The status of the fence (e.g., SIGNALED, TIMEOUT_EXPIRED).
*/
/** @fn bool Driver::isTextureFormatSupported(backend::TextureFormat format)
* @brief Checks if a specific texture format is supported by the driver.
* @param format The texture format to check.
* @return True if the format is supported, false otherwise.
*/
/** @fn bool Driver::isTextureSwizzleSupported()
* @brief Checks if texture channel swizzling is supported by the driver.
* @return True if supported, false otherwise.
*/
/** @fn bool Driver::isTextureFormatMipmappable(backend::TextureFormat format)
* @brief Checks if a texture format can have mipmaps automatically generated.
* @param format The texture format to check.
* @return True if the format is mipmappable, false otherwise.
*/
/** @fn bool Driver::isRenderTargetFormatSupported(backend::TextureFormat format)
* @brief Checks if a texture format is supported for use as a render target attachment.
* @param format The texture format to check.
* @return True if the format is supported, false otherwise.
*/
/** @fn bool Driver::isFrameBufferFetchSupported()
* @brief Checks if framebuffer fetch (reading from the framebuffer in a shader) is supported.
* @return True if supported, false otherwise.
*/
/** @fn bool Driver::isFrameBufferFetchMultiSampleSupported()
* @brief Checks if multisampled framebuffer fetch is supported.
* @return True if supported, false otherwise.
*/
/** @fn bool Driver::isFrameTimeSupported()
* @brief Checks if frame time queries are supported for performance measurement.
* @return True if supported, false otherwise.
*/
/** @fn bool Driver::isAutoDepthResolveSupported()
* @brief Checks if automatic resolution of multisampled depth buffers is supported.
* @return True if supported, false otherwise.
*/
/** @fn bool Driver::isSRGBSwapChainSupported()
* @brief Checks if sRGB swap chains are supported for correct color space handling.
* @return True if supported, false otherwise.
*/
/** @fn bool Driver::isProtectedContentSupported()
* @brief Checks if rendering protected content (e.g., for DRM) is supported.
* @return True if supported, false otherwise.
*/
/** @fn bool Driver::isStereoSupported()
* @brief Checks if stereoscopic rendering is supported.
* @return True if supported, false otherwise.
*/
/** @fn bool Driver::isParallelShaderCompileSupported()
* @brief Checks if the driver can compile shaders in parallel for improved performance.
* @return True if supported, false otherwise.
*/
/** @fn bool Driver::isDepthStencilResolveSupported()
* @brief Checks if resolving multisampled depth/stencil buffers is supported.
* @return True if supported, false otherwise.
*/
/** @fn bool Driver::isDepthStencilBlitSupported(backend::TextureFormat format)
* @brief Checks if blitting (copying) depth/stencil data is supported for a given format.
* @param format The texture format.
* @return True if supported, false otherwise.
*/
/** @fn bool Driver::isProtectedTexturesSupported()
* @brief Checks if creating protected textures is supported.
* @return True if supported, false otherwise.
*/
/** @fn bool Driver::isDepthClampSupported()
* @brief Checks if depth clamping is supported by the hardware.
* @return True if supported, false otherwise.
*/
/** @fn uint8_t Driver::getMaxDrawBuffers()
* @brief Gets the maximum number of simultaneous draw buffers (Multiple Render Targets).
* @return The maximum number of draw buffers.
*/
/** @fn size_t Driver::getMaxUniformBufferSize()
* @brief Gets the maximum size of a uniform buffer in bytes.
* @return The maximum size in bytes.
*/
/** @fn size_t Driver::getMaxTextureSize(backend::SamplerType target)
* @brief Gets the maximum texture dimension (width, height, or depth) for a given target type.
* @param target The texture target type.
* @return The maximum size in texels.
*/
/** @fn size_t Driver::getMaxArrayTextureLayers()
* @brief Gets the maximum number of layers in an array texture.
* @return The maximum number of layers.
*/
/** @fn math::float2 Driver::getClipSpaceParams()
* @brief Gets the clip space parameters for the current backend.
* @return A float2 containing clip space parameters.
*/
/** @fn void Driver::setupExternalImage2(backend::Platform::ExternalImageHandleRef image)
* @brief Performs any necessary setup for an external image before it can be used.
* @param image A reference to the external image.
*/
/** @fn void Driver::setupExternalImage(void* image)
* @brief Performs any necessary setup for an external image before it can be used.
* @param image A pointer to the external image.
*/
/** @fn backend::TimerQueryResult Driver::getTimerQueryValue(backend::TimerQueryHandle query, uint64_t* elapsedTime)
* @brief Gets the result of a timer query, providing the elapsed GPU time.
* @param query The timer query handle.
* @param elapsedTime A pointer to store the elapsed time in nanoseconds.
* @return The result of the query (e.g., AVAILABLE, NOT_READY).
*/
/** @fn bool Driver::isWorkaroundNeeded(backend::Workaround workaround)
* @brief Checks if a specific driver or hardware workaround is needed.
* @param workaround The workaround to check.
* @return True if the workaround is needed, false otherwise.
*/
/** @fn backend::FeatureLevel Driver::getFeatureLevel()
* @brief Gets the feature level supported by the driver.
* @return The driver's feature level.
*/
// Resource updates
/** @fn Driver::setVertexBufferObject(backend::VertexBufferHandle vbh, uint32_t index, backend::BufferObjectHandle bufferObject)
* @brief Associates a buffer object with a specific buffer slot in a vertex buffer.
* @param vbh The handle of the vertex buffer.
* @param index The index of the buffer slot to set.
* @param bufferObject The handle of the buffer object to associate.
*/
/** @fn Driver::updateIndexBuffer(backend::IndexBufferHandle ibh, backend::BufferDescriptor&& data, uint32_t byteOffset)
* @brief Updates the data of an index buffer.
* @param ibh The handle of the index buffer.
* @param data The new data to upload.
* @param byteOffset The offset in bytes into the buffer to start writing to.
*/
/** @fn Driver::updateBufferObject(backend::BufferObjectHandle boh, backend::BufferDescriptor&& data, uint32_t byteOffset)
* @brief Updates the data of a buffer object.
* @param boh The handle of the buffer object.
* @param data The new data to upload.
* @param byteOffset The offset in bytes into the buffer to start writing to.
*/
/** @fn Driver::registerBufferObjectStreams(backend::BufferObjectHandle boh, backend::BufferObjectStreamDescriptor&& streams)
* @brief Registers external streams with a buffer object for efficient data transfer.
* @param boh The handle of the buffer object.
* @param streams The stream descriptors.
*/
/** @fn Driver::updateBufferObjectUnsynchronized(backend::BufferObjectHandle boh, backend::BufferDescriptor&& data, uint32_t byteOffset)
* @brief Updates a buffer object without synchronization, for use when manual synchronization is handled.
* @param boh The handle of the buffer object.
* @param data The new data to upload.
* @param byteOffset The offset in bytes into the buffer to start writing to.
*/
/** @fn Driver::resetBufferObject(backend::BufferObjectHandle boh)
* @brief Resets a buffer object, potentially discarding its contents.
* @param boh The handle of the buffer object.
*/
/** @fn Driver::update3DImage(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)
* @brief Updates a sub-region of a 3D texture.
* @param th The handle of the texture.
* @param level The mipmap level to update.
* @param xoffset The x offset of the sub-region.
* @param yoffset The y offset of the sub-region.
* @param zoffset The z offset of the sub-region.
* @param width The width of the sub-region.
* @param height The height of the sub-region.
* @param depth The depth of the sub-region.
* @param data The pixel data to upload.
*/
/** @fn Driver::generateMipmaps(backend::TextureHandle th)
* @brief Generates mipmaps for a texture automatically.
* @param th The handle of the texture.
*/
/** @fn Driver::setExternalStream(backend::TextureHandle th, backend::StreamHandle sh)
* @brief Associates an external stream with a texture for video or camera input.
* @param th The handle of the texture.
* @param sh The handle of the stream.
*/
// Render passes
/** @fn Driver::beginRenderPass(backend::RenderTargetHandle rth, const backend::RenderPassParams& params)
* @brief Begins a new render pass, targeting a specific render target.
* @param rth The handle of the render target.
* @param params The parameters for the render pass (e.g., clear values, load/store actions).
*/
/** @fn Driver::endRenderPass()
* @brief Ends the current render pass.
*/
/** @fn Driver::nextSubpass()
* @brief Moves to the next subpass within the current render pass.
*/
// Timer queries
/** @fn Driver::beginTimerQuery(backend::TimerQueryHandle query)
* @brief Begins a timer query to measure GPU time.
* @param query The handle of the timer query.
*/
/** @fn Driver::endTimerQuery(backend::TimerQueryHandle query)
* @brief Ends a timer query.
* @param query The handle of the timer query.
*/
/** @fn Driver::compilePrograms(backend::CompilerPriorityQueue priority, backend::CallbackHandler* handler, backend::CallbackHandler::Callback callback, void* user)
* @brief Compiles a queue of pending shader programs.
* @param priority The priority queue to use for compilation.
* @param handler The callback handler.
* @param callback The callback function to be invoked upon completion.
* @param user User data for the callback.
*/
// Swap chain
/** @fn Driver::makeCurrent(backend::SwapChainHandle schDraw, backend::SwapChainHandle schRead)
* @brief Makes a swap chain current for drawing and reading.
* @param schDraw The draw swap chain.
* @param schRead The read swap chain.
*/
/** @fn Driver::commit(backend::SwapChainHandle sch)
* @brief Commits the back buffer of a swap chain, making it visible.
* @param sch The handle of the swap chain.
*/
// Rendering state
/** @fn Driver::setPushConstant(backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant value)
* @brief Sets a push constant value for a specific shader stage.
* @param stage The shader stage to set the constant for.
* @param index The index of the push constant.
* @param value The value to set.
*/
/** @fn Driver::insertEventMarker(const char* string)
* @brief Inserts a debug event marker into the command stream.
* @param string The marker string.
*/
/** @fn Driver::pushGroupMarker(const char* string)
* @brief Pushes a debug group marker onto the command stream stack.
* @param string The marker string.
*/
/** @fn Driver::popGroupMarker()
* @brief Pops a debug group marker from the command stream stack.
*/
/** @fn Driver::startCapture()
* @brief Starts a graphics capture session.
*/
/** @fn Driver::stopCapture()
* @brief Stops a graphics capture session.
*/
// Read-back
/** @fn Driver::readPixels(backend::RenderTargetHandle src, uint32_t x, uint32_t y, uint32_t width, uint32_t height, backend::PixelBufferDescriptor&& data)
* @brief Reads a block of pixels from a render target into a client-side buffer.
* @param src The source render target.
* @param x The x coordinate of the region to read.
* @param y The y coordinate of the region to read.
* @param width The width of the region to read.
* @param height The height of the region to read.
* @param data The buffer to store the pixel data.
*/
/** @fn Driver::readBufferSubData(backend::BufferObjectHandle src, uint32_t offset, uint32_t size, backend::BufferDescriptor&& data)
* @brief Reads a sub-region of a buffer object into a client-side buffer.
* @param src The source buffer object.
* @param offset The offset to start reading from.
* @param size The number of bytes to read.
* @param data The buffer to store the data.
*/
// Rendering
/** @fn Driver::blitDEPRECATED(backend::TargetBufferFlags buffers, backend::RenderTargetHandle dst, backend::Viewport dstRect, backend::RenderTargetHandle src, backend::Viewport srcRect, backend::SamplerMagFilter filter)
* @brief Blits (copies) a region from one render target to another (deprecated).
* @param buffers The buffers to blit (e.g., color, depth).
* @param dst The destination render target.
* @param dstRect The destination rectangle.
* @param src The source render target.
* @param srcRect The source rectangle.
* @param filter The filter to use for scaling.
*/
/** @fn Driver::resolve(backend::TextureHandle dst, uint8_t dstLevel, uint8_t dstLayer, backend::TextureHandle src, uint8_t srcLevel, uint8_t srcLayer)
* @brief Resolves a multisampled texture into a non-multisampled texture.
* @param dst The destination texture.
* @param dstLevel The destination mipmap level.
* @param dstLayer The destination layer.
* @param src The source multisampled texture.
* @param srcLevel The source mipmap level.
* @param srcLayer The source layer.
*/
/** @fn Driver::blit(backend::TextureHandle dst, uint8_t dstLevel, uint8_t dstLayer, math::uint2 dstOrigin, backend::TextureHandle src, uint8_t srcLevel, uint8_t srcLayer, math::uint2 srcOrigin, math::uint2 size)
* @brief Blits (copies) a region from one texture to another.
* @param dst The destination texture.
* @param dstLevel The destination mipmap level.
* @param dstLayer The destination layer.
* @param dstOrigin The origin of the destination region.
* @param src The source texture.
* @param srcLevel The source mipmap level.
* @param srcLayer The source layer.
* @param srcOrigin The origin of the source region.
* @param size The size of the region to blit.
*/
/** @fn Driver::bindPipeline(const backend::PipelineState& state)
* @brief Binds a pipeline state object, including shaders and render states.
* @param state The pipeline state to bind.
*/
/** @fn Driver::bindRenderPrimitive(backend::RenderPrimitiveHandle rph)
* @brief Binds a render primitive for subsequent draw calls.
* @param rph The handle of the render primitive.
*/
/** @fn Driver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount)
* @brief Draws a render primitive using the currently bound pipeline and primitive.
* @param indexOffset The offset into the index buffer.
* @param indexCount The number of indices to draw.
* @param instanceCount The number of instances to draw.
*/
/** @fn Driver::draw(backend::PipelineState state, backend::RenderPrimitiveHandle rph, uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount)
* @brief A combined call to bind a pipeline, bind a primitive, and draw.
* @param state The pipeline state to bind.
* @param rph The render primitive to bind.
* @param indexOffset The offset into the index buffer.
* @param indexCount The number of indices to draw.
* @param instanceCount The number of instances to draw.
*/
/** @fn Driver::dispatchCompute(backend::ProgramHandle program, math::uint3 workGroupCount)
* @brief Dispatches a compute shader.
* @param program The handle of the compute program.
* @param workGroupCount The number of work groups to dispatch in each dimension.
*/
/** @fn Driver::scissor(Viewport scissor)
* @brief Sets the scissor rectangle for clipping.
* @param scissor The scissor rectangle.
*/
@@ -116,7 +116,7 @@ public:
* Destroys the object D at Handle<B> and construct a new D in its place
* e.g.:
* Handle<ConcreteTexture> h = allocateAndConstruct(w, h);
* ConcreteTexture* p = reconstruct(h, w, h);
* ConcreteTexture* p = destroyAndConstruct(h, w, h);
*/
template<typename D, typename B, typename ... ARGS>
std::enable_if_t<std::is_base_of_v<B, D>, D>*
@@ -27,13 +27,13 @@ namespace filament {
class VirtualMachineEnv {
public:
// must be called before VirtualMachineEnv::get() from a thread that is attached to the JavaVM
static jint JNI_OnLoad(JavaVM* vm) noexcept;
static jint JNI_OnLoad(JavaVM* vm);
// must be called on backend thread
static VirtualMachineEnv& get() noexcept;
// can be called from any thread that already has a JniEnv
static JNIEnv* getThreadEnvironment() noexcept;
static JNIEnv* getThreadEnvironment();
// must be called from the backend thread
JNIEnv* getEnvironment() noexcept {
@@ -49,7 +49,7 @@ public:
private:
explicit VirtualMachineEnv(JavaVM* vm) noexcept;
~VirtualMachineEnv() noexcept;
JNIEnv* getEnvironmentSlow() noexcept;
JNIEnv* getEnvironmentSlow();
static utils::Mutex sLock;
static JavaVM* sVirtualMachine;
+3 -3
View File
@@ -16,7 +16,7 @@
#include "private/backend/CircularBuffer.h"
#include <utils/Log.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/architecture.h>
#include <utils/ashmem.h>
@@ -65,7 +65,7 @@ CircularBuffer::~CircularBuffer() noexcept {
// to each others and a special case in circularize()
UTILS_NOINLINE
void* CircularBuffer::alloc(size_t size) noexcept {
void* CircularBuffer::alloc(size_t size) {
#if HAS_MMAP
void* data = nullptr;
void* vaddr = MAP_FAILED;
@@ -127,7 +127,7 @@ void* CircularBuffer::alloc(size_t size) noexcept {
"couldn't allocate " << (size * 2 / 1024) <<
" KiB of virtual address space for the command buffer";
slog.w << "Using 'soft' CircularBuffer (" << (size * 2 / 1024) << " KiB)" << io::endl;
LOG(WARNING) << "Using 'soft' CircularBuffer (" << (size * 2 / 1024) << " KiB)";
// guard page at the end
void* guard = (void*)(uintptr_t(data) + size * 2);
+16 -17
View File
@@ -20,12 +20,12 @@
#include <private/utils/Tracing.h>
#include <utils/compiler.h>
#include <utils/Log.h>
#include <utils/Logger.h>
#include <utils/Mutex.h>
#include <utils/ostream.h>
#include <utils/Panic.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/ostream.h>
#include <algorithm>
#include <mutex>
@@ -53,18 +53,18 @@ CommandBufferQueue::~CommandBufferQueue() {
}
void CommandBufferQueue::requestExit() {
std::lock_guard<utils::Mutex> const lock(mLock);
std::lock_guard const lock(mLock);
mExitRequested = EXIT_REQUESTED;
mCondition.notify_one();
}
bool CommandBufferQueue::isPaused() const noexcept {
std::lock_guard<utils::Mutex> const lock(mLock);
std::lock_guard const lock(mLock);
return mPaused;
}
void CommandBufferQueue::setPaused(bool paused) {
std::lock_guard<utils::Mutex> const lock(mLock);
std::lock_guard const lock(mLock);
if (paused) {
mPaused = true;
} else {
@@ -74,12 +74,12 @@ void CommandBufferQueue::setPaused(bool paused) {
}
bool CommandBufferQueue::isExitRequested() const {
std::lock_guard<utils::Mutex> const lock(mLock);
return (bool)mExitRequested;
std::lock_guard const lock(mLock);
return bool(mExitRequested);
}
void CommandBufferQueue::flush() noexcept {
void CommandBufferQueue::flush() {
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
CircularBuffer& circularBuffer = mCircularBuffer;
@@ -103,7 +103,7 @@ void CommandBufferQueue::flush() noexcept {
static_cast<char const*>(begin), static_cast<char const*>(end));
std::unique_lock<utils::Mutex> lock(mLock);
std::unique_lock lock(mLock);
// circular buffer is too small, we corrupted the stream
FILAMENT_CHECK_POSTCONDITION(used <= mFreeSpace) <<
@@ -121,11 +121,10 @@ void CommandBufferQueue::flush() noexcept {
#ifndef NDEBUG
size_t const totalUsed = circularBuffer.size() - mFreeSpace;
slog.d << "CommandStream used too much space (will block): "
<< "needed space " << requiredSize << " out of " << mFreeSpace
<< ", totalUsed=" << totalUsed << ", current=" << used
<< ", queue size=" << mCommandBuffersToExecute.size() << " buffers"
<< io::endl;
DLOG(INFO) << "CommandStream used too much space (will block): "
<< "needed space " << requiredSize << " out of " << mFreeSpace
<< ", totalUsed=" << totalUsed << ", current=" << used
<< ", queue size=" << mCommandBuffersToExecute.size() << " buffers";
mHighWatermark = std::max(mHighWatermark, totalUsed);
#endif
@@ -147,7 +146,7 @@ std::vector<CommandBufferQueue::Range> CommandBufferQueue::waitForCommands() con
if (!UTILS_HAS_THREADING) {
return std::move(mCommandBuffersToExecute);
}
std::unique_lock<utils::Mutex> lock(mLock);
std::unique_lock lock(mLock);
while ((mCommandBuffersToExecute.empty() || mPaused) && !mExitRequested) {
mCondition.wait(lock);
}
@@ -157,7 +156,7 @@ std::vector<CommandBufferQueue::Range> CommandBufferQueue::waitForCommands() con
void CommandBufferQueue::releaseBuffer(CommandBufferQueue::Range const& buffer) {
size_t const used = std::distance(
static_cast<char const*>(buffer.begin), static_cast<char const*>(buffer.end));
std::lock_guard<utils::Mutex> const lock(mLock);
std::lock_guard const lock(mLock);
mFreeSpace += used;
mCondition.notify_one();
}
+10 -6
View File
@@ -22,10 +22,13 @@
#include <utils/CallStack.h>
#endif
#include <utils/compiler.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <private/utils/Tracing.h>
#include <utils/Logger.h>
#include <utils/Profiler.h>
#include <utils/compiler.h>
#include <utils/ostream.h>
#include <utils/sstream.h>
#include <cstddef>
#include <functional>
@@ -129,9 +132,10 @@ void CommandType<void (Driver::*)(ARGS...)>::Command<METHOD>::log(std::index_seq
#if DEBUG_COMMAND_STREAM
static_assert(UTILS_HAS_RTTI, "DEBUG_COMMAND_STREAM can only be used with RTTI");
std::string command = utils::CallStack::demangleTypeName(typeid(Command).name()).c_str();
slog.d << extractMethodName(command) << " : size=" << sizeof(Command) << "\n\t";
printParameterPack(slog.d, std::get<I>(mArgs)...);
slog.d << io::endl;
DLOG(INFO) << extractMethodName(command) << " : size=" << sizeof(Command);
utils::io::sstream parameterPack;
printParameterPack(parameterPack, std::get<I>(mArgs)...);
DLOG(INFO) << "\t" << parameterPack.c_str();
#endif
}
+2 -2
View File
@@ -25,9 +25,9 @@
#include <private/utils/Tracing.h>
#include <utils/Logger.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <math/half.h>
@@ -149,7 +149,7 @@ void DriverBase::scheduleRelease(AcquiredImage const& image) noexcept {
void DriverBase::debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept {
if constexpr (bool(FILAMENT_DEBUG_COMMANDS > FILAMENT_DEBUG_COMMANDS_NONE)) {
if constexpr (bool(FILAMENT_DEBUG_COMMANDS & FILAMENT_DEBUG_COMMANDS_LOG)) {
utils::slog.d << methodName << utils::io::endl;
DLOG(INFO) << methodName;
}
if constexpr (bool(FILAMENT_DEBUG_COMMANDS & FILAMENT_DEBUG_COMMANDS_SYSTRACE)) {
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
+3 -3
View File
@@ -20,7 +20,7 @@
#include <utils/Allocator.h>
#include <utils/CString.h>
#include <utils/Log.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/compiler.h>
#include <utils/debug.h>
@@ -57,8 +57,8 @@ HandleAllocator<P0, P1, P2>::Allocator::Allocator(AreaPolicy::HeapArea const& ar
size_t const maxHeapSize = std::min(area.size(), HANDLE_INDEX_MASK * getAlignment());
if (UTILS_UNLIKELY(maxHeapSize != area.size())) {
slog.w << "HandleAllocator heap size reduced to "
<< maxHeapSize << " from " << area.size() << io::endl;
LOG(WARNING) << "HandleAllocator heap size reduced to " << maxHeapSize << " from "
<< area.size();
}
// make sure we start with a clean arena. This is needed to ensure that all blocks start
+3 -3
View File
@@ -50,7 +50,7 @@ JavaVM* VirtualMachineEnv::getVirtualMachine() {
*/
UTILS_PUBLIC
UTILS_NOINLINE
jint VirtualMachineEnv::JNI_OnLoad(JavaVM* vm) noexcept {
jint VirtualMachineEnv::JNI_OnLoad(JavaVM* vm) {
std::lock_guard const lock(sLock);
if (sVirtualMachine) {
// It doesn't make sense for JNI_OnLoad() to be called more than once
@@ -77,7 +77,7 @@ VirtualMachineEnv& VirtualMachineEnv::get() noexcept {
}
UTILS_NOINLINE
JNIEnv* VirtualMachineEnv::getThreadEnvironment() noexcept {
JNIEnv* VirtualMachineEnv::getThreadEnvironment() {
JavaVM* const vm = getVirtualMachine();
JNIEnv* env = nullptr;
jint const result = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
@@ -101,7 +101,7 @@ VirtualMachineEnv::~VirtualMachineEnv() noexcept {
}
UTILS_NOINLINE
JNIEnv* VirtualMachineEnv::getEnvironmentSlow() noexcept {
JNIEnv* VirtualMachineEnv::getEnvironmentSlow() {
FILAMENT_CHECK_PRECONDITION(mVirtualMachine)
<< "JNI_OnLoad() has not been called";
+3 -3
View File
@@ -19,8 +19,8 @@
#include "MetalContext.h"
#include "MetalUtils.h"
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/Log.h>
namespace filament::backend {
@@ -323,7 +323,7 @@ id<MTLFunction> MetalBlitter::compileFragmentFunction(BlitFunctionKey key) const
if (!library || !function) {
if (error) {
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
utils::slog.e << description << utils::io::endl;
LOG(ERROR) << description;
}
}
FILAMENT_CHECK_POSTCONDITION(library && function)
@@ -349,7 +349,7 @@ id<MTLFunction> MetalBlitter::getBlitVertexFunction() {
if (!library || !function) {
if (error) {
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
utils::slog.e << description << utils::io::endl;
LOG(ERROR) << description;
}
}
FILAMENT_CHECK_POSTCONDITION(library && function)
@@ -18,8 +18,8 @@
#include "MetalContext.h"
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/Log.h>
#include <utils/trap.h>
#include <thread>
@@ -77,8 +77,7 @@ void MetalBufferPool::releaseBuffer(MetalBufferPoolEntry const *stage) noexcept
auto iter = mUsedStages.find(stage);
if (iter == mUsedStages.end()) {
utils::slog.e << "Unknown Metal buffer: " << stage->capacity << " bytes"
<< utils::io::endl;
LOG(ERROR) << "Unknown Metal buffer: " << stage->capacity << " bytes";
return;
}
stage->lastAccessed = mCurrentFrame;
+4 -3
View File
@@ -18,8 +18,9 @@
#include "MetalHandles.h"
#include <utils/debug.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Logger.h>
#include <utils/debug.h>
#include <utility>
@@ -112,8 +113,8 @@ id<MTLCommandBuffer> getPendingCommandBuffer(MetalContext* context) {
auto errorCode = (MTLCommandBufferError)buffer.error.code;
if (@available(macOS 11.0, *)) {
if (errorCode == MTLCommandBufferErrorMemoryless) {
utils::slog.w << "Metal: memoryless geometry limit reached. "
"Continuing with private storage mode." << utils::io::endl;
LOG(WARNING) << "Metal: memoryless geometry limit reached. Continuing with private "
"storage mode.";
context->memorylessLimitsReached = true;
}
}
+22 -25
View File
@@ -38,10 +38,10 @@
#include <Metal/Metal.h>
#include <QuartzCore/QuartzCore.h>
#include <utils/Log.h>
#include <utils/Invocable.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/sstream.h>
#include <utils/Invocable.h>
#include <algorithm>
@@ -78,20 +78,18 @@ Driver* MetalDriverFactory::create(PlatformMetal* const platform, const Platform
// MetalVertexBufferInfo : 552 moderate
// -- less than or equal to 552 bytes
utils::slog.d
<< "\nMetalSwapChain: " << sizeof(MetalSwapChain)
<< "\nMetalBufferObject: " << sizeof(MetalBufferObject)
<< "\nMetalVertexBuffer: " << sizeof(MetalVertexBuffer)
<< "\nMetalVertexBufferInfo: " << sizeof(MetalVertexBufferInfo)
<< "\nMetalIndexBuffer: " << sizeof(MetalIndexBuffer)
<< "\nMetalRenderPrimitive: " << sizeof(MetalRenderPrimitive)
<< "\nMetalTexture: " << sizeof(MetalTexture)
<< "\nMetalTimerQuery: " << sizeof(MetalTimerQuery)
<< "\nHwStream: " << sizeof(HwStream)
<< "\nMetalRenderTarget: " << sizeof(MetalRenderTarget)
<< "\nMetalFence: " << sizeof(MetalFence)
<< "\nMetalProgram: " << sizeof(MetalProgram)
<< utils::io::endl;
DLOG(INFO) << "MetalSwapChain: " << sizeof(MetalSwapChain);
DLOG(INFO) << "MetalBufferObject: " << sizeof(MetalBufferObject);
DLOG(INFO) << "MetalVertexBuffer: " << sizeof(MetalVertexBuffer);
DLOG(INFO) << "MetalVertexBufferInfo: " << sizeof(MetalVertexBufferInfo);
DLOG(INFO) << "MetalIndexBuffer: " << sizeof(MetalIndexBuffer);
DLOG(INFO) << "MetalRenderPrimitive: " << sizeof(MetalRenderPrimitive);
DLOG(INFO) << "MetalTexture: " << sizeof(MetalTexture);
DLOG(INFO) << "MetalTimerQuery: " << sizeof(MetalTimerQuery);
DLOG(INFO) << "HwStream: " << sizeof(HwStream);
DLOG(INFO) << "MetalRenderTarget: " << sizeof(MetalRenderTarget);
DLOG(INFO) << "MetalFence: " << sizeof(MetalFence);
DLOG(INFO) << "MetalProgram: " << sizeof(MetalProgram);
#endif
return MetalDriver::create(platform, driverConfig);
}
@@ -135,19 +133,18 @@ MetalDriver::MetalDriver(
initializeSupportedGpuFamilies(mContext);
utils::slog.v << "Supported GPU families: " << utils::io::endl;
LOG(INFO) << "Supported GPU families: ";
if (mContext->highestSupportedGpuFamily.common > 0) {
utils::slog.v << " MTLGPUFamilyCommon" << (int) mContext->highestSupportedGpuFamily.common << utils::io::endl;
LOG(INFO) << " MTLGPUFamilyCommon" << (int) mContext->highestSupportedGpuFamily.common;
}
if (mContext->highestSupportedGpuFamily.apple > 0) {
utils::slog.v << " MTLGPUFamilyApple" << (int) mContext->highestSupportedGpuFamily.apple << utils::io::endl;
LOG(INFO) << " MTLGPUFamilyApple" << (int) mContext->highestSupportedGpuFamily.apple;
}
if (mContext->highestSupportedGpuFamily.mac > 0) {
utils::slog.v << " MTLGPUFamilyMac" << (int) mContext->highestSupportedGpuFamily.mac << utils::io::endl;
LOG(INFO) << " MTLGPUFamilyMac" << (int) mContext->highestSupportedGpuFamily.mac;
}
utils::slog.v << "Features:" << utils::io::endl;
utils::slog.v << " readWriteTextureSupport: " <<
(bool) mContext->device.readWriteTextureSupport << utils::io::endl;
LOG(INFO) << "Features:";
LOG(INFO) << " readWriteTextureSupport: " << (bool) mContext->device.readWriteTextureSupport;
// In order to support texture swizzling, the GPU needs to support it and the system be running
// iOS 13+.
@@ -588,7 +585,7 @@ void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program) {
#if FILAMENT_METAL_DEBUG_LOG
auto handleId = rph.getId();
DEBUG_LOG("createProgramR(rph = %d, program = ", handleId);
utils::slog.d << program << utils::io::endl;
DLOG(INFO) << program;
#endif
construct_handle<MetalProgram>(rph, *mContext, std::move(program));
}
@@ -2077,7 +2074,7 @@ void MetalDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGro
error:&error];
if (error) {
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
utils::slog.e << description << utils::io::endl;
LOG(ERROR) << description;
}
assert_invariant(!error);
@@ -20,14 +20,14 @@
#include "MetalEnums.h"
#include "MetalUtils.h"
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/Log.h>
#include <utils/trap.h>
#define NSERROR_CHECK(message) \
if (error) { \
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding]; \
utils::slog.e << description << utils::io::endl; \
LOG(ERROR) << description; \
} \
FILAMENT_CHECK_POSTCONDITION(error == nil) << message;
+9 -8
View File
@@ -27,10 +27,11 @@
#include "private/backend/BackendUtils.h"
#include <utils/compiler.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/trap.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/trap.h>
#include <math/scalar.h>
@@ -115,14 +116,14 @@ MetalSwapChain::MetalSwapChain(
type(SwapChainType::CAMETALLAYER) {
if (!(flags & SwapChain::CONFIG_TRANSPARENT) && !nativeWindow.opaque) {
utils::slog.w << "Warning: Filament SwapChain has no CONFIG_TRANSPARENT flag, "
"but the CAMetaLayer(" << (__bridge void*) nativeWindow << ")"
" has .opaque set to NO." << utils::io::endl;
LOG(WARNING) << "Warning: Filament SwapChain has no CONFIG_TRANSPARENT flag, but the "
"CAMetaLayer("
<< (__bridge void*) nativeWindow << ") has .opaque set to NO.";
}
if ((flags & SwapChain::CONFIG_TRANSPARENT) && nativeWindow.opaque) {
utils::slog.w << "Warning: Filament SwapChain has the CONFIG_TRANSPARENT flag, "
"but the CAMetaLayer(" << (__bridge void*) nativeWindow << ")"
" has .opaque set to YES." << utils::io::endl;
LOG(WARNING) << "Warning: Filament SwapChain has the CONFIG_TRANSPARENT flag, but the "
"CAMetaLayer("
<< (__bridge void*) nativeWindow << ") has .opaque set to YES.";
}
// Needed so we can use the SwapChain as a blit source.
@@ -21,6 +21,7 @@
#include <backend/Program.h>
#include <utils/JobSystem.h>
#include <utils/Logger.h>
#include <utils/Mutex.h>
#include <chrono>
@@ -147,7 +148,7 @@ bool MetalShaderCompiler::isParallelShaderCompileSupported() const noexcept {
if (error) {
auto description =
[error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
utils::slog.w << description << utils::io::endl;
LOG(WARNING) << description;
errorMessage = error.localizedDescription;
}
PANIC_LOG("Failed to compile Metal program.");
@@ -178,7 +179,7 @@ bool MetalShaderCompiler::isParallelShaderCompileSupported() const noexcept {
if (error) {
auto description =
[error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
utils::slog.w << description << utils::io::endl;
LOG(WARNING) << description;
errorMessage = error.localizedDescription;
}
PANIC_LOG("Failed to load main0 in Metal program.");
+3 -3
View File
@@ -18,7 +18,7 @@
#include "MetalEnums.h"
#include <utils/Log.h>
#include <utils/Logger.h>
namespace filament {
namespace backend {
@@ -95,7 +95,7 @@ id<MTLRenderPipelineState> PipelineStateCreator::operator()(id<MTLDevice> device
[NSString stringWithFormat:@"Could not create Metal pipeline state: %@",
error ? error.localizedDescription : @"unknown error"];
auto description = [errorMessage cStringUsingEncoding:NSUTF8StringEncoding];
utils::slog.e << description << utils::io::endl;
LOG(ERROR) << description;
[[NSException exceptionWithName:@"MetalRenderPipelineFailure"
reason:errorMessage
userInfo:nil] raise];
@@ -155,7 +155,7 @@ id<MTLSamplerState> SamplerStateCreator::operator()(id<MTLDevice> device,
// MTLSamplerDescriptor.
// In practice, this means shadows are not supported when running in the simulator.
if (![device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
utils::slog.w << "Warning: sample comparison not supported by this GPU" << utils::io::endl;
LOG(WARNING) << "Warning: sample comparison not supported by this GPU";
samplerDescriptor.compareFunction = MTLCompareFunctionNever;
}
#endif
+3 -4
View File
@@ -19,7 +19,7 @@
#include "MetalDriverFactory.h"
#include <utils/Log.h>
#include <utils/Logger.h>
#import <Foundation/Foundation.h>
@@ -132,9 +132,8 @@ void PlatformMetalImpl::createDeviceImpl(MetalDevice& outDevice) {
result = MTLCreateSystemDefaultDevice();
}
utils::slog.i << "Selected physical device '"
<< [result.name cStringUsingEncoding:NSUTF8StringEncoding] << "'"
<< utils::io::endl;
LOG(INFO) << "Selected physical device '"
<< [result.name cStringUsingEncoding:NSUTF8StringEncoding] << "'";
outDevice.device = result;
mDevice = result;
@@ -360,7 +360,7 @@ void GLDescriptorSet::bind(
}
}, entry.desc);
});
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void GLDescriptorSet::validate(HandleAllocatorGL& allocator,
+16 -10
View File
@@ -18,6 +18,7 @@
#include "private/backend/Driver.h"
#include <utils/Logger.h>
#include <utils/compiler.h>
#include <utils/ostream.h>
#include <utils/trap.h>
@@ -25,6 +26,7 @@
#include <string_view>
#include <stddef.h>
#include <cstdio>
namespace filament::backend {
@@ -55,19 +57,21 @@ std::string_view getGLErrorString(GLenum error) noexcept {
}
UTILS_NOINLINE
GLenum checkGLError(io::ostream& out, const char* function, size_t line) noexcept {
GLenum checkGLError(const char* function, size_t line) noexcept {
GLenum const error = glGetError();
if (UTILS_VERY_UNLIKELY(error != GL_NO_ERROR)) {
auto const string = getGLErrorString(error);
out << "OpenGL error " << io::hex << error << " (" << string << ") in \""
<< function << "\" at line " << io::dec << line << io::endl;
char hexError[16];
snprintf(hexError, sizeof(hexError), "%#x", error);
LOG(ERROR) << "OpenGL error " << hexError << " (" << string << ") in \"" << function
<< "\" at line " << line;
}
return error;
}
UTILS_NOINLINE
void assertGLError(io::ostream& out, const char* function, size_t line) noexcept {
GLenum const err = checkGLError(out, function, line);
void assertGLError(const char* function, size_t line) noexcept {
GLenum const err = checkGLError(function, line);
if (UTILS_VERY_UNLIKELY(err != GL_NO_ERROR)) {
debug_trap();
}
@@ -97,19 +101,21 @@ std::string_view getFramebufferStatusString(GLenum status) noexcept {
}
UTILS_NOINLINE
GLenum checkFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept {
GLenum checkFramebufferStatus(GLenum target, const char* function, size_t line) noexcept {
GLenum const status = glCheckFramebufferStatus(target);
if (UTILS_VERY_UNLIKELY(status != GL_FRAMEBUFFER_COMPLETE)) {
auto const string = getFramebufferStatusString(status);
out << "OpenGL framebuffer error " << io::hex << status << " (" << string << ") in \""
<< function << "\" at line " << io::dec << line << io::endl;
char hexStatus[16];
snprintf(hexStatus, sizeof(hexStatus), "%#x", status);
LOG(ERROR) << "OpenGL framebuffer error " << hexStatus << " (" << string << ") in \""
<< function << "\" at line " << line;
}
return status;
}
UTILS_NOINLINE
void assertFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept {
GLenum const status = checkFramebufferStatus(out, target, function, line);
void assertFramebufferStatus(GLenum target, const char* function, size_t line) noexcept {
GLenum const status = checkFramebufferStatus(target, function, line);
if (UTILS_VERY_UNLIKELY(status != GL_FRAMEBUFFER_COMPLETE)) {
debug_trap();
}
+10 -10
View File
@@ -33,21 +33,21 @@
namespace filament::backend::GLUtils {
std::string_view getGLErrorString(GLenum error) noexcept;
GLenum checkGLError(utils::io::ostream& out, const char* function, size_t line) noexcept;
void assertGLError(utils::io::ostream& out, const char* function, size_t line) noexcept;
GLenum checkGLError(const char* function, size_t line) noexcept;
void assertGLError(const char* function, size_t line) noexcept;
std::string_view getFramebufferStatusString(GLenum err) noexcept;
GLenum checkFramebufferStatus(utils::io::ostream& out, GLenum target, const char* function, size_t line) noexcept;
void assertFramebufferStatus(utils::io::ostream& out, GLenum target, const char* function, size_t line) noexcept;
GLenum checkFramebufferStatus(GLenum target, const char* function, size_t line) noexcept;
void assertFramebufferStatus(GLenum target, const char* function, size_t line) noexcept;
#ifdef NDEBUG
# define CHECK_GL_ERROR(out)
# define CHECK_GL_ERROR_NON_FATAL(out)
# define CHECK_GL_FRAMEBUFFER_STATUS(out, target)
# define CHECK_GL_ERROR()
# define CHECK_GL_ERROR_NON_FATAL()
# define CHECK_GL_FRAMEBUFFER_STATUS(target)
#else
# define CHECK_GL_ERROR(out) { GLUtils::assertGLError(out, __func__, __LINE__); }
# define CHECK_GL_ERROR_NON_FATAL(out) { GLUtils::checkGLError(out, __func__, __LINE__); }
# define CHECK_GL_FRAMEBUFFER_STATUS(out, target) { GLUtils::checkFramebufferStatus(out, target, __func__, __LINE__); }
# define CHECK_GL_ERROR() { GLUtils::assertGLError(__func__, __LINE__); }
# define CHECK_GL_ERROR_NON_FATAL() { GLUtils::checkGLError(__func__, __LINE__); }
# define CHECK_GL_FRAMEBUFFER_STATUS(target) { GLUtils::checkFramebufferStatus( target, __func__, __LINE__); }
#endif
constexpr GLuint getComponentCount(ElementType const type) noexcept {
+30 -51
View File
@@ -22,9 +22,9 @@
#include <backend/platforms/OpenGLPlatform.h>
#include <backend/DriverEnums.h>
#include <utils/Logger.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <functional>
@@ -77,8 +77,8 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
state.version = (char const*)glGetString(GL_VERSION);
state.shader = (char const*)glGetString(GL_SHADING_LANGUAGE_VERSION);
slog.v << "[" << state.vendor << "], [" << state.renderer << "], "
"[" << state.version << "], [" << state.shader << "]" << io::endl;
LOG(INFO) << "[" << state.vendor << "], [" << state.renderer << "], "
"[" << state.version << "], [" << state.shader << "]";
/*
* Figure out GL / GLES version, extensions and capabilities we need to
@@ -164,51 +164,33 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
}
#endif
slog.v << "Feature level: " << +mFeatureLevel << '\n';
slog.v << "Active workarounds: " << '\n';
LOG(INFO) << "Feature level: " << +mFeatureLevel;
LOG(INFO) << "Active workarounds: ";
UTILS_NOUNROLL
for (auto [enabled, name, _] : mBugDatabase) {
if (enabled) {
slog.v << name << '\n';
LOG(INFO) << name;
}
}
flush(slog.v);
#ifndef NDEBUG
// this is useful for development
slog.v
<< "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = "
<< gets.max_anisotropy << '\n'
<< "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = "
<< gets.max_combined_texture_image_units << '\n'
<< "GL_MAX_TEXTURE_SIZE = "
<< gets.max_texture_size << '\n'
<< "GL_MAX_CUBE_MAP_TEXTURE_SIZE = "
<< gets.max_cubemap_texture_size << '\n'
<< "GL_MAX_3D_TEXTURE_SIZE = "
<< gets.max_3d_texture_size << '\n'
<< "GL_MAX_ARRAY_TEXTURE_LAYERS = "
<< gets.max_array_texture_layers << '\n'
<< "GL_MAX_DRAW_BUFFERS = "
<< gets.max_draw_buffers << '\n'
<< "GL_MAX_RENDERBUFFER_SIZE = "
<< gets.max_renderbuffer_size << '\n'
<< "GL_MAX_SAMPLES = "
<< gets.max_samples << '\n'
<< "GL_MAX_TEXTURE_IMAGE_UNITS = "
<< gets.max_texture_image_units << '\n'
<< "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = "
<< gets.max_transform_feedback_separate_attribs << '\n'
<< "GL_MAX_UNIFORM_BLOCK_SIZE = "
<< gets.max_uniform_block_size << '\n'
<< "GL_MAX_UNIFORM_BUFFER_BINDINGS = "
<< gets.max_uniform_buffer_bindings << '\n'
<< "GL_NUM_PROGRAM_BINARY_FORMATS = "
<< gets.num_program_binary_formats << '\n'
<< "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = "
<< gets.uniform_buffer_offset_alignment << '\n'
;
flush(slog.v);
LOG(INFO) << "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = " << gets.max_anisotropy;
LOG(INFO) << "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = " << gets.max_combined_texture_image_units;
LOG(INFO) << "GL_MAX_TEXTURE_SIZE = " << gets.max_texture_size;
LOG(INFO) << "GL_MAX_CUBE_MAP_TEXTURE_SIZE = " << gets.max_cubemap_texture_size;
LOG(INFO) << "GL_MAX_3D_TEXTURE_SIZE = " << gets.max_3d_texture_size;
LOG(INFO) << "GL_MAX_ARRAY_TEXTURE_LAYERS = " << gets.max_array_texture_layers;
LOG(INFO) << "GL_MAX_DRAW_BUFFERS = " << gets.max_draw_buffers;
LOG(INFO) << "GL_MAX_RENDERBUFFER_SIZE = " << gets.max_renderbuffer_size;
LOG(INFO) << "GL_MAX_SAMPLES = " << gets.max_samples;
LOG(INFO) << "GL_MAX_TEXTURE_IMAGE_UNITS = " << gets.max_texture_image_units;
LOG(INFO) << "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = "
<< gets.max_transform_feedback_separate_attribs;
LOG(INFO) << "GL_MAX_UNIFORM_BLOCK_SIZE = " << gets.max_uniform_block_size;
LOG(INFO) << "GL_MAX_UNIFORM_BUFFER_BINDINGS = " << gets.max_uniform_buffer_bindings;
LOG(INFO) << "GL_NUM_PROGRAM_BINARY_FORMATS = " << gets.num_program_binary_formats;
LOG(INFO) << "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = " << gets.uniform_buffer_offset_alignment;
#endif
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
@@ -242,15 +224,14 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
if (ext.KHR_debug) {
auto cb = +[](GLenum, GLenum type, GLuint, GLenum severity, GLsizei length,
const GLchar* message, const void *) {
io::ostream* stream = &slog.i;
auto logSeverity = utils::LogSeverity::kInfo;
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH: stream = &slog.e; break;
case GL_DEBUG_SEVERITY_MEDIUM: stream = &slog.w; break;
case GL_DEBUG_SEVERITY_LOW: stream = &slog.d; break;
case GL_DEBUG_SEVERITY_HIGH: logSeverity = utils::LogSeverity::kError; break;
case GL_DEBUG_SEVERITY_MEDIUM: logSeverity = utils::LogSeverity::kWarning; break;
case GL_DEBUG_SEVERITY_LOW: logSeverity = utils::LogSeverity::kInfo; break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
default: break;
}
io::ostream& out = *stream;
const char* level = ": ";
switch (type) {
case GL_DEBUG_TYPE_ERROR: level = "ERROR: "; break;
@@ -262,7 +243,7 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
case GL_DEBUG_TYPE_MARKER: level = "MARKER: "; break;
default: break;
}
out << "KHR_debug " << level << std::string_view{ message, size_t(length) } << io::endl;
LOG(LEVEL(logSeverity)) << "KHR_debug " << level << std::string_view{ message, size_t(length) };
};
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
@@ -707,9 +688,8 @@ void OpenGLContext::initExtensionsGLES(Extensions* ext, GLint major, GLint minor
GLUtils::unordered_string_set const exts = GLUtils::split(extensions);
if constexpr (DEBUG_PRINT_EXTENSIONS) {
for (auto extension: exts) {
slog.d << "\"" << std::string_view(extension) << "\"\n";
DLOG(INFO) << "\"" << std::string_view(extension) << "\"";
}
flush(slog.d);
}
// figure out and initialize the extensions we need
@@ -783,9 +763,8 @@ void OpenGLContext::initExtensionsGL(Extensions* ext, GLint major, GLint minor)
}
if constexpr (DEBUG_PRINT_EXTENSIONS) {
for (auto extension: exts) {
slog.d << "\"" << std::string_view(extension) << "\"\n";
DLOG(INFO) << "\"" << std::string_view(extension) << "\"";
}
flush(slog.d);
}
using namespace std::literals;
@@ -1045,7 +1024,7 @@ GLuint OpenGLContext::getSamplerSlow(SamplerParams params) const noexcept {
std::min(gets.max_anisotropy, anisotropy));
}
#endif
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
mSamplerMap[params] = s;
return s;
}
+88 -72
View File
@@ -48,12 +48,13 @@
#include <type_traits>
#include <utils/BitmaskEnum.h>
#include <utils/FixedCapacityVector.h>
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Invocable.h>
#include <utils/Log.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/Slice.h>
#include <utils/Systrace.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/ostream.h>
@@ -184,20 +185,18 @@ OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* platform,
// GLVertexBufferInfo : 132 moderate
// -- less than or equal to 136 bytes
slog.d
<< "\nGLSwapChain: " << sizeof(GLSwapChain)
<< "\nGLBufferObject: " << sizeof(GLBufferObject)
<< "\nGLVertexBuffer: " << sizeof(GLVertexBuffer)
<< "\nGLVertexBufferInfo: " << sizeof(GLVertexBufferInfo)
<< "\nGLIndexBuffer: " << sizeof(GLIndexBuffer)
<< "\nGLRenderPrimitive: " << sizeof(GLRenderPrimitive)
<< "\nGLTexture: " << sizeof(GLTexture)
<< "\nGLTimerQuery: " << sizeof(GLTimerQuery)
<< "\nGLStream: " << sizeof(GLStream)
<< "\nGLRenderTarget: " << sizeof(GLRenderTarget)
<< "\nGLFence: " << sizeof(GLFence)
<< "\nOpenGLProgram: " << sizeof(OpenGLProgram)
<< io::endl;
DLOG(INFO) << "GLSwapChain: " << sizeof(GLSwapChain);
DLOG(INFO) << "GLBufferObject: " << sizeof(GLBufferObject);
DLOG(INFO) << "GLVertexBuffer: " << sizeof(GLVertexBuffer);
DLOG(INFO) << "GLVertexBufferInfo: " << sizeof(GLVertexBufferInfo);
DLOG(INFO) << "GLIndexBuffer: " << sizeof(GLIndexBuffer);
DLOG(INFO) << "GLRenderPrimitive: " << sizeof(GLRenderPrimitive);
DLOG(INFO) << "GLTexture: " << sizeof(GLTexture);
DLOG(INFO) << "GLTimerQuery: " << sizeof(GLTimerQuery);
DLOG(INFO) << "GLStream: " << sizeof(GLStream);
DLOG(INFO) << "GLRenderTarget: " << sizeof(GLRenderTarget);
DLOG(INFO) << "GLFence: " << sizeof(GLFence);
DLOG(INFO) << "OpenGLProgram: " << sizeof(OpenGLProgram);
#endif
// here we check we're on a supported version of GL before initializing the driver
@@ -289,7 +288,7 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi
mStreamsWithPendingAcquiredImage.reserve(8);
#ifndef NDEBUG
slog.i << "OS version: " << mPlatform.getOSVersion() << io::endl;
LOG(INFO) << "OS version: " << mPlatform.getOSVersion();
#endif
// Timer queries are core in GL 3.3, otherwise we need EXT_disjoint_timer_query
@@ -668,7 +667,7 @@ void OpenGLDriver::createIndexBufferR(
gl.bindVertexArray(nullptr);
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib->gl.buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, nullptr, getBufferUsage(usage));
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
@@ -693,7 +692,7 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
glBufferData(bo->gl.binding, byteCount, nullptr, getBufferUsage(usage));
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
@@ -730,7 +729,7 @@ void OpenGLDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
// this records the index buffer into the currently bound VAO
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib->gl.buffer);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
@@ -760,7 +759,7 @@ void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
}
construct<OpenGLProgram>(ph, *this, std::move(program));
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
UTILS_NOINLINE
@@ -932,7 +931,12 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
if (gl.features.multisample_texture) {
// multi-sample texture on GL 3.2 / GLES 3.1 and above
t->gl.target = GL_TEXTURE_2D_MULTISAMPLE;
if (depth <= 1) {
// We forcibly change the target to 2D-multisample only for flat texture.
// A depth value greater than 1 may indicate multiview usage, which requires
// GL_TEXTURE_2D_ARRAY. Also 2D MSAA won't work with non-flat texture anyway.
t->gl.target = GL_TEXTURE_2D_MULTISAMPLE;
}
} else {
// Turn off multi-sampling for that texture. It's just not supported.
}
@@ -948,7 +952,7 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
renderBufferStorage(t->gl.id, internalFormat, w, h, samples);
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
@@ -994,7 +998,7 @@ void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
assert_invariant(ref);
ref->count++;
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
@@ -1057,7 +1061,7 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
assert_invariant(ref);
ref->count++;
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::createTextureExternalImage2R(Handle<HwTexture> th, SamplerType target,
@@ -1208,14 +1212,19 @@ void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
if (gl.features.multisample_texture) {
// multi-sample texture on GL 3.2 / GLES 3.1 and above
t->gl.target = GL_TEXTURE_2D_MULTISAMPLE;
if (depth <= 1) {
// We forcibly change the target to 2D-multisample only for flat texture.
// A depth value greater than 1 may indicate multiview usage, which requires
// GL_TEXTURE_2D_ARRAY. Also 2D MSAA won't work with non-flat texture anyway.
t->gl.target = GL_TEXTURE_2D_MULTISAMPLE;
}
} else {
// Turn off multi-sampling for that texture. It's just not supported.
}
#endif
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::updateVertexArrayObject(GLRenderPrimitive* rp, GLVertexBuffer const* vb) {
@@ -1453,8 +1462,15 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
#if !defined(__EMSCRIPTEN__) && !defined(FILAMENT_IOS)
if (layerCount > 1) {
// if layerCount > 1, it means we use the multiview extension.
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, attachment,
t->gl.id, 0, binfo.layer, layerCount);
if (rt->gl.samples > 1) {
// For MSAA
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, attachment,
t->gl.id, 0, rt->gl.samples, binfo.layer, layerCount);
}
else {
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, attachment, t->gl.id, 0,
binfo.layer, layerCount);
}
} else
#endif // !defined(__EMSCRIPTEN__) && !defined(FILAMENT_IOS)
{
@@ -1468,7 +1484,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
// we shouldn't be here
break;
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
} else
#ifndef __EMSCRIPTEN__
#ifdef GL_EXT_multisampled_render_to_texture
@@ -1489,7 +1505,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
GL_RENDERBUFFER, t->gl.id);
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
} else
#endif // GL_EXT_multisampled_render_to_texture
#endif // __EMSCRIPTEN__
@@ -1571,13 +1587,13 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
break;
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
rt->gl.resolve |= resolveFlags;
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
CHECK_GL_ERROR()
CHECK_GL_FRAMEBUFFER_STATUS(GL_FRAMEBUFFER)
}
void OpenGLDriver::renderBufferStorage(GLuint rbo, GLenum internalformat, uint32_t width, // NOLINT(readability-convert-member-functions-to-static)
@@ -1606,7 +1622,7 @@ void OpenGLDriver::renderBufferStorage(GLuint rbo, GLenum internalformat, uint32
// unbind the renderbuffer, to avoid any later confusion
glBindRenderbuffer(GL_RENDERBUFFER, 0);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::createDefaultRenderTargetR(
@@ -1703,7 +1719,7 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
if (UTILS_LIKELY(!getContext().isES2())) {
glDrawBuffers((GLsizei)maxDrawBuffers, bufs);
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
#endif
@@ -1743,7 +1759,7 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
assert_invariant(any(targets & TargetBufferFlags::ALL));
assert_invariant(tmin == tmax);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::createFenceR(Handle<HwFence> fh, int) {
@@ -2094,7 +2110,7 @@ void OpenGLDriver::setAcquiredImage(Handle<HwStream> sh, void* hwbuffer, const m
if (UTILS_UNLIKELY(glstream->user_thread.pending.image)) {
scheduleRelease(glstream->user_thread.pending);
slog.w << "Acquired image is set more than once per frame." << io::endl;
LOG(WARNING) << "Acquired image is set more than once per frame.";
}
glstream->user_thread.pending = mPlatform.transformAcquiredImage({
@@ -2543,7 +2559,7 @@ void OpenGLDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain>
// OpenGL context has changed, resynchronize the state with the cache
mContext.synchronizeStateAndCache(index);
slog.d << "*** OpenGL context change : " << (index ? "protected" : "default") << io::endl;
DLOG(INFO) << "*** OpenGL context change : " << (index ? "protected" : "default");
});
mCurrentDrawSwapChain = scDraw;
@@ -2584,7 +2600,7 @@ void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
vb->bufferObjectsVersion = (version + 1) % kMaxVersion;
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::updateIndexBuffer(
@@ -2601,7 +2617,7 @@ void OpenGLDriver::updateIndexBuffer(
scheduleDestroy(std::move(p));
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::registerBufferObjectStreams(Handle<HwBufferObject> boh, BufferObjectStreamDescriptor&& streams) {
@@ -2681,7 +2697,7 @@ void OpenGLDriver::updateBufferObject(
scheduleDestroy(std::move(bd));
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::updateBufferObjectUnsynchronized(
@@ -2728,7 +2744,7 @@ retry:
scheduleDestroy(std::move(bd));
}
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
#endif
}
@@ -2778,7 +2794,7 @@ void OpenGLDriver::generateMipmaps(Handle<HwTexture> th) {
glGenerateMipmap(t->gl.target);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::setTextureData(GLTexture const* t, uint32_t level,
@@ -2887,7 +2903,7 @@ void OpenGLDriver::setTextureData(GLTexture const* t, uint32_t level,
scheduleDestroy(std::move(p));
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::setCompressedTextureData(GLTexture const* t, uint32_t level,
@@ -2973,7 +2989,7 @@ void OpenGLDriver::setCompressedTextureData(GLTexture const* t, uint32_t level,
scheduleDestroy(std::move(p));
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) {
@@ -3136,7 +3152,7 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
TargetBufferFlags discardFlags = params.flags.discardStart & rt->targets;
GLuint const fbo = gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(GL_FRAMEBUFFER)
// each render-pass starts with a disabled scissor
gl.disable(GL_SCISSOR_TEST);
@@ -3148,7 +3164,7 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
if (attachmentCount) {
gl.procs.invalidateFramebuffer(GL_FRAMEBUFFER, attachmentCount, attachments.data());
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
} else {
// It's important to clear the framebuffer before drawing, as it resets
// the fb to a known state (resets fb compression and possibly other things).
@@ -3235,7 +3251,7 @@ void OpenGLDriver::endRenderPass(int) {
if (attachmentCount) {
gl.procs.invalidateFramebuffer(GL_FRAMEBUFFER, attachmentCount, attachments.data());
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
}
@@ -3281,13 +3297,13 @@ void OpenGLDriver::resolvePass(ResolveAction action, GLRenderTarget const* rt,
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, read);
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, draw);
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_READ_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_DRAW_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(GL_READ_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(GL_DRAW_FRAMEBUFFER)
gl.disable(GL_SCISSOR_TEST);
glBlitFramebuffer(0, 0, (GLint)rt->width, (GLint)rt->height,
0, 0, (GLint)rt->width, (GLint)rt->height, mask, GL_NEAREST);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
#endif
}
@@ -3466,7 +3482,7 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
if (buffer) {
gl.bindFramebuffer(GL_FRAMEBUFFER, s->gl.fbo_read ? s->gl.fbo_read : s->gl.fbo);
glReadPixels(GLint(x), GLint(y), GLint(width), GLint(height), glFormat, glType, buffer);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
// now we need to flip the buffer vertically to match our API
size_t const stride = p.stride ? p.stride : width;
@@ -3498,7 +3514,7 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
glBufferData(GL_PIXEL_PACK_BUFFER, pboSize, nullptr, GL_STATIC_DRAW);
glReadPixels(GLint(x), GLint(y), GLint(width), GLint(height), glFormat, glType, nullptr);
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
// we're forced to make a copy on the heap because otherwise it deletes std::function<> copy
// constructor.
@@ -3538,7 +3554,7 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
glDeleteBuffers(1, &pbo);
scheduleDestroy(std::move(p));
delete pUserBuffer;
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
});
#endif
}
@@ -3563,7 +3579,7 @@ void OpenGLDriver::readBufferSubData(BufferObjectHandle boh,
glCopyBufferSubData(bo->gl.binding, GL_PIXEL_PACK_BUFFER, offset, 0, size);
gl.bindBuffer(bo->gl.binding, 0);
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
// then, we schedule a mapBuffer of the PBO later, once the fence has signaled
auto* pUserBuffer = new BufferDescriptor(std::move(p));
@@ -3580,7 +3596,7 @@ void OpenGLDriver::readBufferSubData(BufferObjectHandle boh,
glDeleteBuffers(1, &pbo);
scheduleDestroy(std::move(p));
delete pUserBuffer;
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
});
} else {
gl.bindBuffer(bo->gl.binding, bo->gl.id);
@@ -3593,7 +3609,7 @@ void OpenGLDriver::readBufferSubData(BufferObjectHandle boh,
}
gl.bindBuffer(bo->gl.binding, 0);
scheduleDestroy(std::move(p));
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
#endif
}
@@ -3623,7 +3639,7 @@ void OpenGLDriver::whenFrameComplete(const std::function<void()>& fn) noexcept {
void OpenGLDriver::whenGpuCommandsComplete(const std::function<void()>& fn) noexcept {
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
mGpuCommandCompleteOps.emplace_back(sync, fn);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::executeGpuCommandsCompleteOps() noexcept {
@@ -3841,7 +3857,7 @@ void OpenGLDriver::clearWithRasterPipe(TargetBufferFlags clearFlags,
}
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void OpenGLDriver::resolve(
@@ -3952,7 +3968,7 @@ void OpenGLDriver::blit(
case SamplerType::SAMPLER_EXTERNAL:
break;
}
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_DRAW_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(GL_DRAW_FRAMEBUFFER)
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, fbo[1]);
switch (s->target) {
@@ -3978,14 +3994,14 @@ void OpenGLDriver::blit(
case SamplerType::SAMPLER_EXTERNAL:
break;
}
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_READ_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(GL_READ_FRAMEBUFFER)
gl.disable(GL_SCISSOR_TEST);
glBlitFramebuffer(
srcOrigin.x, srcOrigin.y, srcOrigin.x + size.x, srcOrigin.y + size.y,
dstOrigin.x, dstOrigin.y, dstOrigin.x + size.x, dstOrigin.y + size.y,
mask, GL_NEAREST);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
gl.unbindFramebuffer(GL_DRAW_FRAMEBUFFER);
gl.unbindFramebuffer(GL_READ_FRAMEBUFFER);
@@ -4048,15 +4064,15 @@ void OpenGLDriver::blitDEPRECATED(TargetBufferFlags buffers,
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, s->gl.fbo);
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, d->gl.fbo);
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_READ_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_DRAW_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(GL_READ_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(GL_DRAW_FRAMEBUFFER)
gl.disable(GL_SCISSOR_TEST);
glBlitFramebuffer(
srcRect.left, srcRect.bottom, srcRect.right(), srcRect.top(),
dstRect.left, dstRect.bottom, dstRect.right(), dstRect.top(),
GL_COLOR_BUFFER_BIT, glFilterMode);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
#endif
}
@@ -4183,9 +4199,9 @@ void OpenGLDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t ins
#endif
#if FILAMENT_ENABLE_MATDBG
CHECK_GL_ERROR_NON_FATAL(utils::slog.e)
CHECK_GL_ERROR_NON_FATAL()
#else
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
#endif
}
@@ -4215,9 +4231,9 @@ void OpenGLDriver::draw2GLES2(uint32_t indexOffset, uint32_t indexCount, uint32_
reinterpret_cast<const void*>(indexOffset << rp->gl.indicesShift));
#if FILAMENT_ENABLE_MATDBG
CHECK_GL_ERROR_NON_FATAL(utils::slog.e)
CHECK_GL_ERROR_NON_FATAL()
#else
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
#endif
}
@@ -4267,9 +4283,9 @@ void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, uint3 workGroupCou
#endif // BACKEND_OPENGL_LEVEL_GLES31
#if FILAMENT_ENABLE_MATDBG
CHECK_GL_ERROR_NON_FATAL(utils::slog.e)
CHECK_GL_ERROR_NON_FATAL()
#else
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
#endif
}
@@ -64,7 +64,7 @@ utils::CString OpenGLPlatform::getRendererString(Driver const* driver) {
}
void OpenGLPlatform::makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain,
utils::Invocable<void()>, utils::Invocable<void(size_t)>) noexcept {
utils::Invocable<void()>, utils::Invocable<void(size_t)>) {
makeCurrent(getCurrentContextType(), drawSwapChain, readSwapChain);
}
@@ -214,7 +214,7 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
case DescriptorType::INPUT_ATTACHMENT:
break;
}
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
}
@@ -114,14 +114,14 @@ void TimerQueryNativeFactory::createTimerQuery(GLTimerQuery* tq) {
tq->state = std::make_shared<GLTimerQuery::State>();
mContext.procs.genQueries(1u, &tq->state->gl.query);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void TimerQueryNativeFactory::destroyTimerQuery(GLTimerQuery* tq) {
assert_invariant(tq->state);
mContext.procs.deleteQueries(1u, &tq->state->gl.query);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
tq->state.reset();
}
@@ -131,14 +131,14 @@ void TimerQueryNativeFactory::beginTimeElapsedQuery(GLTimerQuery* tq) {
tq->state->elapsed.store(int64_t(TimerQueryResult::NOT_READY), std::memory_order_relaxed);
mContext.procs.beginQuery(GL_TIME_ELAPSED, tq->state->gl.query);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
void TimerQueryNativeFactory::endTimeElapsedQuery(OpenGLDriver& driver, GLTimerQuery* tq) {
assert_invariant(tq->state);
mContext.procs.endQuery(GL_TIME_ELAPSED);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
std::weak_ptr<GLTimerQuery::State> const weak = tq->state;
@@ -153,7 +153,7 @@ void TimerQueryNativeFactory::endTimeElapsedQuery(OpenGLDriver& driver, GLTimerQ
GLuint available = 0;
context.procs.getQueryObjectuiv(state->gl.query, GL_QUERY_RESULT_AVAILABLE, &available);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
if (!available) {
// we need to try this one again later
return false;
@@ -23,6 +23,7 @@
#include "OpenGLDriver.h"
#include <iterator>
#include <optional>
#include <private/backend/BackendUtils.h>
#include <backend/DriverEnums.h>
@@ -30,14 +31,14 @@
#include <private/utils/Tracing.h>
#include <utils/compiler.h>
#include <utils/CString.h>
#include <utils/debug.h>
#include <utils/FixedCapacityVector.h>
#include <utils/JobSystem.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/ostream.h>
#include <algorithm>
#include <array>
@@ -64,9 +65,9 @@ static std::string to_string(bool const b) { return b ? "true" : "false"; }
static std::string to_string(int const i) { return std::to_string(i); }
static std::string to_string(float const f) { return "float(" + std::to_string(f) + ")"; }
static void logCompilationError(io::ostream& out, ShaderStage shaderType, const char* name,
GLuint shaderId, CString const& sourceCode) noexcept;
static void logProgramLinkError(io::ostream& out, char const* name, GLuint program) noexcept;
static void logCompilationError(ShaderStage shaderType, const char* name, GLuint shaderId,
Program::ShaderBlob const& sourceCode) noexcept;
static void logProgramLinkError(char const* name, GLuint program) noexcept;
static void process_GOOGLE_cpp_style_line_directive(OpenGLContext const& context, char* source,
size_t len) noexcept;
@@ -87,7 +88,7 @@ struct ShaderCompilerService::OpenGLProgramToken : ProgramToken {
ShaderCompilerService& compiler;
CString const& name;
FixedCapacityVector<std::pair<CString, uint8_t>> attributes;
shaders_source_t shaderSourceCode;
Program::ShaderSource shaderSourceCode;
void* user = nullptr;
struct {
shaders_t shaders{};
@@ -110,17 +111,33 @@ struct ShaderCompilerService::OpenGLProgramToken : ProgramToken {
cond.wait(l, [this] { return signaled; });
}
CallbackManager::Handle handle{};
// This is invoked upon token completion, which occurs after a successful `gl.program`
// population or upon cancellation. In either scenario, the callback handle must be submitted
// to notify the caller that resource loading has concluded.
void trySubmittingCallback() noexcept {
if (handle) {
compiler.submitCallbackHandle(*handle);
handle = std::nullopt;
}
}
std::optional<CallbackManager::Handle> handle{};
// Only valid when the blob functions are provided by users. The validity of this variable
// doesn't guarantee that the program was created from the cache blob.
BlobCacheKey key;
// Used for the `THREAD_POOL` mode.
mutable Mutex lock;
mutable Condition cond;
bool signaled = false;
// Indicate this program was created from the cache blob.
bool retrievedFromBlobCache = false;
};
ShaderCompilerService::OpenGLProgramToken::~OpenGLProgramToken() {
compiler.submitCallbackHandle(handle);
trySubmittingCallback();
}
/* static */ void ShaderCompilerService::setUserData(const program_token_t& token,
@@ -248,6 +265,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
// Try retrieving the cached program blob if available.
token->gl.program = mBlobCache.retrieve(&token->key, mDriver.mPlatform, program);
if (token->gl.program) {
token->retrievedFromBlobCache = true;
return token;
}
@@ -326,12 +344,15 @@ GLuint ShaderCompilerService::getProgram(program_token_t& token) {
assert_invariant(token);// This function should be called when the token is still alive.
if (token->compiler.mMode == Mode::THREAD_POOL) {
auto const job = token->compiler.mCompilerThreadPool.dequeue(token);
if (!job) {
// It's likely that the job was already completed. But it may be still being
// executed at this moment. Just try waiting for it to avoid a race.
token->wait();
// Finalize any pending shader compilation tasks only when the token was created without cache.
if (!token->retrievedFromBlobCache) {
if (token->compiler.mMode == Mode::THREAD_POOL) {
auto const job = token->compiler.mCompilerThreadPool.dequeue(token);
if (!job) {
// It's likely that the job was already completed. But it may be still being
// executed at this moment. Just try waiting for it to avoid a race.
token->wait();
}
}
}
@@ -339,7 +360,7 @@ GLuint ShaderCompilerService::getProgram(program_token_t& token) {
// Cleanup the token.
token->compiler.cancelTickOp(token);
token = nullptr;// This will submit a callback condition (handle) to the callback manager.
token = nullptr; // This will try submitting a callback handle to the callback manager.
}
void ShaderCompilerService::tick() {
@@ -392,7 +413,7 @@ GLuint ShaderCompilerService::initialize(program_token_t& token) {
// Cleanup the token.
token->compiler.cancelTickOp(token);
token = nullptr;// This will submit a callback condition (handle) to the callback manager.
token = nullptr;
return program;
}
@@ -422,8 +443,9 @@ void ShaderCompilerService::ensureTokenIsReady(program_token_t const& token) {
// just log warnings here instead of repeatedly checking compile status. If this turns
// out to be a real issue later, we would need to consider doing the canonical way.
if (!isCompileCompleted(token)) {
slog.w << "Shader compilation for OpenGL program " << token->name.c_str_safe()
<< " is not completed yet. The following program link may not succeed.";
LOG(WARNING)
<< "Shader compilation for OpenGL program " << token->name.c_str_safe()
<< " is not completed yet. The following program link may not succeed.";
}
linkProgram(mDriver.getContext(), token);
@@ -590,7 +612,7 @@ void ShaderCompilerService::executeTickOps() noexcept {
#ifndef NDEBUG
// for debugging we return the original shader source (without the modifications we
// made here), otherwise the line numbers wouldn't match.
token->shaderSourceCode[i] = { shader_src, shader_len };
token->shaderSourceCode[i] = std::move(shader);
#endif
token->gl.shaders[i] = shaderId;
}
@@ -633,8 +655,7 @@ void ShaderCompilerService::executeTickOps() noexcept {
}
// Something went wrong. Log the error message.
const ShaderStage type = static_cast<ShaderStage>(i);
logCompilationError(slog.e, type, token->name.c_str_safe(), shader,
token->shaderSourceCode[i]);
logCompilationError(type, token->name.c_str_safe(), shader, token->shaderSourceCode[i]);
}
}
@@ -659,6 +680,7 @@ void ShaderCompilerService::executeTickOps() noexcept {
}
glLinkProgram(program);
token->gl.program = program;
token->trySubmittingCallback();
}
/* static */ bool ShaderCompilerService::isLinkCompleted(program_token_t const& token) noexcept {
@@ -685,7 +707,7 @@ void ShaderCompilerService::executeTickOps() noexcept {
glGetProgramiv(token->gl.program, GL_LINK_STATUS, &status);
if (UTILS_UNLIKELY(status != GL_TRUE)) {
// Something went wrong. Log the error message.
logProgramLinkError(slog.e, token->name.c_str_safe(), token->gl.program);
logProgramLinkError(token->name.c_str_safe(), token->gl.program);
linked = false;
}
// No need to keep the shaders around regardless of the result of the program linking.
@@ -735,8 +757,9 @@ void ShaderCompilerService::executeTickOps() noexcept {
// ------------------------------------------------------------------------------------------------
UTILS_NOINLINE
/* static */ void logCompilationError(io::ostream& out, ShaderStage shaderType, const char* name,
GLuint const shaderId, UTILS_UNUSED_IN_RELEASE CString const& sourceCode) noexcept {
/* static */ void logCompilationError(ShaderStage shaderType, const char* name,
GLuint const shaderId,
UTILS_UNUSED_IN_RELEASE Program::ShaderBlob const& sourceCode) noexcept {
{ // scope for the temporary string storage
auto to_string = [](ShaderStage type) -> const char* {
@@ -757,12 +780,14 @@ UTILS_NOINLINE
CString infoLog(length);
glGetShaderInfoLog(shaderId, length, nullptr, infoLog.data());
out << "Compilation error in " << to_string(shaderType) << " shader \"" << name << "\":\n"
<< "\"" << infoLog.c_str() << "\"" << io::endl;
LOG(ERROR) << "Compilation error in " << to_string(shaderType) << " shader \"" << name
<< "\":";
LOG(ERROR) << "\"" << infoLog.c_str() << "\"";
}
#ifndef NDEBUG
std::string_view const shader{ sourceCode.data(), sourceCode.size() };
std::string_view const shader{ reinterpret_cast<const char*>(sourceCode.data()),
sourceCode.size() };
size_t lc = 1;
size_t start = 0;
std::string line;
@@ -773,26 +798,25 @@ UTILS_NOINLINE
} else {
line = shader.substr(start, end - start);
}
out << lc++ << ": " << line.c_str() << '\n';
LOG(ERROR) << lc++ << ": " << line.c_str();
if (end == std::string::npos) {
break;
}
start = end + 1;
}
out << io::endl;
LOG(ERROR) << "";
#endif
}
UTILS_NOINLINE
/* static */ void logProgramLinkError(io::ostream& out, char const* name, GLuint program) noexcept {
/* static */ void logProgramLinkError(char const* name, GLuint program) noexcept {
GLint length = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
CString infoLog(length);
glGetProgramInfoLog(program, length, nullptr, infoLog.data());
out << "Link error in \"" << name << "\":\n"
<< "\"" << infoLog.c_str() << "\"" << io::endl;
LOG(ERROR) << "Link error in \"" << name << "\":\n" << "\"" << infoLog.c_str() << "\"";
}
// If usages of the Google-style line directive are present, remove them, as some
@@ -58,7 +58,6 @@ class ShaderCompilerService {
public:
using program_token_t = std::shared_ptr<OpenGLProgramToken>;
using shaders_t = std::array<GLuint, Program::SHADER_TYPE_COUNT>;
using shaders_source_t = std::array<utils::CString, Program::SHADER_TYPE_COUNT>;
explicit ShaderCompilerService(OpenGLDriver& driver);
@@ -70,6 +70,9 @@ PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glMaxShaderCompilerThreadsKHR;
#ifdef GL_OVR_multiview
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR;
#endif
#ifdef GL_OVR_multiview_multisampled_render_to_texture
PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC glFramebufferTextureMultisampleMultiviewOVR;
#endif
#if defined(__ANDROID__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
// On Android, If we want to support a build system less than ANDROID_API 21, we need to
@@ -123,6 +126,9 @@ void importGLESExtensionsEntryPoints() {
#ifdef GL_OVR_multiview
getProcAddress(glFramebufferTextureMultiviewOVR, "glFramebufferTextureMultiviewOVR");
#endif
#ifdef GL_OVR_multiview_multisampled_render_to_texture
getProcAddress(glFramebufferTextureMultisampleMultiviewOVR, "glFramebufferTextureMultisampleMultiviewOVR");
#endif
#if defined(__ANDROID__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
getProcAddress(glDispatchCompute, "glDispatchCompute");
#endif
+3
View File
@@ -154,6 +154,9 @@ extern PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glMaxShaderCompilerThreadsKHR;
#ifdef GL_OVR_multiview
extern PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR;
#endif
#ifdef GL_OVR_multiview_multisampled_render_to_texture
extern PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC glFramebufferTextureMultisampleMultiviewOVR;
#endif
#if defined(__ANDROID__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
extern PFNGLDISPATCHCOMPUTEPROC glDispatchCompute;
#endif
@@ -96,7 +96,7 @@ CocoaExternalImage::SharedGl::~SharedGl() noexcept {
CocoaExternalImage::CocoaExternalImage(const CVOpenGLTextureCacheRef textureCache,
const SharedGl &sharedGl) noexcept : mSharedGl(sharedGl), mTextureCache(textureCache) {
glGenFramebuffers(1, &mFBO);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
CocoaExternalImage::~CocoaExternalImage() noexcept {
@@ -125,7 +125,7 @@ bool CocoaExternalImage::set(CVPixelBufferRef image) noexcept {
mTexture = createTextureFromImage(image);
mRgbaTexture = encodeCopyRectangleToTexture2D(CVOpenGLTextureGetName(mTexture),
CVPixelBufferGetWidth(image), CVPixelBufferGetHeight(image));
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
return true;
}
@@ -182,33 +182,33 @@ GLuint CocoaExternalImage::encodeCopyRectangleToTexture2D(GLuint rectangle,
// Create a texture to hold the result of the blit image.
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
// source textures
glBindSampler(0, mSharedGl.sampler);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_RECTANGLE, rectangle);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
// destination texture
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_FRAMEBUFFER_STATUS(GL_FRAMEBUFFER)
CHECK_GL_ERROR()
// draw
glViewport(0, 0, width, height);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
glUseProgram(mSharedGl.program);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
glDisableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
mState.restore();
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
return texture;
}
@@ -119,7 +119,7 @@ CocoaTouchExternalImage::CocoaTouchExternalImage(const CVOpenGLESTextureCacheRef
glGenFramebuffers(1, &mFBO);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
}
CocoaTouchExternalImage::~CocoaTouchExternalImage() noexcept {
@@ -247,7 +247,7 @@ GLuint CocoaTouchExternalImage::encodeColorConversionPass(GLuint yPlaneTexture,
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
// source textures
glBindSampler(0, mSharedGl.sampler);
@@ -261,8 +261,8 @@ GLuint CocoaTouchExternalImage::encodeColorConversionPass(GLuint yPlaneTexture,
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
CHECK_GL_ERROR()
CHECK_GL_FRAMEBUFFER_STATUS(GL_FRAMEBUFFER)
// geometry
glBindVertexArray(0);
@@ -275,7 +275,7 @@ GLuint CocoaTouchExternalImage::encodeColorConversionPass(GLuint yPlaneTexture,
glUseProgram(mSharedGl.program);
glDrawArrays(GL_TRIANGLES, 0, 3);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_ERROR()
mState.restore();
@@ -20,9 +20,9 @@
#include <backend/Platform.h>
#include <utils/Logger.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#if __has_include(<android/surface_texture.h>)
@@ -59,7 +59,7 @@ void ExternalStreamManagerAndroid::destroy(ExternalStreamManagerAndroid* pExtern
ExternalStreamManagerAndroid::ExternalStreamManagerAndroid() noexcept
: mVm(VirtualMachineEnv::get()) {
if (__builtin_available(android 28, *)) {
slog.d << "Using ASurfaceTexture" << io::endl;
DLOG(INFO) << "Using ASurfaceTexture";
}
}
@@ -255,7 +255,7 @@ void PlatformCocoaGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept
}
bool PlatformCocoaGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept {
SwapChain* readSwapChain) {
ASSERT_PRECONDITION_NON_FATAL(drawSwapChain == readSwapChain,
"ContextManagerCocoa does not support using distinct draw/read swap chains.");
CocoaGLSwapChain* swapChain = (CocoaGLSwapChain*)drawSwapChain;
@@ -155,7 +155,7 @@ uint32_t PlatformCocoaTouchGL::getDefaultFramebufferObject() noexcept {
}
bool PlatformCocoaTouchGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept {
SwapChain* readSwapChain) {
ASSERT_PRECONDITION_NON_FATAL(drawSwapChain == readSwapChain,
"PlatformCocoaTouchGL does not support using distinct draw/read swap chains.");
CAEAGLLayer* const glLayer = (__bridge CAEAGLLayer*) drawSwapChain;
@@ -32,9 +32,9 @@
#endif
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Invocable.h>
#include <utils/Log.h>
#include <utils/Logger.h>
#include <utils/debug.h>
#include <utils/ostream.h>
#include <algorithm>
@@ -74,7 +74,7 @@ void PlatformEGL::logEglError(const char* name) noexcept {
}
void PlatformEGL::logEglError(const char* name, EGLint error) noexcept {
slog.e << name << " failed with " << getEglErrorName(error) << io::endl;
LOG(ERROR) << name << " failed with " << getEglErrorName(error);
}
const char* PlatformEGL::getEglErrorName(EGLint error) noexcept {
@@ -101,7 +101,7 @@ void PlatformEGL::clearGlError() noexcept {
// clear GL error that may have been set by previous calls
GLenum const error = glGetError();
if (error != GL_NO_ERROR) {
slog.w << "Ignoring pending GL error " << io::hex << error << io::endl;
LOG(WARNING) << "Ignoring pending GL error " << io::hex << error;
}
}
@@ -142,7 +142,7 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& drive
}
if (UTILS_UNLIKELY(!initialized)) {
slog.e << "eglInitialize failed" << io::endl;
LOG(ERROR) << "eglInitialize failed";
return nullptr;
}
@@ -209,10 +209,42 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& drive
}
#endif
// Configure GPU context priority level for scheduling and preemption
if (driverConfig.gpuContextPriority != Platform::GpuContextPriority::DEFAULT) {
if (extensions.has("EGL_IMG_context_priority")) {
EGLint priorityLevel = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
const char* priorityName;
switch (driverConfig.gpuContextPriority) {
case Platform::GpuContextPriority::DEFAULT:
assert_invariant(false);
break;
case Platform::GpuContextPriority::LOW:
priorityLevel = EGL_CONTEXT_PRIORITY_LOW_IMG;
priorityName = "LOW";
break;
case Platform::GpuContextPriority::MEDIUM:
priorityLevel = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
priorityName = "MEDIUM";
break;
case Platform::GpuContextPriority::HIGH:
priorityLevel = EGL_CONTEXT_PRIORITY_HIGH_IMG;
priorityName = "HIGH";
break;
case Platform::GpuContextPriority::REALTIME:
priorityLevel = EGL_CONTEXT_PRIORITY_HIGH_IMG;
priorityName = "REALTIME(=HIGH)";
break;
}
contextAttribs[EGL_CONTEXT_PRIORITY_LEVEL_IMG] = priorityLevel;
LOG(INFO) << "EGL: Enabling GPU context priority: " << priorityName;
} else {
LOG(WARNING) << "EGL: GPU context priority requested but not supported";
}
}
// config use for creating the context
EGLConfig eglConfig = EGL_NO_CONFIG_KHR;
if (UTILS_UNLIKELY(!ext.egl.KHR_no_config_context)) {
// find a config we can use if we don't have "EGL_KHR_no_config_context" and that we can use
// for the dummy pbuffer surface.
@@ -577,18 +609,18 @@ OpenGLPlatform::ContextType PlatformEGL::getCurrentContextType() const noexcept
}
bool PlatformEGL::makeCurrent(ContextType type,
SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept {
SwapChain* drawSwapChain, SwapChain* readSwapChain) {
SwapChainEGL const* const dsc = static_cast<SwapChainEGL const*>(drawSwapChain);
SwapChainEGL const* const rsc = static_cast<SwapChainEGL const*>(readSwapChain);
EGLContext context = getContextForType(type);
EGLBoolean const success = egl.makeCurrent(context, dsc->sur, rsc->sur);
return success == EGL_TRUE ? true : false;
return success == EGL_TRUE;
}
void PlatformEGL::makeCurrent(SwapChain* drawSwapChain,
SwapChain* readSwapChain,
Invocable<void()> preContextChange,
Invocable<void(size_t index)> postContextChange) noexcept {
Invocable<void(size_t index)> postContextChange) {
assert_invariant(drawSwapChain);
assert_invariant(readSwapChain);
@@ -796,7 +828,7 @@ void PlatformEGL::Config::erase(EGLint name) noexcept {
// ------------------------------------------------------------------------------------------------
EGLBoolean PlatformEGL::EGL::makeCurrent(EGLContext context, EGLSurface drawSurface,
EGLSurface readSurface) noexcept {
EGLSurface readSurface) {
if (UTILS_UNLIKELY((
mCurrentContext != context ||
drawSurface != mCurrentDrawSurface || readSurface != mCurrentReadSurface))) {
@@ -29,13 +29,12 @@
#include <android/native_window.h>
#include <android/hardware_buffer.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/android/PerformanceHintManager.h>
#include <utils/compiler.h>
#include <utils/compiler.h>
#include <utils/ostream.h>
#include <utils/Panic.h>
#include <utils/Log.h>
#include <utils/compiler.h>
#include <utils/ostream.h>
#include <EGL/egl.h>
@@ -135,7 +134,7 @@ static constexpr const std::string_view kNativeWindowInvalidMsg =
bool PlatformEGLAndroid::makeCurrent(ContextType type,
SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept {
SwapChain* readSwapChain) {
// fast & safe path
if (UTILS_LIKELY(!mAssertNativeWindowIsValid)) {
@@ -327,7 +326,7 @@ bool PlatformEGLAndroid::setImage(ExternalImageEGLAndroid const* eglExternalImag
EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
if (eglImage == EGL_NO_IMAGE_KHR) {
// Handle error
slog.e << "Failed to create EGL image" << io::endl;
LOG(ERROR) << "Failed to create EGL image";
glDeleteTextures(1, &texture->id);
return false;
}
@@ -340,7 +339,7 @@ bool PlatformEGLAndroid::setImage(ExternalImageEGLAndroid const* eglExternalImag
glBindTexture(texture->target, texture->id);
GLenum error = glGetError();
if (UTILS_UNLIKELY(error != GL_NO_ERROR)) {
slog.e << "Error after glBindTexture: " << error << io::endl;
LOG(ERROR) << "Error after glBindTexture: " << error;
glDeleteTextures(1, &texture->id);
eglDestroyImageKHR(eglGetCurrentDisplay(), eglImage);
glActiveTexture(prevActiveTexture);
@@ -350,7 +349,7 @@ bool PlatformEGLAndroid::setImage(ExternalImageEGLAndroid const* eglExternalImag
glEGLImageTargetTexture2DOES(texture->target, static_cast<GLeglImageOES>(eglImage));
error = glGetError();
if (UTILS_UNLIKELY(error != GL_NO_ERROR)) {
slog.e << "Error after glEGLImageTargetTexture2DOES: " << error << io::endl;
LOG(ERROR) << "Error after glEGLImageTargetTexture2DOES: " << error;
glDeleteTextures(1, &texture->id);
eglDestroyImageKHR(eglGetCurrentDisplay(), eglImage);
glActiveTexture(prevActiveTexture);
@@ -408,7 +407,7 @@ AcquiredImage PlatformEGLAndroid::transformAcquiredImage(AcquiredImage source) n
EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(pHardwareBuffer);
if (!clientBuffer) {
slog.e << "Unable to get EGLClientBuffer from AHardwareBuffer." << io::endl;
LOG(ERROR) << "Unable to get EGLClientBuffer from AHardwareBuffer.";
return {};
}
@@ -427,7 +426,7 @@ AcquiredImage PlatformEGLAndroid::transformAcquiredImage(AcquiredImage source) n
EGLImageKHR eglImage = eglCreateImageKHR(mEGLDisplay,
EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attributes.data());
if (eglImage == EGL_NO_IMAGE_KHR) {
slog.e << "eglCreateImageKHR returned no image." << io::endl;
LOG(ERROR) << "eglCreateImageKHR returned no image.";
return {};
}
@@ -442,7 +441,7 @@ AcquiredImage PlatformEGLAndroid::transformAcquiredImage(AcquiredImage source) n
auto patchedCallback = [](void* image, void* userdata) {
Closure* closure = (Closure*)userdata;
if (eglDestroyImageKHR(closure->display, (EGLImageKHR) image) == EGL_FALSE) {
slog.e << "eglDestroyImageKHR failed." << io::endl;
LOG(ERROR) << "eglDestroyImageKHR failed.";
}
closure->acquiredImage.callback(closure->acquiredImage.image, closure->acquiredImage.userData);
delete closure;
@@ -21,9 +21,9 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <utils/compiler.h>
#include <utils/Log.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/compiler.h>
using namespace utils;
@@ -42,12 +42,12 @@ backend::Driver* PlatformEGLHeadless::createDriver(void* sharedContext,
const Platform::DriverConfig& driverConfig) noexcept {
EGLBoolean bindAPI = eglBindAPI(EGL_OPENGL_API);
if (UTILS_UNLIKELY(!bindAPI)) {
slog.e << "eglBindAPI EGL_OPENGL_API failed" << io::endl;
LOG(ERROR) << "eglBindAPI EGL_OPENGL_API failed";
return nullptr;
}
int bindBlueGL = bluegl::bind();
if (UTILS_UNLIKELY(bindBlueGL != 0)) {
slog.e << "bluegl bind failed" << io::endl;
LOG(ERROR) << "bluegl bind failed";
return nullptr;
}
@@ -16,7 +16,7 @@
#include <backend/platforms/PlatformGLX.h>
#include <utils/Log.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <X11/Xlib.h>
@@ -84,7 +84,7 @@ static PFNGLXGETPROCADDRESSPROC getProcAddress;
static bool loadLibraries() {
g_glx.library = dlopen(LIBRARY_GLX, RTLD_LOCAL | RTLD_NOW);
if (!g_glx.library) {
utils::slog.e << "Could not find library " << LIBRARY_GLX << utils::io::endl;
LOG(ERROR) << "Could not find library " << LIBRARY_GLX;
return false;
}
@@ -115,7 +115,7 @@ static bool loadLibraries() {
g_x11.library = dlopen(LIBRARY_X11, RTLD_LOCAL | RTLD_NOW);
if (!g_x11.library) {
utils::slog.e << "Could not find library " << LIBRARY_X11 << utils::io::endl;
LOG(ERROR) << "Could not find library " << LIBRARY_X11;
return false;
}
@@ -134,7 +134,7 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
// Get the display device
mGLXDisplay = g_x11.openDisplay(NULL);
if (mGLXDisplay == nullptr) {
utils::slog.e << "Failed to open X display. (exiting)." << utils::io::endl;
LOG(ERROR) << "Failed to open X display. (exiting).";
exit(1);
}
@@ -145,8 +145,7 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
r = g_glx.queryContext(mGLXDisplay, sharedCtx, GLX_FBCONFIG_ID, &usedFbId);
if (r != 0) {
utils::slog.e << "Failed to get GLX_FBCONFIG_ID from shared GL context."
<< utils::io::endl;
LOG(ERROR) << "Failed to get GLX_FBCONFIG_ID from shared GL context.";
return nullptr;
}
@@ -154,7 +153,7 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
GLXFBConfig* fbConfigs = g_glx.getFbConfigs(mGLXDisplay, 0, &numConfigs);
if (fbConfigs == nullptr) {
utils::slog.e << "Failed to get the available GLXFBConfigs." << utils::io::endl;
LOG(ERROR) << "Failed to get the available GLXFBConfigs.";
return nullptr;
}
@@ -164,8 +163,7 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
for (int i = 0; i < numConfigs; ++i) {
r = g_glx.getFbConfigAttrib(mGLXDisplay, fbConfigs[i], GLX_FBCONFIG_ID, &fbId);
if (r != 0) {
utils::slog.e << "Failed to get GLX_FBCONFIG_ID for entry " << i << "."
<< utils::io::endl;
LOG(ERROR) << "Failed to get GLX_FBCONFIG_ID for entry " << i << ".";
continue;
}
@@ -176,8 +174,7 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
}
if (fbIndex < 0) {
utils::slog.e << "Failed to find an `GLXFBConfig` with the requested ID."
<< utils::io::endl;
LOG(ERROR) << "Failed to find an `GLXFBConfig` with the requested ID.";
return nullptr;
}
@@ -202,8 +199,7 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
getProcAddress((GLubyte*)"glXCreateContextAttribsARB");
if (glXCreateContextAttribs == nullptr) {
utils::slog.i << "Unable to retrieve function pointer for `glXCreateContextAttribs()`."
<< utils::io::endl;
LOG(INFO) << "Unable to retrieve function pointer for `glXCreateContextAttribs()`.";
return nullptr;
}
@@ -266,7 +262,7 @@ void PlatformGLX::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
}
bool PlatformGLX::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept {
SwapChain* readSwapChain) {
g_glx.setCurrentContext(mGLXDisplay,
(GLXDrawable)drawSwapChain, (GLXDrawable)readSwapChain, mGLXContext);
return true;
@@ -169,7 +169,7 @@ void PlatformOSMesa::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
}
bool PlatformOSMesa::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept {
SwapChain* readSwapChain) {
OSMesaAPI* api = (OSMesaAPI*) mOsMesaApi;
OSMesaSwapchain* impl = (OSMesaSwapchain*) drawSwapChain;
@@ -32,7 +32,7 @@
#include "GL/glext.h"
#include "GL/wglext.h"
#include <utils/Log.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
namespace {
@@ -55,8 +55,7 @@ void reportWindowsError(DWORD dwError) {
0, nullptr
);
utils::slog.e << "Windows error code: " << dwError << ". " << lpMessageBuffer
<< utils::io::endl;
LOG(ERROR) << "Windows error code: " << dwError << ". " << lpMessageBuffer;
LocalFree(lpMessageBuffer);
}
@@ -106,7 +105,7 @@ Driver* PlatformWGL::createDriver(void* sharedGLContext,
HDC whdc = mWhdc = GetDC(mHWnd);
if (whdc == NULL) {
dwError = GetLastError();
utils::slog.e << "CreateWindowA() failed" << utils::io::endl;
LOG(ERROR) << "CreateWindowA() failed";
goto error;
}
@@ -117,8 +116,7 @@ Driver* PlatformWGL::createDriver(void* sharedGLContext,
tempContext = wglCreateContext(whdc);
if (!wglMakeCurrent(whdc, tempContext)) {
dwError = GetLastError();
utils::slog.e << "wglMakeCurrent() failed, whdc=" << whdc << ", tempContext=" <<
tempContext << utils::io::endl;
LOG(ERROR) << "wglMakeCurrent() failed, whdc=" << whdc << ", tempContext=" << tempContext;
goto error;
}
@@ -142,7 +140,7 @@ Driver* PlatformWGL::createDriver(void* sharedGLContext,
}
if (!mContext) {
utils::slog.e << "wglCreateContextAttribs() failed, whdc=" << whdc << utils::io::endl;
LOG(ERROR) << "wglCreateContextAttribs() failed, whdc=" << whdc;
goto error;
}
@@ -152,8 +150,7 @@ Driver* PlatformWGL::createDriver(void* sharedGLContext,
if (!wglMakeCurrent(whdc, mContext)) {
dwError = GetLastError();
utils::slog.e << "wglMakeCurrent() failed, whdc=" << whdc << ", mContext=" <<
mContext << utils::io::endl;
LOG(ERROR) << "wglMakeCurrent() failed, whdc=" << whdc << ", mContext=" << mContext;
goto error;
}
@@ -262,7 +259,7 @@ void PlatformWGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
}
bool PlatformWGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept {
SwapChain* readSwapChain) {
ASSERT_PRECONDITION_NON_FATAL(drawSwapChain == readSwapChain,
"PlatformWGL does not support distinct draw/read swap chains.");
@@ -47,7 +47,7 @@ void PlatformWebGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
}
bool PlatformWebGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept {
SwapChain* readSwapChain) {
return true;
}
@@ -40,7 +40,7 @@ inline void blitFast(VulkanCommandBuffer* commands, VkImageAspectFlags aspect, V
FVK_LOGD << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
<< " layout=" << src.getLayout()
<< " to=" << dst.texture->getVkImage() << ",level=" << (int) dst.level
<< " layout=" << dst.getLayout() << utils::io::endl;
<< " layout=" << dst.getLayout();
}
VkImageSubresourceRange const srcRange = src.getSubresourceRange();
@@ -80,7 +80,7 @@ inline void resolveFast(VulkanCommandBuffer* commands, VkImageAspectFlags aspect
FVK_LOGD << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
<< " layout=" << src.getLayout()
<< " to=" << dst.texture->getVkImage() << ",level=" << (int) dst.level
<< " layout=" << dst.getLayout() << utils::io::endl;
<< " layout=" << dst.getLayout();
}
VkImageSubresourceRange const srcRange = src.getSubresourceRange();
@@ -1,137 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "VulkanBuffer.h"
#include "VulkanMemory.h"
#include <utils/Panic.h>
using namespace bluevk;
namespace filament::backend {
VulkanBuffer::VulkanBuffer(VmaAllocator allocator, VulkanStagePool& stagePool,
VkBufferUsageFlags usage, uint32_t numBytes)
: mAllocator(allocator),
mStagePool(stagePool),
mUsage(usage),
mUpdatedOffset(0),
mUpdatedBytes(0) {
// for now make sure that only 1 bit is set in usage
// (because loadFromCpu() assumes that somewhat)
assert_invariant(usage && !(usage & (usage - 1)));
// Create the VkBuffer.
VkBufferCreateInfo bufferInfo {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = numBytes,
.usage = usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT
};
VmaAllocationCreateInfo allocInfo { .usage = VMA_MEMORY_USAGE_GPU_ONLY };
vmaCreateBuffer(mAllocator, &bufferInfo, &allocInfo, &mGpuBuffer, &mGpuMemory, nullptr);
}
VulkanBuffer::~VulkanBuffer() {
vmaDestroyBuffer(mAllocator, mGpuBuffer, mGpuMemory);
}
void VulkanBuffer::loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint32_t byteOffset,
uint32_t numBytes) {
VulkanStage const* stage = mStagePool.acquireStage(numBytes);
void* mapped;
vmaMapMemory(mAllocator, stage->memory, &mapped);
memcpy(mapped, cpuData, numBytes);
vmaUnmapMemory(mAllocator, stage->memory);
vmaFlushAllocation(mAllocator, stage->memory, 0, numBytes);
// If there was a previous update, then we need to make sure the following write is properly
// synced with the previous read.
if (mUpdatedBytes > 0 &&
(byteOffset >= mUpdatedOffset && byteOffset <= (mUpdatedOffset + mUpdatedBytes))) {
VkAccessFlags srcAccess = 0;
VkPipelineStageFlags srcStage = 0;
if (mUsage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
srcAccess = VK_ACCESS_SHADER_READ_BIT;
srcStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} else if (mUsage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) {
srcAccess = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
srcStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
} else if (mUsage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT) {
srcAccess = VK_ACCESS_INDEX_READ_BIT;
srcStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
}
VkBufferMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.srcAccessMask = srcAccess,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = mGpuBuffer,
.offset = byteOffset,
.size = numBytes,
};
vkCmdPipelineBarrier(cmdbuf, srcStage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1,
&barrier, 0, nullptr);
}
VkBufferCopy region = {
.srcOffset = 0,
.dstOffset = byteOffset,
.size = numBytes,
};
vkCmdCopyBuffer(cmdbuf, stage->buffer, mGpuBuffer, 1, &region);
mUpdatedOffset = byteOffset;
mUpdatedBytes = numBytes;
// Firstly, ensure that the copy finishes before the next draw call.
// Secondly, in case the user decides to upload another chunk (without ever using the first one)
// we need to ensure that this upload completes first (hence
// dstStageMask=VK_PIPELINE_STAGE_TRANSFER_BIT).
VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
if (mUsage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) {
dstAccessMask |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
} else if (mUsage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT) {
dstAccessMask |= VK_ACCESS_INDEX_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
} else if (mUsage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
} else if (mUsage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) {
// TODO: implement me
}
VkBufferMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = dstAccessMask,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = mGpuBuffer,
.offset = byteOffset,
.size = numBytes,
};
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0, 0, nullptr, 1,
&barrier, 0, nullptr);
}
} // namespace filament::backend
+22 -21
View File
@@ -17,35 +17,36 @@
#ifndef TNT_FILAMENT_BACKEND_VULKANBUFFER_H
#define TNT_FILAMENT_BACKEND_VULKANBUFFER_H
#include "VulkanContext.h"
#include "VulkanStagePool.h"
#include "VulkanMemory.h"
#include "memory/Resource.h"
#include <functional>
namespace filament::backend {
// Encapsulates a Vulkan buffer, its attached DeviceMemory and a staging area.
class VulkanBuffer {
class VulkanBuffer : public fvkmemory::Resource {
public:
VulkanBuffer(VmaAllocator allocator, VulkanStagePool& stagePool, VkBufferUsageFlags usage,
uint32_t numBytes);
~VulkanBuffer();
void loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint32_t byteOffset,
uint32_t numBytes);
VkBuffer getGpuBuffer() const {
return mGpuBuffer;
// Because we need to recycle the unused `VulkanGpuBuffer`, we allow for a callback that the
// "Pool" can use to acquire the buffer back.
using OnRecycle = std::function<void(VulkanGpuBuffer const*)>;
VulkanBuffer(VulkanGpuBuffer const* gpuBuffer, OnRecycle&& onRecycleFn)
: mGpuBuffer(gpuBuffer),
mOnRecycleFn(onRecycleFn) {}
~VulkanBuffer() {
if (mOnRecycleFn) {
mOnRecycleFn(mGpuBuffer);
}
}
private:
VmaAllocator mAllocator;
VulkanStagePool& mStagePool;
VulkanGpuBuffer const* getGpuBuffer() const { return mGpuBuffer; }
VmaAllocation mGpuMemory = VK_NULL_HANDLE;
VkBuffer mGpuBuffer = VK_NULL_HANDLE;
VkBufferUsageFlags mUsage = {};
uint32_t mUpdatedOffset = 0;
uint32_t mUpdatedBytes = 0;
private:
VulkanGpuBuffer const* mGpuBuffer;
OnRecycle mOnRecycleFn;
};
} // namespace filament::backend
}// namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_VULKANBUFFER_H
#endif// TNT_FILAMENT_BACKEND_VULKANBUFFER_H
@@ -0,0 +1,207 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "VulkanBufferCache.h"
#include "VulkanBuffer.h"
#include "VulkanConstants.h"
#include "VulkanMemory.h"
#include "memory/Resource.h"
#include "memory/ResourceManager.h"
#include <utility>
namespace filament::backend {
namespace {
VkBufferUsageFlags getVkBufferUsage(VulkanBufferUsage usage) {
switch (usage) {
case VulkanBufferUsage::VERTEX:
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
case VulkanBufferUsage::INDEX:
return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
case VulkanBufferUsage::UNIFORM:
return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
case VulkanBufferUsage::SHADER_STORAGE:
return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
case VulkanBufferUsage::UNKNOWN:
return 0;
}
return 0;
}
}// namespace
VulkanBufferCache::VulkanBufferCache(VulkanContext const& context,
fvkmemory::ResourceManager& resourceManager, VmaAllocator allocator)
: mContext(context),
mResourceManager(resourceManager),
mAllocator(allocator) {}
fvkmemory::resource_ptr<VulkanBuffer> VulkanBufferCache::acquire(VulkanBufferUsage usage,
uint32_t numBytes) noexcept {
assert_invariant(usage != VulkanBufferUsage::UNKNOWN);
BufferPool& bufferPool = getPool(usage);
// First check if an allocation exists whose capacity is greater than or equal to the requested
// size.
auto iter = bufferPool.lower_bound(numBytes);
if (iter != bufferPool.end()) {
VulkanGpuBuffer const* gpuBuffer = iter->second.gpuBuffer;
bufferPool.erase(iter);
return fvkmemory::resource_ptr<VulkanBuffer>::construct(&mResourceManager, gpuBuffer,
[this](VulkanGpuBuffer const* gpuBuffer) { this->release(gpuBuffer); });
}
// We were not able to find a sufficiently large allocation, so create a new one that is
// recycled after being yielded.
VulkanGpuBuffer const* gpuBuffer = allocate(usage, numBytes);
return fvkmemory::resource_ptr<VulkanBuffer>::construct(&mResourceManager, gpuBuffer,
[this](VulkanGpuBuffer const* gpuBuffer) { this->release(gpuBuffer); });
}
void VulkanBufferCache::gc() noexcept {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("VulkanBufferCache::gc");
// If this is one of the first few frames, return early to avoid wrapping unsigned integers.
constexpr uint32_t TIME_BEFORE_EVICTION = 3;
if (++mCurrentFrame <= TIME_BEFORE_EVICTION) {
return;
}
const uint64_t evictionTime = mCurrentFrame - TIME_BEFORE_EVICTION;
// Destroy buffers that have not been used for several frames.
for (auto& bufferPool: mGpuBufferPools) {
for (auto poolIter = bufferPool.begin(); poolIter != bufferPool.end();) {
if (poolIter->second.lastAccessed < evictionTime) {
#if FVK_ENABLED(FVK_DEBUG_VULKAN_BUFFER_CACHE)
FVK_LOGD << "VulkanBufferCache - Destroyed vkBuffer "
<< poolIter->second.gpuBuffer->vkbuffer << " with usage "
<< static_cast<int>(poolIter->second.gpuBuffer->usage) << utils::io::endl;
#endif// FVK_DEBUG_VULKAN_BUFFER_CACHE
destroy(poolIter->second.gpuBuffer);
poolIter = bufferPool.erase(poolIter);
} else {
++poolIter;
}
}
}
FVK_SYSTRACE_END();
}
void VulkanBufferCache::terminate() noexcept {
for (auto& bufferPool: mGpuBufferPools) {
for (auto& poolEntry: bufferPool) {
destroy(poolEntry.second.gpuBuffer);
}
bufferPool.clear();
}
}
void VulkanBufferCache::release(VulkanGpuBuffer const* gpuBuffer) noexcept {
assert_invariant(gpuBuffer != nullptr);
BufferPool& bufferPool = getPool(gpuBuffer->usage);
bufferPool.insert(std::make_pair(gpuBuffer->numBytes, UnusedGpuBuffer{
.lastAccessed = mCurrentFrame,
.gpuBuffer = gpuBuffer,
}));
}
VulkanGpuBuffer const* VulkanBufferCache::allocate(VulkanBufferUsage usage,
uint32_t numBytes) noexcept {
VkBufferCreateInfo const bufferInfo{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = numBytes,
// `VK_BUFFER_USAGE_TRANSFER_DST_BIT` is needed to allow updating the buffer through
// a staging using `vkCmdCopyBuffer`.
.usage = getVkBufferUsage(usage) | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
};
VmaAllocationCreateFlags vmaFlags = 0;
if (usage == VulkanBufferUsage::UNIFORM) {
// In the case of UMA, the uniform buffers will always be mappable
if (mContext.isUnifiedMemoryArchitecture()) {
vmaFlags |= VMA_ALLOCATION_CREATE_MAPPED_BIT |
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
}
}
VulkanGpuBuffer* gpuBuffer = new VulkanGpuBuffer{
.numBytes = numBytes,
.usage = usage,
};
VmaAllocationCreateInfo const allocInfo{
.flags = vmaFlags,
.usage = VMA_MEMORY_USAGE_AUTO,
.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
};
UTILS_UNUSED_IN_RELEASE VkResult result = vmaCreateBuffer(mAllocator, &bufferInfo, &allocInfo,
&gpuBuffer->vkbuffer, &gpuBuffer->vmaAllocation, &gpuBuffer->allocationInfo);
#if FVK_ENABLED(FVK_DEBUG_VULKAN_BUFFER_CACHE)
if (result != VK_SUCCESS) {
FVK_LOGE << "VulkanBufferCache - failed to allocate a new vkBuffer of size " << numBytes
<< " and usage " << static_cast<int>(usage) << ", error: " << result
<< utils::io::endl;
} else {
FVK_LOGD << "VulkanBufferCache - allocated a vkBuffer " << gpuBuffer->vkbuffer
<< " of size " << numBytes << " and usage = " << static_cast<int>(usage)
<< " successfully" << utils::io::endl;
}
#endif// FVK_DEBUG_VULKAN_BUFFER_CACHE
return gpuBuffer;
}
void VulkanBufferCache::destroy(VulkanGpuBuffer const* gpuBuffer) noexcept {
vmaDestroyBuffer(mAllocator, gpuBuffer->vkbuffer, gpuBuffer->vmaAllocation);
delete gpuBuffer;
gpuBuffer = nullptr;
}
VulkanBufferCache::BufferPool& VulkanBufferCache::getPool(VulkanBufferUsage usage) noexcept {
int poolIndex = -1;
switch (usage) {
case VulkanBufferUsage::VERTEX:
poolIndex = 0;
break;
case VulkanBufferUsage::INDEX:
poolIndex = 1;
break;
case VulkanBufferUsage::UNIFORM:
poolIndex = 2;
break;
case VulkanBufferUsage::SHADER_STORAGE:
poolIndex = 3;
break;
case VulkanBufferUsage::UNKNOWN:
PANIC_LOG("There's no pool for buffers with unkown usage.");
break;
}
assert_invariant(poolIndex >= 0 && poolIndex < MAX_POOL_COUNT);
return mGpuBufferPools[poolIndex];
}
}// namespace filament::backend
@@ -0,0 +1,84 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_BACKEND_VULKANBUFFERCACHE_H
#define TNT_FILAMENT_BACKEND_VULKANBUFFERCACHE_H
#include "VulkanBuffer.h"
#include "VulkanContext.h"
#include "VulkanMemory.h"
#include "memory/Resource.h"
#include "memory/ResourceManager.h"
#include <map>
namespace filament::backend {
class VulkanBufferCache {
public:
VulkanBufferCache(VulkanContext const& context, fvkmemory::ResourceManager& resourceManager,
VmaAllocator allocator);
// `VulkanBufferCache` is not copyable.
VulkanBufferCache(const VulkanBufferCache&) = delete;
VulkanBufferCache& operator=(const VulkanBufferCache&) = delete;
// Allocates or reuse a new VkBuffer that is device local.
// In the case of Unified memory architecture, uniform buffers are also host visible.
fvkmemory::resource_ptr<VulkanBuffer> acquire(VulkanBufferUsage usage,
uint32_t numBytes) noexcept;
// Evicts old unused `VulkanGpuBuffer` and bumps the current frame number
void gc() noexcept;
// Destroys all unused `VulkanGpuBuffer`.
// This should be called while the context's VkDevice is still alive.
void terminate() noexcept;
private:
struct UnusedGpuBuffer {
uint64_t lastAccessed;
VulkanGpuBuffer const* gpuBuffer;
};
using BufferPool = std::multimap<uint32_t, UnusedGpuBuffer>;
// Return a `VulkanGpuBuffer` back to its corresponding pool
void release(VulkanGpuBuffer const* gpuBuffer) noexcept;
// Allocate a new VkBuffer from the VMA pool of the corresponding `numBytes` and `usage`.
VulkanGpuBuffer const* allocate(VulkanBufferUsage usage, uint32_t numBytes) noexcept;
// Destroy the corresponding VkBuffer and return the VkDeviceMemory to the VMA pool.
void destroy(VulkanGpuBuffer const* gpuBuffer) noexcept;
BufferPool& getPool(VulkanBufferUsage usage) noexcept;
VulkanContext const& mContext;
fvkmemory::ResourceManager& mResourceManager;
VmaAllocator mAllocator;
// Buffers can be recycled, after they are released. Each type of buffer have its own pool
static constexpr int MAX_POOL_COUNT = 4;
BufferPool mGpuBufferPools[MAX_POOL_COUNT];
// Store the current "time" (really just a frame count) and LRU eviction parameters.
uint64_t mCurrentFrame = 0;
};
}// namespace filament::backend
#endif// TNT_FILAMENT_BACKEND_VULKANBUFFERCACHE_H
@@ -0,0 +1,163 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "VulkanBufferProxy.h"
#include "VulkanBufferCache.h"
#include "VulkanCommands.h"
#include "VulkanContext.h"
#include "VulkanMemory.h"
using namespace bluevk;
namespace filament::backend {
VulkanBufferProxy::VulkanBufferProxy(VmaAllocator allocator, VulkanStagePool& stagePool,
VulkanBufferCache& bufferCache, VulkanBufferUsage usage, uint32_t numBytes)
: mAllocator(allocator),
mStagePool(stagePool),
mBufferCache(bufferCache),
mBuffer(mBufferCache.acquire(usage, numBytes)),
mUpdatedOffset(0),
mUpdatedBytes(0) {}
void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* cpuData,
uint32_t byteOffset, uint32_t numBytes) {
// The VulkanBuffer is available if the only object reference is hold by the
// `VulkanBufferProxy`. This means that the buffer is not currently referenced by a
// `VulkanCommandBuffer`.
bool const isAvailable = mBuffer->getCount() == 1;
if (isAvailable) {
// We are up to date with all the update operations, so no need to synchronize with previous
// updates.
mUpdatedBytes = 0;
mUpdatedOffset = 0;
}
// Keep track of the VulkanBuffer usage
commands.acquire(mBuffer);
// Check if we can just memcpy directly to the GPU memory.
// This is only allowed for UNIFORMS that are AVAILABLE and the memory is HOST_VISIBLE
// (supports memcpy from host). This works regardless if it's a full or partial update of the
// buffer.
bool const isMemcopyable = mBuffer->getGpuBuffer()->allocationInfo.pMappedData != nullptr;
bool const isUniform = getUsage() == VulkanBufferUsage::UNIFORM;
bool const useMemcpy =
isUniform && isMemcopyable && isAvailable && !FVK_FORCE_STAGING_FOR_BUFFER_UPDATES;
if (useMemcpy) {
char* dest = static_cast<char*>(mBuffer->getGpuBuffer()->allocationInfo.pMappedData) +
byteOffset;
memcpy(dest, cpuData, numBytes);
vmaFlushAllocation(mAllocator, mBuffer->getGpuBuffer()->vmaAllocation, byteOffset,
numBytes);
return;
}
// Note: this should be stored within the command buffer before going out of
// scope, so that the command buffer can manage its lifecycle.
fvkmemory::resource_ptr<VulkanStage::Segment> stage = mStagePool.acquireStage(numBytes);
assert_invariant(stage->memory());
commands.acquire(stage);
memcpy(stage->mapping(), cpuData, numBytes);
vmaFlushAllocation(mAllocator, stage->memory(), stage->offset(), numBytes);
// If there was a previous update, then we need to make sure the following write is properly
// synced with the previous read.
if (mUpdatedBytes > 0 &&
(byteOffset >= mUpdatedOffset && byteOffset <= (mUpdatedOffset + mUpdatedBytes))) {
VkAccessFlags srcAccess = 0;
VkPipelineStageFlags srcStage = 0;
if (getUsage() == VulkanBufferUsage::UNIFORM) {
srcAccess = VK_ACCESS_SHADER_READ_BIT;
srcStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} else if (getUsage() == VulkanBufferUsage::VERTEX) {
srcAccess = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
srcStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
} else if (getUsage() == VulkanBufferUsage::INDEX) {
srcAccess = VK_ACCESS_INDEX_READ_BIT;
srcStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
}
VkBufferMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.srcAccessMask = srcAccess,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = getVkBuffer(),
.offset = byteOffset,
.size = numBytes,
};
vkCmdPipelineBarrier(commands.buffer(), srcStage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0,
nullptr, 1, &barrier, 0, nullptr);
}
VkBufferCopy region = {
.srcOffset = stage->offset(),
.dstOffset = byteOffset,
.size = numBytes,
};
vkCmdCopyBuffer(commands.buffer(), stage->buffer(), getVkBuffer(), 1, &region);
mUpdatedOffset = byteOffset;
mUpdatedBytes = numBytes;
// Firstly, ensure that the copy finishes before the next draw call.
// Secondly, in case the user decides to upload another chunk (without ever using the first one)
// we need to ensure that this upload completes first (hence
// dstStageMask=VK_PIPELINE_STAGE_TRANSFER_BIT).
VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
if (getUsage() == VulkanBufferUsage::VERTEX) {
dstAccessMask |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
} else if (getUsage() == VulkanBufferUsage::INDEX) {
dstAccessMask |= VK_ACCESS_INDEX_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
} else if (getUsage() == VulkanBufferUsage::UNIFORM) {
dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
} else if (getUsage() == VulkanBufferUsage::SHADER_STORAGE) {
// TODO: implement me
}
VkBufferMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = dstAccessMask,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = getVkBuffer(),
.offset = byteOffset,
.size = numBytes,
};
vkCmdPipelineBarrier(commands.buffer(), VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0, 0,
nullptr, 1, &barrier, 0, nullptr);
}
VkBuffer VulkanBufferProxy::getVkBuffer() const noexcept {
return mBuffer->getGpuBuffer()->vkbuffer;
}
VulkanBufferUsage VulkanBufferProxy::getUsage() const noexcept {
return mBuffer->getGpuBuffer()->usage;
}
} // namespace filament::backend
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_BACKEND_VULKANBUFFERPROXY_H
#define TNT_FILAMENT_BACKEND_VULKANBUFFERPROXY_H
#include "VulkanBufferCache.h"
#include "VulkanCommands.h"
#include "VulkanContext.h"
#include "VulkanMemory.h"
#include "VulkanStagePool.h"
namespace filament::backend {
// This class acts as a dynamic wrapper for a `VulkanBuffer`. It allows you to modify the
// `VulkanBuffer` it references at runtime, wihtout affecting any external objects.
class VulkanBufferProxy {
public:
VulkanBufferProxy(VmaAllocator allocator, VulkanStagePool& stagePool,
VulkanBufferCache& bufferCache, VulkanBufferUsage usage, uint32_t numBytes);
void loadFromCpu(VulkanCommandBuffer& commands, const void* cpuData, uint32_t byteOffset,
uint32_t numBytes);
VkBuffer getVkBuffer() const noexcept;
VulkanBufferUsage getUsage() const noexcept;
private:
VmaAllocator mAllocator;
VulkanStagePool& mStagePool;
VulkanBufferCache& mBufferCache;
fvkmemory::resource_ptr<VulkanBuffer> mBuffer;
uint32_t mUpdatedOffset = 0;
uint32_t mUpdatedBytes = 0;
};
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_VULKANBUFFERPROXY_H
@@ -215,7 +215,7 @@ VkSemaphore VulkanCommandBuffer::submit() {
}
FVK_LOGI << ") "
<< " signal=" << mSubmission
<< " fence=" << mFence << utils::io::endl;
<< " fence=" << mFence;
#endif
mFenceStatus->setStatus(VK_NOT_READY);
@@ -224,7 +224,7 @@ VkSemaphore VulkanCommandBuffer::submit() {
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
if (result != VK_SUCCESS) {
FVK_LOGD << "Failed command buffer submission result: " << result << utils::io::endl;
FVK_LOGD << "Failed command buffer submission result: " << result;
}
#endif
assert_invariant(result == VK_SUCCESS);
@@ -490,7 +490,7 @@ void VulkanCommands::pushGroupMarker(char const* str, VulkanGroupMarkers::Timest
mProtectedPool->pushMarker(str, timestamp);
}
#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS)
FVK_LOGD << "----> " << str << utils::io::endl;
FVK_LOGD << "----> " << str;
#endif
}
@@ -502,8 +502,7 @@ void VulkanCommands::popGroupMarker() {
auto const& startTime = ret.second;
auto const endTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = endTime - startTime;
FVK_LOGD << "<---- " << marker << " elapsed: " << (diff.count() * 1000) << " ms"
<< utils::io::endl;
FVK_LOGD << "<---- " << marker << " elapsed: " << (diff.count() * 1000) << " ms";
#else
mPool->popMarker();
#endif // FVK_DEBUG_PRINT_GROUP_MARKERS
+14 -8
View File
@@ -17,7 +17,7 @@
#ifndef TNT_FILAMENT_BACKEND_VULKANCONSTANTS_H
#define TNT_FILAMENT_BACKEND_VULKANCONSTANTS_H
#include <utils/Log.h>
#include <utils/Logger.h>
#include <stdint.h>
@@ -73,14 +73,16 @@
#define FVK_DEBUG_RESOURCE_LEAK 0x00010000
// Set this to enable logging "only" to one output stream. This is useful in the case where we want
// to debug with print statements and want ordered logging (e.g slog.i and slog.e will not appear in
// order of calls).
// to debug with print statements and want ordered logging (e.g LOG(INFO) and LOG(ERROR) will not
// appear in order of calls).
#define FVK_DEBUG_FORCE_LOG_TO_I 0x00020000
// Enable a minimal set of traces to assess the performance of the backend.
// All other debug features must be disabled.
#define FVK_DEBUG_PROFILING 0x00040000
#define FVK_DEBUG_VULKAN_BUFFER_CACHE 0x00080000
// Useful default combinations
#define FVK_DEBUG_EVERYTHING (0xFFFFFFFF & ~FVK_DEBUG_PROFILING)
#define FVK_DEBUG_PERFORMANCE \
@@ -172,15 +174,15 @@ static_assert(FVK_ENABLED(FVK_DEBUG_VALIDATION));
#endif
#if FVK_ENABLED(FVK_DEBUG_FORCE_LOG_TO_I)
#define FVK_LOGI (utils::slog.i)
#define FVK_LOGI LOG(INFO)
#define FVK_LOGD FVK_LOGI
#define FVK_LOGE FVK_LOGI
#define FVK_LOGW FVK_LOGI
#else
#define FVK_LOGE (utils::slog.e)
#define FVK_LOGW (utils::slog.w)
#define FVK_LOGD (utils::slog.d)
#define FVK_LOGI (utils::slog.i)
#define FVK_LOGE LOG(ERROR)
#define FVK_LOGW LOG(WARNING)
#define FVK_LOGD DLOG(INFO)
#define FVK_LOGI LOG(INFO)
#endif
// All vkCreate* functions take an optional allocator. For now we select the default allocator by
@@ -212,4 +214,8 @@ constexpr static const int FVK_MAX_PIPELINE_AGE = FVK_MAX_COMMAND_BUFFERS;
// destroying any unused pipeline object.
static_assert(FVK_MAX_PIPELINE_AGE >= FVK_MAX_COMMAND_BUFFERS);
// Whether the buffer updates always use staging or not. Otherwise its allowed to also use memcpy
// for buffer updates. Default is false
constexpr static const bool FVK_FORCE_STAGING_FOR_BUFFER_UPDATES = false;
#endif
+5 -5
View File
@@ -71,23 +71,23 @@ struct VulkanRenderPass {
struct VulkanContext {
public:
static uint32_t selectMemoryType(VkPhysicalDeviceMemoryProperties const& memoryProperties,
uint32_t flags, VkFlags reqs) {
uint32_t types, VkFlags reqs) {
for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
if (flags & 1) {
if (types & 1) {
if ((memoryProperties.memoryTypes[i].propertyFlags & reqs) == reqs) {
return i;
}
}
flags >>= 1;
types >>= 1;
}
return (uint32_t) VK_MAX_MEMORY_TYPES;
}
inline uint32_t selectMemoryType(uint32_t flags, VkFlags reqs) const {
inline uint32_t selectMemoryType(uint32_t types, VkFlags reqs) const {
if ((reqs & VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0) {
assert_invariant(isProtectedMemorySupported());
}
return selectMemoryType(mMemoryProperties, flags, reqs);
return selectMemoryType(mMemoryProperties, types, reqs);
}
inline fvkutils::VkFormatList const& getAttachmentDepthStencilFormats() const {
@@ -320,7 +320,7 @@ void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr<VulkanDescri
uint8_t binding, fvkmemory::resource_ptr<VulkanBufferObject> bufferObject,
VkDeviceSize offset, VkDeviceSize size) noexcept {
VkDescriptorBufferInfo const info = {
.buffer = bufferObject->buffer.getGpuBuffer(),
.buffer = bufferObject->buffer.getVkBuffer(),
.offset = offset,
.range = size,
};
+59 -44
View File
@@ -19,7 +19,8 @@
#include "CommandStreamDispatcher.h"
#include "SystraceProfile.h"
#include "VulkanAsyncHandles.h"
#include "VulkanBuffer.h"
#include "VulkanBufferCache.h"
#include "VulkanBufferProxy.h"
#include "VulkanCommands.h"
#include "VulkanDriverFactory.h"
#include "VulkanHandles.h"
@@ -84,7 +85,11 @@ VmaAllocator createAllocator(VkInstance instance, VkPhysicalDevice physicalDevic
.vkGetImageMemoryRequirements2KHR = vkGetImageMemoryRequirements2KHR
#endif
};
VmaAllocatorCreateInfo const allocatorInfo {
VmaAllocatorCreateInfo const allocatorInfo{
// Disable the internal VMA synchronization because the backend is singled threaded.
// Improve CPU performance when using VMA functions. The backend will guarantee that all
// access to VMA is done in a thread safe way.
.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT,
.physicalDevice = physicalDevice,
.device = device,
.pVulkanFunctions = &funcs,
@@ -99,15 +104,15 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallback(VkDebugReportFlagsEXT flags,
VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location,
int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) {
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
FVK_LOGE << "VULKAN ERROR: (" << pLayerPrefix << ") " << pMessage << utils::io::endl;
FVK_LOGE << "VULKAN ERROR: (" << pLayerPrefix << ") " << pMessage;
} else {
// TODO: emit best practices warnings about aggressive pipeline barriers.
if (strstr(pMessage, "ALL_GRAPHICS_BIT") || strstr(pMessage, "ALL_COMMANDS_BIT")) {
return VK_FALSE;
}
FVK_LOGW << "VULKAN WARNING: (" << pLayerPrefix << ") " << pMessage << utils::io::endl;
FVK_LOGW << "VULKAN WARNING: (" << pLayerPrefix << ") " << pMessage;
}
FVK_LOGE << utils::io::endl;
FVK_LOGE;
return VK_FALSE;
}
#endif // FVK_ENABLED(FVK_DEBUG_VALIDATION)
@@ -117,18 +122,16 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsCallback(VkDebugUtilsMessageSeverityFla
VkDebugUtilsMessageTypeFlagsEXT types, const VkDebugUtilsMessengerCallbackDataEXT* cbdata,
void* pUserData) {
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
FVK_LOGE << "VULKAN ERROR: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage
<< utils::io::endl;
FVK_LOGE << "VULKAN ERROR: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage;
} else {
// TODO: emit best practices warnings about aggressive pipeline barriers.
if (strstr(cbdata->pMessage, "ALL_GRAPHICS_BIT")
|| strstr(cbdata->pMessage, "ALL_COMMANDS_BIT")) {
return VK_FALSE;
}
FVK_LOGW << "VULKAN WARNING: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage
<< utils::io::endl;
FVK_LOGW << "VULKAN WARNING: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage;
}
FVK_LOGE << utils::io::endl;
FVK_LOGE << "";
return VK_FALSE;
}
#endif // FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
@@ -209,7 +212,8 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
mPlatform->getProtectedGraphicsQueueFamilyIndex(), &mContext),
mPipelineLayoutCache(mPlatform->getDevice()),
mPipelineCache(mPlatform->getDevice()),
mStagePool(mAllocator, &mCommands),
mStagePool(mAllocator, &mResourceManager, &mCommands, &mContext.getPhysicalDeviceLimits()),
mBufferCache(context, mResourceManager, mAllocator),
mFramebufferCache(mPlatform->getDevice()),
mYcbcrConversionCache(mPlatform->getDevice()),
mSamplerCache(mPlatform->getDevice()),
@@ -270,20 +274,18 @@ Driver* VulkanDriver::create(VulkanPlatform* platform, VulkanContext const& cont
// VulkanRenderTarget : 312 few
// -- less than or equal to 312 bytes
FVK_LOGD
<< "\nVulkanSwapChain: " << sizeof(VulkanSwapChain)
<< "\nVulkanBufferObject: " << sizeof(VulkanBufferObject)
<< "\nVulkanVertexBuffer: " << sizeof(VulkanVertexBuffer)
<< "\nVulkanVertexBufferInfo: " << sizeof(VulkanVertexBufferInfo)
<< "\nVulkanIndexBuffer: " << sizeof(VulkanIndexBuffer)
<< "\nVulkanRenderPrimitive: " << sizeof(VulkanRenderPrimitive)
<< "\nVulkanTexture: " << sizeof(VulkanTexture)
<< "\nVulkanTimerQuery: " << sizeof(VulkanTimerQuery)
<< "\nHwStream: " << sizeof(HwStream)
<< "\nVulkanRenderTarget: " << sizeof(VulkanRenderTarget)
<< "\nVulkanFence: " << sizeof(VulkanFence)
<< "\nVulkanProgram: " << sizeof(VulkanProgram)
<< utils::io::endl;
FVK_LOGD << "VulkanSwapChain: " << sizeof(VulkanSwapChain);
FVK_LOGD << "VulkanBufferObject: " << sizeof(VulkanBufferObject);
FVK_LOGD << "VulkanVertexBuffer: " << sizeof(VulkanVertexBuffer);
FVK_LOGD << "VulkanVertexBufferInfo: " << sizeof(VulkanVertexBufferInfo);
FVK_LOGD << "VulkanIndexBuffer: " << sizeof(VulkanIndexBuffer);
FVK_LOGD << "VulkanRenderPrimitive: " << sizeof(VulkanRenderPrimitive);
FVK_LOGD << "VulkanTexture: " << sizeof(VulkanTexture);
FVK_LOGD << "VulkanTimerQuery: " << sizeof(VulkanTimerQuery);
FVK_LOGD << "HwStream: " << sizeof(HwStream);
FVK_LOGD << "VulkanRenderTarget: " << sizeof(VulkanRenderTarget);
FVK_LOGD << "VulkanFence: " << sizeof(VulkanFence);
FVK_LOGD << "VulkanProgram: " << sizeof(VulkanProgram);
#endif
assert_invariant(platform);
@@ -328,7 +330,6 @@ void VulkanDriver::terminate() {
// descriptorSetLayoutCache
mExternalImageManager.terminate();
mStagePool.terminate();
mPipelineCache.terminate();
mFramebufferCache.terminate();
mSamplerCache.terminate();
@@ -339,6 +340,15 @@ void VulkanDriver::terminate() {
// Before terminating ResourceManager, we must make sure all of the resource_ptrs have been unset.
mResourceManager.terminate();
// Must come after `mResourceManager`.
// Before terminating the memory pool, we must make sure all the VulkanBufferMemory are yielded
// back to the pool.
mBufferCache.terminate();
// Before terminating stagePool, we need all resources to have been
// reclaimed, as they perform cleanup within the stage pool.
mStagePool.terminate();
#if FVK_ENABLED(FVK_DEBUG_RESOURCE_LEAK)
mResourceManager.print();
#endif
@@ -371,6 +381,7 @@ void VulkanDriver::collectGarbage() {
mCommands.gc();
mDescriptorSetCache.gc();
mStagePool.gc();
mBufferCache.gc();
mFramebufferCache.gc();
mPipelineCache.gc();
@@ -383,7 +394,13 @@ void VulkanDriver::collectGarbage() {
void VulkanDriver::beginFrame(int64_t monotonic_clock_ns,
int64_t refreshIntervalNs, uint32_t frameId) {
FVK_PROFILE_MARKER(PROFILE_NAME_BEGINFRAME);
// Do nothing.
// Check if any command have finished and reset all its used resources. The resources
// wont be destroyed but their reference count will decreased if the command is already
// completed.
//
// This will let us check if any VulkanBuffer is currently in flight or not.
mCommands.gc();
if (mAppState.hasExternalSamplers()) {
mExternalImageManager.onBeginFrame();
@@ -514,7 +531,7 @@ void VulkanDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType ele
FVK_SYSTRACE_SCOPE();
auto elementSize = (uint8_t) getElementTypeSize(elementType);
auto ib = resource_ptr<VulkanIndexBuffer>::make(&mResourceManager, ibh, mAllocator, mStagePool,
elementSize, indexCount);
mBufferCache, elementSize, indexCount);
ib.inc();
}
@@ -531,7 +548,7 @@ void VulkanDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
BufferObjectBinding bindingType, BufferUsage usage) {
FVK_SYSTRACE_SCOPE();
auto bo = resource_ptr<VulkanBufferObject>::make(&mResourceManager, boh, mAllocator, mStagePool,
byteCount, bindingType);
mBufferCache, byteCount, bindingType);
bo.inc();
}
@@ -784,14 +801,12 @@ void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
mResourceManager.gc();
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 && !isSRGBSwapChainSupported()) {
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it"
<< utils::io::endl;
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it";
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
}
if (flags & backend::SWAP_CHAIN_CONFIG_PROTECTED_CONTENT) {
if (!isProtectedContentSupported()) {
FVK_LOGW << "protected swapchain requested, but Platform does not support it"
<< utils::io::endl;
FVK_LOGW << "protected swapchain requested, but Platform does not support it";
}
}
auto swapChain = resource_ptr<VulkanSwapChain>::make(&mResourceManager, sch, mPlatform,
@@ -802,8 +817,7 @@ void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
uint32_t height, uint64_t flags) {
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 && !isSRGBSwapChainSupported()) {
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it"
<< utils::io::endl;
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it";
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
}
assert_invariant(width > 0 && height > 0 && "Vulkan requires non-zero swap chain dimensions.");
@@ -1223,12 +1237,13 @@ void VulkanDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor
VulkanCommandBuffer& commands = mCommands.get();
auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh);
commands.acquire(ib);
ib->buffer.loadFromCpu(commands.buffer(), p.buffer, byteOffset, p.size);
ib->buffer.loadFromCpu(commands, p.buffer, byteOffset, p.size);
scheduleDestroy(std::move(p));
}
void VulkanDriver::registerBufferObjectStreams(Handle<HwBufferObject> boh, BufferObjectStreamDescriptor&& streams) {
void VulkanDriver::registerBufferObjectStreams(Handle<HwBufferObject> boh,
BufferObjectStreamDescriptor&& streams) {
// Noop
}
@@ -1238,7 +1253,7 @@ void VulkanDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescript
auto bo = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh);
commands.acquire(bo);
bo->buffer.loadFromCpu(commands.buffer(), bd.buffer, byteOffset, bd.size);
bo->buffer.loadFromCpu(commands, bd.buffer, byteOffset, bd.size);
scheduleDestroy(std::move(bd));
}
@@ -1249,7 +1264,7 @@ void VulkanDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> boh,
auto bo = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh);
commands.acquire(bo);
// TODO: implement unsynchronized version
bo->buffer.loadFromCpu(commands.buffer(), bd.buffer, byteOffset, bd.size);
bo->buffer.loadFromCpu(commands, bd.buffer, byteOffset, bd.size);
scheduleDestroy(std::move(bd));
}
@@ -1291,7 +1306,7 @@ TimerQueryResult VulkanDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint
uint64_t const end = results.endTime;
if (begin >= end) {
// TODO: queries might have ran on different command buffers.
FVK_LOGW << "Timestamps are not monotonically increasing. " << utils::io::endl;
FVK_LOGW << "Timestamps are not monotonically increasing. ";
*elapsedTime = 0;
return TimerQueryResult::ERROR;
}
@@ -1622,8 +1637,8 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y
mReadPixels.run(
srcTarget, x, y, width, height, mPlatform->getGraphicsQueueFamilyIndex(),
std::move(pbd),
[&context = mContext](uint32_t reqs, VkFlags flags) {
return context.selectMemoryType(reqs, flags);
[&context = mContext](uint32_t types, VkFlags reqs) {
return context.selectMemoryType(types, reqs);
},
[this](PixelBufferDescriptor&& pbd) {
scheduleDestroy(std::move(pbd));
@@ -1898,7 +1913,7 @@ void VulkanDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
// avoid rebinding these if they are already bound, but since we do not (yet) support subranges
// it would be rare for a client to make consecutive draw calls with the same render primitive.
vkCmdBindVertexBuffers(cmdbuffer, 0, bufferCount, buffers, offsets);
vkCmdBindIndexBuffer(cmdbuffer, prim->indexBuffer->buffer.getGpuBuffer(), 0,
vkCmdBindIndexBuffer(cmdbuffer, prim->indexBuffer->buffer.getVkBuffer(), 0,
prim->indexBuffer->indexType);
}
@@ -2029,7 +2044,7 @@ void VulkanDriver::debugCommandBegin(CommandStream* cmds, bool synchronous, cons
assert_invariant(inRenderPass);
inRenderPass = false;
} else if (inRenderPass && OUTSIDE_COMMANDS.find(command) != OUTSIDE_COMMANDS.end()) {
FVK_LOGE << command.data() << " issued inside a render pass." << utils::io::endl;
FVK_LOGE << command.data() << " issued inside a render pass.";
}
#endif
}
+4 -1
View File
@@ -18,15 +18,17 @@
#define TNT_FILAMENT_BACKEND_VULKANDRIVER_H
#include "VulkanBlitter.h"
#include "VulkanBufferCache.h"
#include "VulkanConstants.h"
#include "VulkanContext.h"
#include "VulkanFboCache.h"
#include "VulkanHandles.h"
#include "VulkanMemory.h"
#include "VulkanPipelineCache.h"
#include "VulkanQueryManager.h"
#include "VulkanReadPixels.h"
#include "VulkanSamplerCache.h"
#include "VulkanStagePool.h"
#include "VulkanQueryManager.h"
#include "VulkanYcbcrConversionCache.h"
#include "vulkan/VulkanDescriptorSetCache.h"
#include "vulkan/VulkanDescriptorSetLayoutCache.h"
@@ -138,6 +140,7 @@ private:
VulkanPipelineLayoutCache mPipelineLayoutCache;
VulkanPipelineCache mPipelineCache;
VulkanStagePool mStagePool;
VulkanBufferCache mBufferCache;
VulkanFboCache mFramebufferCache;
VulkanYcbcrConversionCache mYcbcrConversionCache;
VulkanSamplerCache mSamplerCache;

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