google / filament

Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WebGL2
https://google.github.io/filament/
Apache License 2.0
17.36k stars 1.84k forks source link

Uniform buffer loads fail on Metal backend on Intel GPUs #7588

Open palver123 opened 4 months ago

palver123 commented 4 months ago

Describe the bug There are visible shadow artifacts when using the Metal backend with Intel GPUs. Based on our investigations the root cause is that uniform buffer loads sometimes fail. I could repro it on tag v1.49.0 but on current main too.

To Reproduce Just run gltf_viewer sample with FILAMENT_FORCE_INTEGRATED_GPU=1 on a device which has Intel GPU (default view settings).

Expected behavior No visual artifacts.

Screenshots https://github.com/google/filament/assets/12460850/8783e405-9dd4-4d4f-91c4-4a4cd0a91dfd

Logs The actual log is spammed with warnings because SPIRV-Cross generates unused variables in Metal shaders. I hope this is enough:

FEngine (64 bits) created at 0x10c024c00 (threading is enabled)
FEngine resolved backend: Metal
2024-02-21 21:49:09.908852+0100 gltf_viewer[22812:97578] Metal GPU Frame Capture Enabled
2024-02-21 21:49:09.909171+0100 gltf_viewer[22812:97578] Metal API Validation Enabled
Selected physical device 'Intel(R) UHD Graphics 630'
Supported GPU families: 
  MTLGPUFamilyCommon3
  MTLGPUFamilyMac2
Features:
  readWriteTextureSupport: true
Backend feature level: 3
FEngine feature level: 3

Desktop (please complete the following information):

Additional context Here's a screenshot of an Xcode frame capture of gltf_viewer sample with the DamagedHelmet model. This is a draw call from the shadow pass. initObjectUniforms() can see the per-renderable UBO (see highlighted variables at the bottom) but the thread local variables (e.g. object_uniforms_worldFromModelNormalMatrix) contain zeros at the end of the function. This is not the only affected draw call, only the first of them. Here it's related to the UBO containing an array, so setting FILAMENT_HAS_FEATURE_INSTANCING to false fixes this particular draw call, but the issue reappears around SSAO. image

The currently accessible Metal Feature Set Tables says Mac2 family GPUs use 32 byte alignment (see Minimum constant buffer offset alignment) but Apple originally recommended 256, they just changed it ~2 years ago (I can attach the old Metal Feature Set Tables.pdf, if interested). Filament uses 32 bytes too for Mac2 GPUs. We were suspecting UBO alignment issues but setting METAL_CONSTANT_BUFFER_OFFSET_ALIGNMENT to 256 doesn't help.

Any ideas what could this be?

palver123 commented 4 months ago

For the record this doesn't happen on the AMD and Apple GPUs we tested on macOS

palver123 commented 4 months ago

Filament uses very high slot numbers for UBOs on Metal: UNIFORM_BUFFER_BINDING_START is 17. Based on the Metal Feature Set Tables, the Maximum number of constant buffer arguments in vertex, fragment, tile, or kernel function is 14 (for Mac2 GPUs), so we experimented with setting UNIFORM_BUFFER_BINDING_START to 1 to fit into the the 0..13 UBO slot range. Didn't help either.

palver123 commented 4 months ago

I forgot to mention that none of these issues were reproducible in v1.12.8. Of course, there was no instancing support before v1.24.0 so that explains why initObjectUniforms() didn't cause a problem back then.