Compare commits

..
Author SHA1 Message Date
Benjamin Doherty d273838e07 Merge branch 'rc/1.49.0' into release 2023-12-11 00:13:00 -08:00
Benjamin Doherty a1de8c924d Update RELEASE_NOTES 2023-12-11 00:09:20 -08:00
Benjamin Doherty 72765a5b0a Fix bump-version script on Darwin 2023-12-10 19:52:39 -08:00
Benjamin Doherty e1beabaa98 Bump MATERIAL_VERSION to 49 2023-12-10 19:43:28 -08:00
Eliza Velasquez ebaee14b8b Generate dummy skinning variants for FL0 mats
Even if skinning is not fully implemented on FL0, we have clients which depend
on materials with skinning variants that otherwise could easily be converted to
FL0 materials. There are two proper ways to deal with this:

1. Support skinning/morphing in Feature Level 0.

2. Allow ESSL 1.0 code and ESSL 3.0 code to support different sets of variants.

However, the simplest solution is to just include skinning/morphing variants,
but disable codegen for ESSL 1.0 code, making them identical to the base
variants. This shouldn't increase the file size much due to the dictionary
deflation. Of course, skinning will not work correctly on FL0, but this has
always been the case. Future work here would be to properly implement one of the
two solutions described above.
2023-12-10 19:19:17 -08:00
Powei Feng d4f08dafbb vk: workaround swiftshader spirv no-op issue (#7417)
Swiftshader runs spirv validation before compilation. However,
the validation does not like having Nop (no-op) in the input.
So we skip instructions instead of writing no-op for the
output of `workaroundSpecConstant`.

Also, fix issue to keep the value in the original shader if a
specialization wasn't provided.
2023-12-08 12:05:20 -08:00
Powei Feng 753fb102c4 spirv-headers: fix failed headers check (#7416)
Due to a cmake misconfiguration, we are installing spirv as part
of the release, public headers. It's now corrected.
2023-12-08 12:05:12 -08:00
Powei Feng b219113a55 vk: spec const workaround through runtime spirv modification (#7399)
To avoid driver edge cases with spec const, we manually change the
spec const into a regular constant in the spirv.

FIXES=310603393
2023-12-08 12:05:03 -08:00
Sungun Park 9140d44b29 Bump version to 1.49.0 2023-12-05 11:39:05 -08:00
Sungun Park 8b0d65768a Merge branch 'rc/1.48.0' into release 2023-12-05 11:34:11 -08:00
Powei Feng 349bf7be38 Update MATERIAL_VERSION to 48 2023-12-01 11:01:36 -08:00
Powei Feng a01d282f14 Add intermediate.h include to builtinResource.h (#7388) 2023-12-01 11:00:08 -08:00
Powei Feng 3c3296a114 Bump version to 1.48.0 2023-11-27 14:22:16 -08:00
Powei Feng 61501ba122 Merge branch 'rc/1.47.0' into release 2023-11-27 14:20:27 -08:00
Powei Feng 99ba40e965 Update MATERIAL_VERSION to 47 2023-11-27 19:40:34 +00:00
Eliza Velasquez 4116af7971 Enable optimizations for ESSL 1.0 code
The CL introducing the ESSL 1.0 chunk in materials inadvertently disabled
optimizations for said code. This commit reintroduces those optimizations and
fixes associated bugs which manifested. In particular, spirv-cross was
generating uints for bools; this has been fixed with a hack. Additionally,
spirv-cross is now compiled with exceptions enabled so that matc can gracefully
fail and show the code which failed to compile rather than abruptly aborting.
2023-11-27 19:32:59 +00:00
Eliza Velasquez 2fab93faff Fix typo in depth_main.fs 2023-11-27 19:32:47 +00:00
Eliza Velasquez b92c5cab07 Incorporate feedback 2023-11-27 19:32:34 +00:00
Eliza Velasquez 8ed9678cbe Update NEW_RELEASE_NOTES.md 2023-11-27 19:32:21 +00:00
Eliza Velasquez 731e52a3c1 Add option to matc to disable ESSL 1.0 codegen 2023-11-27 19:32:03 +00:00
Eliza Velasquez 687b6da800 Enable preprocessor optimization of ESSL 1.0
Since #7358 is blocked by an upstream spirv-cross issue, we can at least do a
bit of preprocessor optimization for ESSL 1.0 code in the meantime and introduce
the FILAMENT_EFFECTIVE_VERSION preprocessor definitions.
2023-11-27 19:31:52 +00:00
Ben Doherty 64f4c097ac Remove debug code in MetalShaderCompiler (#7368) 2023-11-15 13:55:34 -08:00
Powei Feng 0191e1fe46 Bump version to 1.47.0 2023-11-14 21:38:45 -08:00
Powei Feng 21093067db Merge branch 'rc/1.46.0' into release 2023-11-14 21:34:54 -08:00
Eliza Velasquez 1b10e7d4f3 Add FILAMENT_ENABLE_FEATURE_LEVEL_0 option
This allows clients to selectively exclude feature level 0 support.
2023-11-14 16:52:26 -08:00
Eliza Velasquez 5b2d3ac225 Fix some ES2 issues
Fix specification of mipmaps when generating textures.

Fix oversight where emulated UBOs would not replace uniforms when swapped out
for another.
2023-11-14 16:29:23 -08:00
Antonio MaioranoandPowei Feng 422dfcc1e6 Add missing include for latest glslang (#7365)
This change in glslang removes the include of "intermediate.h" from
GlslangToSpv.h:
https://github.com/KhronosGroup/glslang/commit/62de186c3383feef067feb6ea578f79977910722

As a result, the definition of "class TIntermediate" is removed, and
will fail compilation of MaterialCompiler.cpp when glslang is updated to
a version including the aforementioned change. We fix this by adding an
explicit include to this header in MaterialCompiler.cpp.

Co-authored-by: Powei Feng <powei@google.com>
2023-11-14 16:00:34 -08:00
Powei Feng 0d304393f4 Small compilation fixes (#7363)
- gltfio: Enable -Wall -Werror for gltfio_core
 - gltfio: Fix various errors that were missed warnings
 - matdbg: switch from std::atomic_uint64_t to
   std::atomic<uint64_t> for older clang
2023-11-14 14:21:52 -08:00
Mathias Agopian 57aa99e964 Fix (again) the shadow transform
- we were not using the correct field in ShadowMapManager
- we were not computing the transform correctly, it should applied
  after the local transform, not before.

FIXES=[299310624]
2023-11-13 22:29:52 -08:00
Mathias Agopian cfc133fcf1 repair visible shadow status
FIXES=[309519433]
2023-11-13 22:29:26 -08:00
Powei Feng 8eade6be1f Revert "engine: move setFrontFaceWindingInverted from View to MaterialInstance (#7331)" (#7360)
This reverts commit 038f07cb34.
2023-11-13 22:27:56 -08:00
Powei Feng 2250664e58 Update Material_VERSION to 46 2023-11-13 10:40:02 -08:00
Benjamin Doherty 8a27cc8b7f Bump version to 1.46.0 2023-11-09 10:11:39 -08:00
Benjamin Doherty d786d59ea1 Merge branch 'rc/1.45.1' into release 2023-11-09 10:09:56 -08:00
Ben Doherty 79116905aa Fix mix-precision quaternion conversions (#7339) 2023-11-08 12:38:23 -08:00
Benjamin Doherty 763950ec18 Revert "fix a couple shadow stability bugs"
This reverts commit 1b0db0fca2.
2023-11-08 12:33:24 -08:00
Mathias Agopian 13571868de don't use a spinlock for the HandleArena
We've seen hangs/ANR that are not well understood on that spinlock, so
for now we're going back to mutexes, which, on android, are very 
efficient under low contention (no syscall).

FIXES=[308029108]
2023-10-30 15:16:01 -07:00
Mathias Agopian 0f2c89b140 improvements to EntityManagers and Filament APIs (#7302)
* prevent public classes from being created on the stack

- we used to to this by deleting operator delete, but this prevented
  the internal "F" classes from being virtual; which can be useful
  when using EntityManger::Listener.
  now we just make the destructor protected in each class.

- EntityManger::Listener now has a virtual destructor so that
  objects could be correctly destroyed from Listener*

* improve EntityManger and Component managers

- all component managers now have the same "base" API
    - getComponentCount()
	- empty()
    - getEntity()
    - getEntities()

- Scene now has getEntityCount()

- EntityManager now has getEntityCount()

- all component manager implement gc() the same way, by calling destroy()

- SingleInstanceComponentManager::gc() that calls removeComponent() has
  been removed because it's dangerous. removeComponent() is often
  not enough, some additional cleanup might be needed.
2023-10-30 15:15:00 -07:00
Mathias Agopian f8b70e8ec5 fix a Transform component leak in CameraManager
CameraManager creates a Transform component for each Camera component
is not already present. However, it didn't destroy the transform
component when it's itself destroyed. the leaked transform component
would eventually be garbage collected, but caused significant
slow down and memory pressure. This is because camera components are
created every frame for the shadow maps.

FIXES=[303914944]
2023-10-30 15:14:52 -07:00
Mathias Agopian 7abdea5a2e improve BlobCache API and compatibility
- the insert and retrieve handlers can now be set/unset independently.
  this could be useful for debugging.

- program caching is disabled if the GL implementation doesn't support it.

- removed unused code

FIXES=[307549547]
2023-10-30 15:13:28 -07:00
Powei Feng cb3e808e8d Bump version to 1.45.1 2023-10-25 15:18:59 -07:00
Powei Feng b2e0b97bad Merge branch 'rc/1.45.0' into release 2023-10-25 15:16:19 -07:00
Mathias Agopian 9c0cbed214 OpenGLBlobCache: be more robust when shader fails to compile
- don't call BlobCache if link status false
- don't assume glGetProgramiv never fails
- don't assume malloc never fails

FIXES=[307549547]
2023-10-24 20:45:52 -07:00
Powei Feng c531a9c077 filamat: Fix MaterialInfo::userMaterialHasCustomDepth init (#7292)
Leaving it uninitialized leads to msan failure.
2023-10-24 20:45:34 -07:00
Powei Feng 2a1f762e23 Update MATERIAL_VERSION to 45 2023-10-22 22:19:41 -07:00
Ben Doherty 4dd98e63e4 Create use-after-free detector for Metal textures (#7250) 2023-10-20 17:16:55 -04:00
Ben Doherty 1b7187f427 Support stencil buffer when post-processing is disabled (#7227) 2023-10-20 17:08:30 -04:00
Benjamin Doherty 0dddd94eab Fix missing SkinningBuffer include 2023-10-18 13:45:08 -07:00
Benjamin Doherty 2ef0244266 Fix build failures due to filamat lite removal 2023-10-13 11:34:47 -07:00
Ben Doherty 0774bf9501 Remove problematic GlslangToSpv option: emitNonSemanticShaderDebugInfo (#7260) 2023-10-13 09:37:56 -07:00
Ben Doherty 8f5b2fd230 Update glslang to 277d09e679f0f4d9469c463c00cb11c6a040e65f (#7261) 2023-10-13 09:37:49 -07:00
Benjamin Doherty 274191036f Bump version to 1.45.0 2023-10-02 15:29:31 -07:00
Benjamin Doherty 13afbc2876 Merge branch 'rc/1.44.0' into release 2023-10-02 15:27:51 -07:00
Eliza Velasquez a7bb0a60fb Revert "Remove now-redundant feature level 0 materials"
This reverts most of commit 9a6b8bf24e. The hello
triangle sample remains unreverted.

The original commit inadvertently broke screen space reflections, and perhaps
other features when the default material was used. The source of the issue is
that MaterialBuilder.cpp (correctly) filters out variants that aren't supported
in feature level 0 materials, including screen space reflections.

Unfortunately, while the "feature level 0 compatibility" feature itself was
intended to make creating duplicate materials like this redundant in client
code, unfortunately, it seems the best solution for resolving this issue is to
simply keep these redundant materials in the core.

To elaborate: clients should expect that feature level 0 materials that they
create work on /all/ feature levels /exactly/ or /close to exactly/ identically.
This includes restricting more advanced features that theoretically could be
available on a higher feature level, like SSR. It's already true that if a user
would like to optionally opt-in to a more advanced material which takes
advantage of more advanced features, they would have to maintain two separate
versions of that material: one for feature level 3 and one for feature level 1.
It should be no different in this case.

However, the materials built into the engine core are an exception to this
expectation. Given that feature level 0 was tacked on after the fact with fewer
features, there must /by necessity/ have been a new material introduced for both
the default material and the default skybox specifically for feature level 0
with fewer features than extant client apps expected to be included by default.
I imagine if filament were to be rebuilt from the ground up, this exception
wouldn't exist. However, the end result is this somewhat messy redundancy.
2023-09-29 16:49:40 -07:00
Powei Feng 0650b13358 vk: remove uneeded log in readpixels 2023-09-28 15:27:17 -07:00
Powei Feng 6cd851e77e Update MATERIAL_VERSION to 44 2023-09-28 15:27:06 -07:00
Powei Feng 87a8cb3872 Bump version to 1.44.0 2023-09-27 11:30:16 -07:00
Powei Feng a4869eaf19 Merge branch 'rc/1.43.1' into release 2023-09-27 11:11:53 -07:00
Powei Feng 1740220f6a Update MATERIAL_VERSION to 43 2023-09-25 10:10:25 -07:00
Benjamin Doherty 5deccffdce Bump version to 1.43.1 2023-09-18 14:23:12 -07:00
Benjamin Doherty a76eacba67 Merge branch 'rc/1.43.0' into release 2023-09-18 14:22:06 -07:00
Benjamin Doherty ee31ca6fc0 Fix RELEASE_NOTES version 2023-09-18 14:20:30 -07:00
Benjamin Doherty 7dd6686087 Correct version to 1.43.0 2023-09-18 11:07:05 -07:00
Powei Feng fdffd93949 vulkan: fix fence deadlock (#7173)
Should only reset fences in VulkanCommands::gc
2023-09-14 17:11:49 -07:00
Powei Feng f0a0a9b2e1 Bump version to 1.42.3 2023-09-13 23:05:11 -07:00
Powei Feng e743e9243f Merge branch 'rc/1.42.2' into release 2023-09-13 22:59:52 -07:00
Powei Feng 8e13d53b1e vulkan: fix swapchain leak (#7161) 2023-09-11 23:23:04 -07:00
Ben Doherty ff274c8387 Fix incorrect SamplerParams operators (#7150) 2023-09-11 22:47:25 -07:00
Benjamin Doherty e08e1c209b Bump version to 1.42.2 2023-09-07 17:59:26 -07:00
Benjamin Doherty de310ed9ad Merge branch 'rc/1.42.1' into release 2023-09-07 17:55:24 -07:00
Powei Feng d01b29fa01 vulkan: properly set bool spec onst (#7125)
We wrote a bool directly into 4 bytes (as the first byte). This has two issues:
 - the other 3 bytes are not initialized
 - should be writing VK_TRUE/FALSE instead
2023-09-01 14:17:18 -07:00
Mathias Agopian 8cba3d4366 Revert "workaround another PowerVR compiler bug "
This reverts commit 58f96be2c4.

This caused material files to increase in size significantly. It turns
out that glslang has to generate a copy for each parameter that is
passed to a function as a non-const parameter.


This revert will break IMG devices again, but that should be the case
only on debug builds. Release builds lose the const qualifier by 
virtue of going through spirv. We'll try to address this some other 
way later.
2023-09-01 14:16:59 -07:00
Ben Doherty be1e51ad91 Update FrameCompletedCallback using directive (#7128) 2023-08-30 16:29:28 -07:00
Ben Doherty 29ce1cad84 Transition setFrameCompletedCallback to take a CallbackHandler (#7103) 2023-08-30 16:28:53 -07:00
Ben Doherty 6a967ad007 Make destroyFence asynchronous (#7127) 2023-08-30 16:28:36 -07:00
Powei Feng fe2bb3d9a4 Merge branch 'rc/1.42.0' into release 2023-08-28 13:26:35 -07:00
Mathias Agopian cd7973bdcf Revert "workaround another PowerVR compiler bug "
This reverts commit 58f96be2c4.

This caused material files to increase in size significantly. It turns
out that glslang has to generate a copy for each parameter that is
passed to a function as a non-const parameter.


This revert will break IMG devices again, but that should be the case
only on debug builds. Release builds lose the const qualifier by 
virtue of going through spirv. We'll try to address this some other 
way later.
2023-08-28 10:43:26 -07:00
Powei Feng e6384e0e92 Bump version to 1.42.1 2023-08-22 13:41:42 -07:00
Powei Feng e63dc17f54 Fix missing createFence (#7076)
Continuing from #7072
2023-08-21 10:59:42 -07:00
Powei Feng af338cf2ec Update MaterialEnums.h (#7098) 2023-08-21 10:52:25 -07:00
Benjamin Doherty f1d8a04337 Bump version to 1.42.0 2023-08-15 17:13:50 -07:00
Benjamin Doherty b13497e2a0 Merge branch 'rc/1.41.0' into release 2023-08-15 17:12:01 -07:00
Powei Feng 175c9f9966 Bump version to 1.41.0 2023-08-09 10:43:02 -07:00
Powei Feng 1a50420b46 Merge branch 'rc/1.40.5' into release 2023-08-09 10:32:50 -07:00
Powei Feng bbad75a012 vulkan: fix fence initialization (#7038)
Previously, we have a VulkanSync with a default constructor that
allows us to have sync objects that returns error when
actual fences are not yet present.  We need to replicate that
with VulkanFence since sync objects have been removed from the
API.

Fixes #7034
2023-08-07 10:17:15 -07:00
Powei Feng 25c08f19e3 vulkan: fix TSAN in readpixels (#7023) (#7028) 2023-08-02 11:00:48 -07:00
Benjamin Doherty 59063fb7b4 Bump version to 1.40.5 2023-08-01 15:39:35 -07:00
Benjamin Doherty 71f60de0ad Merge branch 'rc/1.40.4' into release 2023-08-01 15:38:37 -07:00
Powei Feng 743661109d vulkan: fix TSAN in readpixels 2023-08-01 15:35:06 -07:00
Benjamin Doherty 5014cbb023 Bump version to 1.40.4 2023-07-26 12:53:47 -07:00
Benjamin Doherty 4142e7a1cf Merge branch 'rc/1.40.3' into release 2023-07-26 12:52:12 -07:00
Benjamin Doherty a721e648b7 Bump version to 1.40.3 2023-07-17 15:50:20 -06:00
Benjamin Doherty 358e89ef08 Merge branch 'rc/1.40.2' into release 2023-07-17 15:49:29 -06:00
Benjamin Doherty e023e90e7a Bump version to 1.40.2 2023-07-12 13:44:52 -07:00
Benjamin Doherty a5b5b0c3a7 Merge branch 'rc/1.40.1' into release 2023-07-12 13:43:33 -07:00
Powei Feng b7b4d3c295 Update Material version to match 1.40.1 2023-07-10 14:27:51 -07:00
Benjamin Doherty a445c4e156 Merge branch 'rc/1.40.0' into release 2023-06-26 13:29:06 +08:00
Benjamin Doherty 1432c59499 Add missing atomic header 2023-06-26 13:23:38 +08:00
Benjamin Doherty 4c7c10fad0 Bump version to 1.40.1 2023-06-26 13:17:45 +08:00
Benjamin Doherty 7c8a0d1967 Bump MATERIAL_VERSION to 40 2023-06-26 10:33:02 +08:00
Powei Feng 11fbacea20 Update MaterialEnums.h to v39 2023-06-20 11:57:42 -07:00
Powei Feng 8cd70454c3 Update MaterialEnums.h to v39 2023-06-20 11:56:40 -07:00
Benjamin Doherty 1d988182fc Bump version to 1.40.0 2023-06-20 23:55:00 +08:00
Benjamin Doherty dba49f00df Merge branch 'rc/1.39.0' into release 2023-06-20 23:45:04 +08:00
Ben Doherty 89c0b44da9 Re-enable Metal half conversion, only register SimplificationPasses for Metal (#6883) 2023-06-20 14:27:44 +08:00
Ben Doherty 4f450fd5c4 Temporarily disable Metal relaxed to half pass due to spirv-cross bug (#6880) 2023-06-20 14:27:37 +08:00
Mathias Agopian f0943cfca2 align uniform buffer to 16 bytes
this is needed on armv7 because we use alignas to get strcture-alignment,
but that also implies (to the compiler) that the structure itself
is aligned properly.
2023-06-20 14:23:47 +08:00
Mathias Agopian 9aa52b79d4 helpers to fix jank when resizing a TextureView (#6889)
There was two related issues:
- we need to "latch" the new TextureView size when its resized. That
  can only be done by recreating the EGLSurface (i.e. recreating the
  SwapChain). UiHelper now calls onNativeWindowChanged in the case of
  the TextureView resize, so clients can recreate their SwapChain.
- we also needed to make sure that all current filament frames have
  finished to render (i.e. the last eglSwapBuffers has been called) so
  that they don't pick-up a new size (this happens after
  eglSwapBuffers) that doesn't match the viewport.

Fixes b/282220665
2023-06-12 23:13:48 -07:00
Powei Feng a82125dbbd vulkan: minor fixes (#6874)
- flush() and wait() before destroying a swapchain
 - Make sure the debug marker extension is enabled under correct
   circumstances.
 - Change shared_ptrs to unique_ptrs and raw pointers.
 - Rename most teardown methods to terminate()
2023-06-07 11:45:09 -07:00
Benjamin Doherty 24fcb299b5 Bump version to 1.39.0 2023-06-07 11:32:33 -05:00
Benjamin Doherty 753aa9ca61 Merge branch 'rc/1.38.0' into release 2023-06-07 11:31:21 -05:00
Benjamin Doherty a33eada7ec Bump version to 1.38.0 2023-06-07 11:29:02 -05:00
Benjamin Doherty 676a2be874 Correct MATERIAL_VERSION to 37 2023-06-05 17:20:18 -05:00
Powei Feng c95d466cdd Fix missing include (#6858) 2023-06-01 16:28:05 -07:00
Powei Feng 3d8ac384ad Update MATERIAL_VERSION to 38 (#6852) (#6854) 2023-05-31 15:00:34 -07:00
Powei Feng 57424cc7e9 Merge branch 'rc/1.37.0' into release 2023-05-30 16:22:31 -07:00
Powei Feng 78fe4ba547 vulkan: allow for headless linux builds (#6836) 2023-05-24 17:19:42 -07:00
Benjamin Doherty a3d25cd22b Bump version to 1.37.0 2023-05-15 16:57:27 -07:00
Benjamin Doherty 56bf841bac Merge branch 'rc/1.36.0' into release 2023-05-15 16:55:48 -07:00
Ben Doherty dfdf0db794 Fix incorrect target passed to glBindFramebuffer (#6807) 2023-05-15 15:28:44 -07:00
Benjamin Doherty bf6bd4eca8 Fix Android CI release build 2023-05-09 13:22:47 -04:00
Benjamin Doherty 36c69dda9c Fix Android CI release build 2023-05-09 13:22:20 -04:00
Benjamin Doherty f14fdc11f5 Bump MATERIAL_VERSION to 36 2023-05-08 18:07:13 -04:00
Benjamin Doherty 0157487b1f Bump version to 1.36.0 2023-05-08 18:06:59 -04:00
Benjamin Doherty 1716c856c3 Merge branch 'rc/1.35.0' into release 2023-05-08 18:05:07 -04:00
Benjamin Doherty 31521c70c2 Fix Android CI release build 2023-05-01 18:45:34 -04:00
Benjamin Doherty 8cac90d81e Bump MATERIAL_VERSION to 35 2023-05-01 13:37:24 -04:00
Benjamin Doherty 388b4f5efb Bump version to 1.35.0 2023-05-01 13:36:40 -04:00
Benjamin Doherty f9b5a7f301 Merge branch 'rc/1.34.0' into release 2023-05-01 13:35:16 -04:00
Benjamin Doherty 00c78cc225 Bump MATERIAL_VERSION to 34 2023-05-01 12:20:50 -04:00
Powei Feng 2bdb8b560c vulkan: fix RenderPass size (#6775) (#6776) 2023-04-27 14:09:46 -07:00
Benjamin Doherty a974fddd4c Bump version to 1.34.0 2023-04-25 13:10:24 -04:00
Benjamin Doherty 83a3e243da Merge branch 'rc/1.33.0' into release 2023-04-25 13:09:13 -04:00
Benjamin Doherty f286e308bf Bump version to 1.33.0 2023-04-19 14:11:43 -04:00
Benjamin Doherty 29af3be2e3 Merge branch 'rc/1.32.4' into release 2023-04-19 14:10:10 -04:00
Mathias Agopian 6623dcbebf fix specification constant injection in glsl
- boolean where handled as int
- always cast float to float()
2023-04-17 10:29:02 -04:00
Powei Feng 89dc43f361 vulkan: fix spec constant bool size 2023-04-17 10:28:44 -04:00
Ben Doherty b77aac43ea Fix float spec constant formatting (#6731) 2023-04-17 10:28:24 -04:00
Benjamin Doherty 0d63fa02ee Fix build when exceptions disabled 2023-04-17 10:28:00 -04:00
Benjamin Doherty e187bc442d Bump version to 1.32.4 2023-04-11 11:19:53 -07:00
Benjamin Doherty d62268fbfb Merge branch 'rc/1.32.3' into release 2023-04-11 11:17:47 -07:00
Benjamin Doherty 3b73e3de60 Bump version to 1.32.3 2023-04-05 12:56:23 -07:00
Benjamin Doherty 7685736d6c Merge branch 'rc/1.32.2' into release 2023-04-05 12:55:12 -07:00
Benjamin Doherty b8a3a7f221 Bump version to 1.32.2 2023-04-05 12:53:18 -07:00
Benjamin Doherty 732628acf5 Merge branch 'rc/1.32.1' into release 2023-03-21 15:48:49 -07:00
Powei Feng 7bd00d2b30 Revert "vulkan: async readPixels (#6605)" (#6644)
This reverts commit 6f25e8ae5a.

Reason for revert: breaks clients that were expecting synchronous readPixels for vulkan
2023-03-16 13:05:48 -07:00
Benjamin Doherty 0759797e61 Include atomic in VulkanCommands.h 2023-03-15 11:15:24 -07:00
Benjamin Doherty fddc5160c7 Bump version to 1.32.1 2023-03-14 10:48:50 -07:00
Benjamin Doherty 2a579c460f Merge branch 'rc/1.32.0' into release 2023-03-14 10:46:27 -07:00
Ben Doherty efdc801cff Vulkan: fix stack use-after-free (#6639) 2023-03-14 10:24:18 -07:00
Benjamin Doherty dd654c575a Bump MATERIAL_VERSION to 32 2023-03-13 14:04:13 -07:00
Benjamin Doherty 0c2599b6ca Bump version to 1.32.0 2023-03-09 10:40:39 -08:00
Benjamin Doherty 979d6742e0 Merge branch 'rc/1.31.7' into release 2023-03-09 10:39:41 -08:00
Mathias Agopian 4a7a033d04 Fix timer query breakage on webgl 2023-03-08 12:33:11 -08:00
Ben Doherty 5c2bbcb4a1 Remove compute shader assertion in GLProgram 2023-03-08 10:56:24 -08:00
Benjamin Doherty dec903a0ee Bump version to 1.31.7 2023-03-01 11:26:50 -08:00
Benjamin Doherty e9475b322b Merge branch 'rc/1.31.6' into release 2023-03-01 11:24:13 -08:00
Benjamin Doherty d9aead8aac Linux CI: use clang 14 2023-02-21 16:06:48 -08:00
Powei Feng ce148ebeb1 Update linux clang to version 10 (#6556) 2023-02-21 16:00:07 -08:00
Powei Feng e1315fbaa7 Update CI Ubuntu version 2023-02-21 15:57:00 -08:00
Benjamin Doherty 1690549392 Bump version to 1.31.6 2023-02-21 13:18:22 -08:00
Benjamin Doherty c73710e343 Merge branch 'rc/1.31.5' into release 2023-02-21 13:16:47 -08:00
Benjamin Doherty 092a0489da Bump version to 1.31.5 2023-02-13 11:53:24 -08:00
Benjamin Doherty 1c6279366f Merge branch 'rc/1.31.4' into release 2023-02-13 11:51:37 -08:00
Benjamin Doherty 2ac85049a9 Bump version to 1.31.4 2023-02-01 11:55:09 -08:00
Benjamin Doherty ea428a27d1 Merge branch 'rc/1.31.3' into release 2023-02-01 11:54:04 -08:00
Benjamin Doherty 3bef718238 Bump version to 1.31.3 2023-01-24 14:28:21 -08:00
Benjamin Doherty e9daaa0503 Merge branch 'rc/1.31.2' into release 2023-01-24 14:27:02 -08:00
Benjamin Doherty 6d3ea21993 Bump version to 1.31.2 2023-01-18 14:25:45 -08:00
Benjamin Doherty f39127605d Merge branch 'rc/1.31.1' into release 2023-01-18 14:23:59 -08:00
Ben Doherty db476f00f7 Vulkan: fix stack-use-after-scope ASAN error in VulkanContext.cpp (#6463) 2023-01-18 11:59:10 -08:00
Powei Feng e54d8ec0a4 [vulkan] enumerate: Returning size = 0 is ok (#6450) 2023-01-17 10:14:45 -08:00
Benjamin Doherty b95ac854b4 Bump version to 1.31.1 2023-01-10 12:52:49 -05:00
Benjamin Doherty 96443f6dac Merge branch 'rc/1.31.0' into release 2023-01-10 12:50:52 -05:00
Benjamin Doherty e5e3dff9fa Fix Windows CI build 2022-12-20 11:01:49 -07:00
Benjamin Doherty 31d9da38fd Fix CI build 2022-12-20 09:40:07 -07:00
Benjamin Doherty c5a59bb6b1 Bump version to 1.31.0 2022-12-19 11:14:41 -08:00
Benjamin Doherty e6854148d7 Merge branch 'rc/1.30.0' into release 2022-12-19 11:12:54 -08:00
Ben Doherty 001daf0350 Fix memory leak in Scene (#6387) 2022-12-16 14:38:38 -08:00
Mathias Agopian d26c48110d Fix Android continuous and presubmit builds
Since cmake 3.25 LINUX is automatically set based on CMAKE_SYSTEM_NAME, 
which the android cmake files are setting to "Linux". This created an
inconsistant state in our build system.
2022-12-15 11:54:33 -08:00
Mathias Agopian 15a070f0c9 Fix unused variables in release builds 2022-12-12 11:17:42 -08:00
Mathias Agopian 93230b06cf Fix Android continuous and presubmit builds
Since cmake 3.25 LINUX is automatically set based on CMAKE_SYSTEM_NAME, 
which the android cmake files are setting to "Linux". This created an
inconsistant state in our build system.
2022-12-12 10:44:49 -08:00
Mathias Agopian 4c55fc3c48 fix TransformManager high precision mode
The residual would be corrupted when using transactions.
2022-12-12 10:06:18 -08:00
Mathias Agopian a4797a631e Fix a WebGL program link failure
WebGL complained about:

Precisions of uniform block 'ShadowUniforms' member
'ShadowUniforms.shadows.texelSizeAtOneMeter' differ between VERTEX and
FRAGMENT shaders.


this field didn't have a precision qualifier, this might be specific to
WebGL or a Chrome bug, unsure. Either we fix it by specifying all
qualifiers.
2022-11-29 23:32:21 -08:00
Mathias Agopian 5868e857aa Fix a WebGL program link failure
WebGL complained about:

Precisions of uniform block 'ShadowUniforms' member 
'ShadowUniforms.shadows.texelSizeAtOneMeter' differ between VERTEX and 
FRAGMENT shaders.


this field didn't have a precision qualifier, this might be specific to
WebGL or a Chrome bug, unsure. Either we fix it by specifying all
qualifiers.
2022-11-29 23:31:03 -08:00
Benjamin Doherty 32ba063bd7 Fix CI build 2022-11-21 16:58:37 -08:00
Benjamin Doherty 02f0839f9b Bump version to 1.30.0 2022-11-21 15:45:27 -08:00
Benjamin Doherty e50f3c4c91 Merge branch 'rc/1.29.0' into release 2022-11-21 15:44:36 -08:00
Ben Doherty 7ca15bfc16 Use GitHub script for release asset upload (#6308) 2022-11-21 15:39:55 -08:00
Benjamin Doherty b7b7afb62a Bump version to 1.29.0 2022-11-09 16:43:08 -08:00
Benjamin Doherty b8ff6a9ad9 Merge branch 'rc/1.28.3' into release 2022-11-09 16:38:02 -08:00
Ben Doherty a1dcb4f259 Skip rendering renderables with missing geometry (#6281) 2022-11-09 16:35:31 -08:00
Benjamin Doherty c3501393fd Fix RELEASE_NOTES 2022-11-09 16:34:42 -08:00
Benjamin Doherty a03de75a4e Update Python requirements.txt to fix CI 2022-11-04 11:35:21 -07:00
Benjamin Doherty 0c3d59aba3 Update Python requirements.txt to fix CI 2022-11-03 16:15:29 -07:00
Benjamin Doherty ce1987f291 Fix iOS build 2022-11-01 15:10:57 -04:00
Benjamin Doherty 7eae926ed7 Bump version to 1.28.3 2022-11-01 13:03:19 -04:00
Benjamin Doherty 606af52eda Merge branch 'rc/1.28.2' into release 2022-11-01 13:02:05 -04:00
Benjamin Doherty 8ea30aea80 Update RELEASE_NOTES for 1.28.2 2022-11-01 13:00:04 -04:00
Ben Doherty 72dea695ba Fix G3 reported ubsan warning (#6257) 2022-11-01 12:52:10 -04:00
daemyung jang 1c0cf56ed0 Fix glTF breaking issue (#6239) 2022-10-28 13:08:50 -04:00
Benjamin Doherty bcb4eb35cd Bump version to 1.28.2 2022-10-25 13:09:21 -04:00
Benjamin Doherty bce2676335 Merge branch 'rc/1.28.1' into release 2022-10-25 13:08:12 -04:00
Benjamin Doherty 510097d722 Force spirv-cross to keep Metal argument buffer equal sized 2022-10-25 12:10:54 -04:00
Ben Doherty 5784118a12 Fix, don't use encoder.device (#6212) 2022-10-20 13:08:04 -04:00
Ben Doherty b5de0f2d23 Metal: fix simulator regression due to arg buffers (#6181) 2022-10-18 16:29:18 -04:00
Ben Doherty 04df3f4dad Metal: fix use-after-free ASAN error (#6203) 2022-10-18 16:29:12 -04:00
Benjamin Doherty 093ca4d623 Revert Android API_LEVEL change
glDispatchCompute requires Android API level 21, however bumping our
required minimum from 19 to 21 caused some clients' builds to fail.
Commenting-out that line for now to proceed with the 1.28.0 upgrade.
2022-10-18 16:28:58 -04:00
Mathias Agopian a3ed1558d3 fix a directional light shadowing issue
the shadow frustum could be be smaller than expected.
2022-10-14 15:42:03 -07:00
Benjamin Doherty fe379070ae Bump version to 1.28.1 2022-10-13 12:38:40 -04:00
Benjamin Doherty ead0a2f597 Merge branch 'rc/1.28.0' into release 2022-10-13 12:37:07 -04:00
Benjamin Doherty 5dbc593f90 Fix assertion in ShadowMap due to vertexCount 2022-10-12 18:16:53 -04:00
Ben Doherty d47dc12bf0 G3 fixes for 1.28.0 (#6174) 2022-10-12 14:48:37 -04:00
Philip Rideout 4392f63e57 Vulkan: fix black screen regression
The VulkanProgram constructor was bailing out early and emitting a
warning because it saw that one of the stages wasn't fulfilled.
However it's okay for a pipeline to be missing a compute program.

Fixes regression that started with fabba73b1.
2022-10-12 14:48:25 -04:00
Ben Doherty f64b7aca79 Fix Metal argument buffer encoding (#6150) 2022-10-10 10:07:41 -07:00
Ben Doherty 3762ec5750 Fix Android release build (#6133) 2022-09-30 11:48:13 -07:00
Ben Doherty 4591fdd9c0 Fix Android release build (#6133) 2022-09-30 11:47:41 -07:00
Benjamin Doherty d3068d2a0e Bump version to 1.28.0 2022-09-29 13:13:18 -07:00
Benjamin Doherty ca0a4bc23a Merge branch 'rc/1.27.2' into release 2022-09-29 13:12:20 -07:00
Ben Doherty 433c163c61 Fixes for 1.27.2 release (#6125) 2022-09-29 13:08:39 -07:00
Mathias Agopian c867fda883 don't attempt to use more texture units than present
to emulate the bindless API in the gl backend we always used the highest
texture unit available. However at feature level 3, we support up to 62
textures, so the that max was bumped to 62 -- however, where we're not
on a feature level 2 device, that texture unit doesn't exist.

Instead we now always use binding 31, which is guaranteed to exist by 
EGL's minspec.
2022-09-29 12:36:28 -07:00
Ben Doherty 566540ae6d Fix generic/Mutex.h not installed on Linux (#6117) 2022-09-28 16:49:03 -07:00
Benjamin Doherty 759f490dae Bump version to 1.27.2 2022-09-20 11:06:02 -07:00
Benjamin Doherty 867d4d44f5 Merge branch 'rc/1.27.1' into release 2022-09-20 11:04:58 -07:00
Ben Doherty 65747d5877 Update glslang to c0cf8ad87 (master) (#6076) 2022-09-19 12:38:05 -07:00
Benjamin Doherty bd357f6076 Bump version to 1.27.1 2022-09-13 10:15:12 -07:00
Benjamin Doherty 9e960b7d45 Merge branch 'rc/1.27.0' into release 2022-09-13 10:14:24 -07:00
Ben Doherty 0c54d4a6a1 Add return case to fix G3 compiler error (#6062) 2022-09-12 12:34:56 -07:00
Philip Rideout 526e846a81 gltfio: fix crash when material is unspecified 2022-09-06 22:13:19 -04:00
Philip Rideout 8bcfa373d4 gltfio: do not clear out the texture slots too early.
This broke asyncGetLoadProgress() and caused WebGL to crash reliably
because ResourceLoader got destroyed too soon.

Bug was introduced with de7dfc2ea6.

I intend to cherry pick this to rc/1.27.0, which is where it was
introduced, so there's no need to update the release notes.
2022-09-06 22:09:25 -04:00
Ben Doherty db9a0f2c1f Fix uberarchive not included in PodSpec (#6024) 2022-09-01 12:18:20 -04:00
Benjamin Doherty 646b1e2193 Bump version to 1.27.0 2022-08-31 12:04:55 -04:00
Benjamin Doherty 41bd30f81d Merge branch 'rc/1.26.0' into release 2022-08-31 12:04:08 -04:00
Mathias Agopian bd626aea27 material instanced property must be false by default.
this fix auto-instancing.
2022-08-26 18:28:56 -04:00
Benjamin Doherty 8a03f75485 Bump version to 1.26.0 2022-08-23 12:07:33 -04:00
Benjamin Doherty dc9594fbdf Merge branch 'rc/1.25.6' into release 2022-08-23 12:05:44 -04:00
Benjamin Doherty fad0b533c0 Update RELEASE_NOTES for 1.25.6 2022-08-23 12:03:28 -04:00
Benjamin Doherty 4d773e9453 Bump version to 1.25.6 2022-08-16 11:03:07 -07:00
Benjamin Doherty e0c610b013 Merge branch 'rc/1.25.5' into release 2022-08-16 11:01:04 -07:00
Benjamin Doherty 0da4f36c33 Bump version to 1.25.5 2022-08-16 10:54:00 -07:00
Ben Doherty 11d17e1db3 Fix SamplerGroup update issue (#5928) 2022-08-16 10:47:18 -07:00
Philip Rideout b8c318d923 WASM: Allow clients to enable pthreads.
Filament does not yet fully support threads with WASM, but this is a
baby step in that direction.

To enable experimental pthreads support, enable the WEBGL_PTHREADS CMake
option. This will enable pthreads support in `gltfio` and `utils`, which
is known to work, but not when served with GitHub Pages.

The web server must emit COOP, COEP and CORP headers, so our build
instructions now recommend the use of `emrun` for local testing.

This also changes our demos so that they do not use unpkg, which
does not work when using `emrun`, due to cross-origin restrictions.
2022-08-12 15:43:28 -07:00
Philip Rideout e563cc6f5e gltfio: add 'detach' methods to allow ownership transfer
These new methods allow gltfio to be integrated into internal Google
libraries.
2022-08-09 14:37:44 -07:00
Benjamin Doherty cb8914ab96 Merge branch 'rc/1.25.4' into release 2022-08-02 11:47:52 -07:00
Alan Eneev 2fecda7bdc Headless EGL: Fallback to a 24-bit depth buffer 2022-07-29 10:10:46 -07:00
Alan Eneev 543d8efb25 Fix PlatformEGLHeadless build and add a build.sh option to build EGL
I have disabled building SDL with headless EGL, because
SDL_config_minimal.h doesn't work with EGL, and I don't know how to
implement a an SDL config that would work with EGL.

I have verified that this works in a separate project, and that it
compiles in this project.

```
$ ./build.sh -e release
$ find ./out/ -name "*EGL*"
./out/cmake-release/filament/backend/CMakeFiles/backend.dir/src/opengl/platforms/PlatformEGL.cpp.o
./out/cmake-release/filament/backend/CMakeFiles/backend.dir/src/opengl/platforms/PlatformEGLHeadless.cpp.o
./out/cmake-release/libs/bluegl/CMakeFiles/bluegl.dir/src/BlueGLLinuxEGL.cpp.o
```
2022-07-29 10:10:40 -07:00
Benjamin Doherty 396b1079a7 Bump version to 1.25.4 2022-07-26 09:57:34 -07:00
Benjamin Doherty eedcd9f8cb Merge branch 'rc/1.25.3' into release 2022-07-26 09:56:22 -07:00
Ben Doherty ab252b210c Fix config object related build failures (#5814) 2022-07-26 09:51:55 -07:00
Benjamin Doherty 1071b8ea90 Bump version to 1.25.3 2022-07-18 15:15:03 -07:00
Benjamin Doherty a9c5bbf185 Merge branch 'rc/1.25.2' into release 2022-07-18 15:14:02 -07:00
Philip Rideout 8dd4bff7a7 gltfio: minor fixups to prep for g3 integration. 2022-07-18 15:11:36 -07:00
Philip Rideout 77c54446af gltfio: use openLocalTransformTransaction API. 2022-07-18 15:11:30 -07:00
Benjamin Doherty 4a0bc0af57 Bump version to 1.25.2 2022-07-11 15:51:55 -07:00
Benjamin Doherty a171e75e70 Merge branch 'rc/1.25.1' into release 2022-07-11 15:50:10 -07:00
Benjamin Doherty f5ffa092fe Bump version to 1.25.1 2022-07-06 19:09:34 -07:00
Benjamin Doherty 8de5fdd551 Merge branch 'rc/1.25.0' into release 2022-07-06 19:07:42 -07:00
Benjamin Doherty ecca3abe98 Bump version to 1.25.0 2022-07-01 12:09:29 -07:00
Benjamin Doherty 8570e35224 Merge branch 'rc/1.24.0' into release 2022-07-01 12:08:48 -07:00
Benjamin Doherty 84df9f9a03 Update version to 1.24.0 2022-07-01 12:03:38 -07:00
Benjamin Doherty 5f93fb9613 Update RELEASE_NOTES for 1.24.0 2022-06-30 16:37:03 -07:00
Benjamin Doherty 75f77fdbdd Metal: Allow Filament to disregard MTLTexture pixelFormat when importing 2022-06-30 16:04:28 -07:00
Ben Doherty 7825d582c2 CocoaPods: include uberz library (#5752) 2022-06-30 14:07:55 -07:00
Ben Doherty 5deb0ba933 CocoaPods: include uberz library (#5752) 2022-06-30 14:04:02 -07:00
Philip Rideout 18e917aaf2 ImGuiHelper: add support for Y flip. (#5748)
Reflects a change from Betty and should be cherry picked to v1.23.3

Users could customize the ImGuiHelper camera, but they had no control
over the scissor coordinates. This allows them to use vertically flipped
coordinates, which, unfortunately, is required for MediaPipe
integration.
2022-06-30 12:05:53 -07:00
Benjamin Doherty a165f3890a Vulkan: Support VMA_DYNAMIC_VULKAN_FUNCTIONS off 2022-06-21 15:09:26 -07:00
Philip Rideout f88b6d9c97 Do not trigger UB with string_view. 2022-06-20 21:11:52 -07:00
Mathias Agopian db8ecd9952 configure render primitive pool so it works with msvc
a 64 bytes pool seems to work with both clang and msvc, unfortunately,
c++ doesn't let us know the allocator object size at compile time
for map containers, so we have to guess.
2022-06-16 13:13:33 -07:00
Benjamin Doherty b5ec06c2d2 Fix build breakage 2022-06-15 17:05:53 -07:00
Benjamin Doherty dfbac8385e Merge branch 'rc/1.23.2' into release 2022-06-15 11:49:06 -07:00
Ben Doherty eaab737b2c NoopDriver: return unique handles (#5697) 2022-06-15 11:28:08 -07:00
Benjamin Doherty 45991cda0a Update RELEASE_NOTES for 1.23.2 2022-06-13 15:27:03 -07:00
Philip Rideout 09a016bb6f Remove an 'API Change' warning from one item. 2022-06-09 14:33:49 -07:00
Benjamin Doherty 31607d355d Bump version to 1.23.2 2022-06-06 15:18:57 -07:00
Benjamin Doherty a67d50b9e2 Merge branch 'rc/1.23.1' into release 2022-06-06 15:16:53 -07:00
Benjamin Doherty 8d42f53c80 Update RELEASE_NOTES for 1.23.1 2022-06-06 15:14:59 -07:00
Benjamin Doherty 5e21a55bce Revert "iOS: implement headleass swapchain (#5486)"
This reverts commit 0e5ba60cb6.

This causes issues in G3, still need to investigate the root cause.
2022-06-06 13:17:04 -07:00
Benjamin Doherty 85930ea2e8 Bump version to 1.23.1 2022-06-01 14:58:29 -07:00
Benjamin Doherty 4b3cde8b39 Merge branch 'rc/1.23.0' into release 2022-06-01 14:55:20 -07:00
Benjamin Doherty eedfa85355 Update RELEASE_NOTES for 1.23.0 2022-06-01 14:54:50 -07:00
Benjamin Doherty bb54c6c807 Release Filament 1.23.0 2022-06-01 14:53:48 -07:00
Benjamin Doherty c23f905858 Update RELEASE_NOTES for 1.23.0 2022-06-01 14:53:23 -07:00
Benjamin Doherty 8c7be0a1d0 Revert "iOS: implement headleass swapchain (#5486)"
This reverts commit 0e5ba60cb6.

This causes issues in G3, still need to investigate the root cause.
2022-05-31 11:29:38 -07:00
Benjamin Doherty 878497b3d5 Bump version to 1.23.0 2022-05-24 15:19:51 -07:00
Benjamin Doherty a155561769 Merge branch 'rc/1.22.2' into release 2022-05-24 15:17:55 -07:00
Benjamin Doherty 8b86a0ed2e Revert "iOS: implement headleass swapchain (#5486)"
This reverts commit 0e5ba60cb6.

This causes issues in G3, still need to investigate the root cause.
2022-05-24 20:13:10 +00:00
Benjamin Doherty 26f9a9b122 Update RELEASE_NOTES for 1.22.2 2022-05-23 12:40:47 -07:00
Ben Doherty 6e5f6978fb Add ktxreader and viewer libs to CocoaPods (#5573) 2022-05-18 16:24:51 -07:00
Ben Doherty 0d31d7b2de Add ktxreader and viewer libs to CocoaPods (#5573) 2022-05-18 16:13:26 -07:00
Benjamin Doherty dd862b7e0a Bump version to 1.22.2 2022-05-17 18:03:38 -07:00
Benjamin Doherty 52065f2cbd Merge branch 'rc/1.22.1' into release 2022-05-17 18:01:37 -07:00
Benjamin Doherty 77c02d5831 Update RELEASE_NOTES for 1.22.1 2022-05-17 17:51:37 -07:00
Ben Doherty f7e4c8d16d Add package name back to AndroidManifest.xml to fix G3 (#5569) 2022-05-17 17:51:21 -07:00
Philip Rideout b7410474ff Workaround: partially revert "don't issue a flush..."
This is a temporary workaround for a memory corruption issue observed on
some devices from a specific vendor. We will try to make this workaround
more targeted in a subequent change.

Partial revert for b2cdf9f2b4.
2022-05-16 10:39:55 -07:00
Benjamin Doherty 384cc4ebf6 Bump version to 1.22.1 2022-05-09 13:09:39 -07:00
Benjamin Doherty 7c0643f122 Merge branch 'rc/1.22.0' into release 2022-05-09 13:07:07 -07:00
Benjamin Doherty 58abae3067 Release Filament 1.22.0 2022-05-09 13:07:02 -07:00
Benjamin Doherty 4742693869 Update RELEASE_NOTES for 1.22.0 2022-05-09 13:04:55 -07:00
Benjamin Doherty 6c39e474ea Bump version to 1.22.0 2022-05-02 13:19:43 -04:00
Benjamin Doherty 5c8977c906 Merge branch 'rc/1.21.3' into release 2022-05-02 13:18:06 -04:00
Benjamin Doherty 6b3cc2e2f3 Update RELEASE_NOTES for 1.21.3 2022-05-02 13:12:51 -04:00
Ben Doherty 76b2edd6ea Move toCompressedFilamentEnum to Ktx1Reader header (#5493) 2022-04-29 14:50:24 -04:00
Benjamin Doherty 8ebb37d011 Bump version to 1.21.3 2022-04-25 16:58:19 -04:00
Benjamin Doherty 3366db83ef Merge branch 'rc/1.21.2' into release 2022-04-25 16:57:25 -04:00
Benjamin Doherty 5415254aac Update RELEASE_NOTES for 1.21.2 2022-04-25 16:50:53 -04:00
Benjamin Doherty caacc61602 Bump version to 1.21.2 2022-04-13 10:21:09 -06:00
Benjamin Doherty e902df19b2 Merge branch 'rc/1.21.1' into release 2022-04-13 10:15:50 -06:00
Benjamin Doherty 40b372dda7 Update RELEASE_NOTES for 1.21.1 2022-04-12 14:36:26 -06:00
Ben Doherty fd330a98aa Releases: specify Python dependencies in requirements.txt file (#5402) 2022-04-08 14:35:51 -07:00
Ben Doherty 90c23a7d5d Correctly prepare color grading as subpass programs (#5384) 2022-04-04 13:24:01 -07:00
Benjamin Doherty 5710304114 Bump version to 1.21.1 2022-04-04 13:03:39 -07:00
Benjamin Doherty 0f684820bc Merge branch 'rc/1.21.0' into release 2022-04-04 13:01:35 -07:00
Benjamin Doherty e1d2d6ade6 Update RELEASE_NOTES for 1.21.0 2022-04-04 12:58:54 -07:00
Mathias Agopian e0b6f2ca71 Change version number to 1.21.0 2022-04-04 12:41:38 -07:00
Benjamin Doherty 2a35ee279b Bump version to 1.20.6 2022-03-28 18:47:38 -07:00
Benjamin Doherty 5abf780360 Merge branch 'rc/1.20.5' into release 2022-03-28 18:45:34 -07:00
Benjamin Doherty 181f158ea9 Update RELEASE_NOTES for 1.20.5 2022-03-28 18:42:41 -07:00
Benjamin Doherty f4087fc81d Bump version to 1.20.5 2022-03-21 14:45:34 -07:00
Benjamin Doherty 82793f9b82 Merge branch 'rc/1.20.4' into release 2022-03-21 14:43:15 -07:00
Benjamin Doherty 537576e84a Update RELEASE_NOTES for 1.20.4 2022-03-21 14:42:35 -07:00
Benjamin Doherty 375d1f55e3 Release Filament 1.20.4 2022-03-21 14:38:14 -07:00
Benjamin Doherty 597218963f Update RELEASE_NOTES for 1.20.4 2022-03-21 14:37:17 -07:00
Philip Rideout 0d29b3ddc8 WebGL endFrame: restore additional default state. 2022-03-21 09:43:45 -07:00
Philip Rideout e0e3b42623 WebGL: reset VAO and texture bindings when frame ends. 2022-03-21 09:43:33 -07:00
Benjamin Doherty 0995ca6614 Bump version to 1.20.4 2022-03-14 14:19:36 -07:00
Benjamin Doherty 3d741fc8d4 Merge branch 'rc/1.20.3' into release 2022-03-14 14:17:54 -07:00
Benjamin Doherty c20772b458 Update RELEASE_NOTES for 1.20.3 2022-03-10 12:56:56 -08:00
Benjamin Doherty 4a6b659098 Bump version to 1.20.3 2022-03-07 14:12:28 -08:00
Benjamin Doherty 2b93f08ca5 Merge branch 'rc/1.20.2' into release 2022-03-07 14:10:07 -08:00
Benjamin Doherty fca62b8fff Update RELEASE_NOTES for 1.20.2 2022-03-07 14:08:41 -08:00
Benjamin Doherty dee6d9de2c Bump version to 1.20.2 2022-03-02 15:51:38 -08:00
Benjamin Doherty 574e3e7521 Merge branch 'rc/1.20.1' into release 2022-03-02 15:47:21 -08:00
Ben Doherty 29fdf82ac5 Make VulkanContext compatible with vk_mem_alloc dev 2022-03-02 12:10:20 -08:00
Benjamin Doherty c8cf2a54e8 Update RELEASE_NOTES for 1.20.1 2022-03-02 11:47:51 -08:00
Ben Doherty bfd32e67d4 Apply some clang-tidy fixes (#5281) 2022-03-02 11:43:51 -08:00
Benjamin Doherty 95915367fa Bump version to 1.20.1 2022-02-24 13:59:17 -08:00
Benjamin Doherty b769cfda62 Merge branch 'rc/1.20.0' into release 2022-02-24 13:57:10 -08:00
Benjamin Doherty 40ac88dfed Bump MATERIAL_VERSION to 20 2022-02-24 13:53:43 -08:00
Benjamin Doherty 6d96082f07 Bump version to 1.20.0 2022-02-24 13:53:43 -08:00
Benjamin Doherty 21f913db1c Update RELEASE_NOTES for 1.20.0 2022-02-24 13:53:42 -08:00
Ben Doherty 699a578966 Add SSR variant filter to matc (#5256) 2022-02-24 10:36:06 -08:00
Philip Rideout babbfa1394 Vulkan: remove layout checks from SwapChain.
These asserts will come back in the next Filament release, which has
much cleaner layout tracking.
2022-02-23 13:48:13 -08:00
Philip Rideout 73f0d58e10 Vulkan: fix backend tests (especially ReadPixels Y flip). 2022-02-23 11:18:29 -08:00
Philip Rideout 9cb4b74bbd Fix web apps that have multiple Filament viewers.
This fixes the emscripten binding errors that we've been seeing
with the <filament-viewer> test page, which prevented us from
including web in the last few Filament releases.

The binding errors were caused by double-initializing the emscripten
module.

I fixed this by allowing clients (e.g. FilamentViewer) to call
Filament.init() more than once. We now accumulate a list of "on ready"
callbacks that get triggered after the emscripten module becomes ready.

As far as I can tell, multiple canvases were actually always broken, and
the viewer test page worked in the past only because we got lucky.
2022-02-22 16:12:13 -08:00
Ben Doherty f2c8456971 Attempt to fix Windows CI builds (#5205) 2022-02-15 11:12:19 -08:00
Benjamin Doherty e571600c30 Bump version to 1.19.1 2022-02-14 13:48:59 -08:00
Benjamin Doherty e84c94d3eb Merge branch 'rc/1.19.0' into release 2022-02-14 13:46:45 -08:00
Benjamin Doherty e791d4818f Update RELEASE_NOTES for 1.19.0 2022-02-14 13:45:28 -08:00
Philip Rideout cdadb43e50 WebGL: another fix for BufferDescriptor bindings.
The previous code would convert each element of the source data
into 8 bit-per-element, but we wnat to preserve the original format
that the user provides.

The new solution is to use `slice()` which is a robust way to clone
all the data in a typed array.

This fixes the new regression with Triangle that Ben caught.
2022-02-09 15:44:26 -08:00
Philip Rideout edaff60fbf WebGL: remove buffer sharing optimization.
If emscripten grows the heap inside one of our BufferDescriptor binding
functions, then the old heap becomes "detached" and an error can
occur.

This fixes the issue seen with the Parquet demo that Ben caught.
2022-02-09 12:51:06 -08:00
Benjamin Doherty 3f64e46557 Bump version to 1.19.0 2022-02-08 09:27:14 -08:00
Benjamin Doherty 32dab23bc6 Update RELEASE_NOTES for 1.18.0 2022-02-08 09:25:41 -08:00
Benjamin Doherty 362de7dd31 Merge branch 'rc/1.18.0' into release 2022-02-08 09:22:21 -08:00
Benjamin Doherty 6b01fbb903 Correct version to 1.18.0 2022-02-08 09:08:49 -08:00
Philip Rideout 4934d9f7bc Vulkan: fix leak when apps do not draw anything. 2022-02-07 14:27:06 -08:00
Ben Doherty ed73955b00 Initialize useLegacyMorphing to fix MSAN warning (#5164) 2022-02-07 11:28:03 -08:00
Ben Doherty 3f1f2726c4 Add a MAX_LEGACY_MORPH_TARGETS definition (#5163) 2022-02-07 11:27:45 -08:00
Philip Rideout 1a7bd7ea8d Rewrite VulkanPipelineCache (without changing its API).
All three types of caches (descriptor sets, pipelines, and pipeline
layouts) are now managed in exactly the same way. They all use an LRU
eviction scheme that is based on a count of command buffer flush
events.

Vulkan objects can only be destroyed if there are no in-flight command
buffers that reference them, so an easy way to know when it is safe to
evict a given entry is to wait for "N" flushes after its last use, where
"N" is the number of command buffers in the command buffer ring.

Another big simplification is that there are no more dirty flags,
instead we store two sets of state vectors for each type of cache: the
"currently bound" state, and the "current requirements" state.
2022-02-03 17:37:40 -08:00
Ben Doherty 946ea43436 Fix sampler overflow check in SamplerBindingMap (#5143) 2022-02-02 11:04:48 -08:00
Philip Rideout 7f42385f5f VulkanPipelineCache: fix spurious SEGV.
Fixes #5142 by replacing unsafe pointers with map keys.

One of the differences between robin_map and unordered_map is the
following:

    pointers to keys or values in the map are invalidated in the same
    way as iterators to these keys-values

Therefore it is unsafe to track the pointer to a value that is stored
in a robin_map.
2022-02-01 16:34:34 -08:00
Philip Rideout 8845ac2b75 VulkanPipelineCache: code cleanup and minor fixes.
This is mostly just code cleanup. One actual bug was the fact that the
dummy sampler was re-created every time a new pipeline layout was
created.

It also felt strange to use `auto&` to refer to a C-style array. I
changed this into a `std::array` which is more consistent with other
fixed size arrays in this class.
2022-02-01 16:34:27 -08:00
Ben Doherty da85001d4d Support legacy morphing (#5129)
Support legacy morphing (morphing with targets supplied via VertexAttributes) for older clients. This gives clients more time to transition over to the new MorphTargetBuffer API.
2022-01-27 16:08:46 -08:00
Mathias Agopian 8d15079937 update material version to 18 2022-01-26 14:32:46 -08:00
adc542b5cd Bind samplers to specified shader stages (#5036)
Co-authored-by: Ben Doherty <bendoherty@google.com>
Co-authored-by: Mathias Agopian <mathias@google.com>
2022-01-26 14:31:30 -08:00
Philip Rideout 72feb044a3 Vulkan now supports offsets when uploading texture data.
This allows `MorphStressTest` to work on Vulkan.

However, `Horse` is still broken because it provides positions but not
tangents.  Separate fix for that is coming.

Partial fix for #5109.
2022-01-26 14:31:00 -08:00
Philip Rideout c0ba260ddf Vulkan: clean up image layout management.
This fixes validation errors and makes a first pass at simplification.
VulkanTexture now tracks image layout using RangeMap, which paves the
way for further simplification.
2022-01-26 14:30:45 -08:00
Philip Rideout 2da215e8e7 RangeMap: improve naming convention, etc. 2022-01-26 14:30:23 -08:00
Philip Rideout 4d0368b5f1 RangeMap: improve the auto-merge functionality. 2022-01-26 14:30:09 -08:00
Philip Rideout d11c78857d utils: introduce RangeMap container and unit test.
This will allow the Vulkan backend to efficiently track the subresource
image layouts for each texture.

This is a sparse container for a series of ordered non-overlapping
integer intervals, where each interval maps to a concrete value.
2022-01-26 14:29:45 -08:00
Mathias Agopian e829d90c4a A morphing buffer must be bound when skinning is active
This is because we're using the same program variant for skinning
and morphing, in the skinning-only case, the buffer won't be accessed
in the shader, but it must be present.

fixes #5085
2022-01-26 14:20:25 -08:00
Mathias Agopian a8006acd33 [GL backend] fix sampler binding bug
When a program had an unused SamplerInterfaceBlock, other samplers
could be bound to the wrong TMU

Fixes #5088
2022-01-26 14:20:12 -08:00
Benjamin Doherty 86ec502040 Bump version to 1.17.1 2022-01-24 12:52:22 -08:00
Benjamin Doherty b19a73cc50 Merge branch 'rc/1.17.0' into release 2022-01-24 12:50:22 -08:00
Benjamin Doherty a99c695932 Update RELEASE_NOTES for 1.17.0 2022-01-24 12:45:05 -08:00
Benjamin Doherty 8cd720b53a Bump version to 1.17.0 2022-01-18 13:54:40 -08:00
Benjamin Doherty 04df79e58f Merge branch 'rc/1.16.1' into release 2022-01-18 13:53:02 -08:00
Benjamin Doherty a4b3717762 Update RELEASE_NOTES for 1.16.1 2022-01-18 13:48:36 -08:00
Benjamin Doherty 1035e442ee Bump version to 1.16.1 2022-01-10 10:47:46 -08:00
Benjamin Doherty 60d3638f15 Merge branch 'rc/1.16.0' into release 2022-01-10 10:44:36 -08:00
Benjamin Doherty 3e7d3c9035 Update RELEASE_NOTES for 1.16.0 2022-01-10 10:41:14 -08:00
jeanlemotan eb360be2ad Fixed cubemap update 2022-01-10 10:34:49 -08:00
Benjamin Doherty 485ac8704d Bump version to 1.16.0 2022-01-04 11:55:19 -08:00
Benjamin Doherty dc74540423 Merge branch 'rc/1.15.2' into release 2022-01-04 11:53:02 -08:00
Benjamin Doherty 96219c22db Update RELEASE_NOTES for 1.15.2 2022-01-04 11:49:50 -08:00
Romain Guy f3b7048775 Add missing JNI impl (#4959) 2022-01-04 11:43:19 -08:00
Romain Guy aaed6fb376 Fix rounding math 2022-01-04 11:43:13 -08:00
Romain Guy 35a5d3310f Fix preprocessor test 2021-12-13 13:53:20 -07:00
Benjamin Doherty 9da79a1d2d Bump version to 1.15.2 2021-12-13 11:08:28 -07:00
Benjamin Doherty 595b355d1b Merge branch 'rc/1.15.1' into release 2021-12-13 11:06:45 -07:00
Benjamin Doherty 3a67d769f4 Update RELEASE_NOTES for 1.15.1 2021-12-06 16:54:28 -08:00
Benjamin Doherty 6fb536a937 Bump version to 1.15.1 2021-12-06 11:17:37 -08:00
Benjamin Doherty bb460d78d8 Merge branch 'rc/1.15.0' into release 2021-12-06 11:14:00 -08:00
Benjamin Doherty 838835a715 Update RELEASE_NOTES for 1.15.0 2021-12-02 11:52:04 -08:00
Romain Guy 63acd53e23 Use __ANDROID__ instead of ANDROID 2021-11-30 11:15:49 -08:00
Romain Guy fcd2d0457b Workaround for a build system issue 2021-11-30 11:15:42 -08:00
Benjamin Doherty 58fc26461b Bump version to 1.15.0 2021-11-29 14:08:28 -08:00
Benjamin Doherty fd82f6b04e Merge branch 'rc/1.14.2' into release 2021-11-29 14:07:03 -08:00
Benjamin Doherty cef3200533 Add additional RELEASE_NOTES for 1.14.2 2021-11-29 10:21:56 -08:00
Ben Doherty 634500c398 Fix, avoid divide-by-zero inside makeBone (#4889) 2021-11-24 16:29:33 -08:00
Ben Doherty b3e294ac54 Fix Metal depth comparison initialization (#4886) 2021-11-23 12:09:43 -08:00
Benjamin Doherty 2bf7535ad0 Update RELEASE_NOTES for 1.14.2 2021-11-22 10:16:00 -08:00
Benjamin Doherty 3315f75de9 Bump version to 1.14.2 2021-11-22 10:12:44 -08:00
Benjamin Doherty bbe7dbfa92 Merge branch 'rc/1.14.1' into release 2021-11-22 10:11:06 -08:00
Benjamin Doherty 5697922a65 Update RELEASE_NOTES for 1.14.1 2021-11-17 12:04:26 -08:00
Ben Doherty 4da83df2b9 Fix material compilation error with device vertex domain (#4865)
A recent refactor was causing the following error when the vertex domain
was set to `device`:
```
ERROR: main.vs:23: 'material' : undeclared identifier
ERROR: main.vs:23: 'materialVertex' : no matching overloaded function found
```
2021-11-17 12:03:55 -08:00
Ben Doherty 8f156d6588 Android: re-enable VSM cascade fix (#4863) 2021-11-17 10:19:09 -08:00
Benjamin Doherty cec0871c11 Bump version to 1.14.1 2021-11-15 10:09:45 -08:00
Benjamin Doherty 41a809368b Merge branch 'rc/1.14.0' into release 2021-11-15 10:07:56 -08:00
Romain Guy ea53eb9290 Skip task incompatible with configuration caching (#4831) 2021-11-09 15:56:00 -08:00
Benjamin Doherty 05875057c9 Update RELEASE_NOTES for 1.14.0 2021-11-09 15:51:13 -08:00
Benjamin Doherty 44125926d1 Disable configuration-cache 2021-11-08 17:05:34 -08:00
Benjamin Doherty 60734349de Bump version to 1.14.0 2021-11-08 11:52:50 -08:00
Benjamin Doherty fbfd5ec0ec Merge branch 'rc/1.13.0' into release 2021-11-08 11:50:19 -08:00
Ben Doherty a74a95cc65 Call VirtualMachineEnv::JNI_OnLoad for non-Android Java builds (better fix) (#4779) 2021-11-04 13:28:17 -07:00
Benjamin Doherty bc0ea16ff0 Update RELEASE_NOTES for 1.13.0 2021-11-02 13:15:53 -07:00
Mathias Agopian b2dc8aa84c Fix typo that broke the directional shadowmap 2021-11-02 13:11:44 -07:00
Benjamin Doherty 9987e8b6ab Bump version to 1.13.0 2021-11-01 14:59:11 -07:00
Benjamin Doherty 0d9bdcc008 Merge branch 'rc/1.12.11' into release 2021-11-01 14:55:58 -07:00
Benjamin Doherty b5c634045e Update RELEASE_NOTES for 1.12.11 2021-10-28 16:13:50 -07:00
Ben Doherty 1f05531d53 Call VirtualMachineEnv::JNI_OnLoad for non-Android Java builds (better fix) (#4779) 2021-10-28 16:02:23 -07:00
Benjamin Doherty 88f382f0e3 Revert "refactor colorgrading materials"
This reverts commit fb86a77cf8.
2021-10-28 15:56:50 -07:00
Benjamin Doherty 3e59925900 Remove problematic configuration-cache setting for release build 2021-10-28 15:56:26 -07:00
Benjamin Doherty ea404f8d4f Remove problematic configuration-cache setting for release build 2021-10-26 10:09:51 -07:00
Benjamin Doherty 602a550d93 Bump version to 1.12.11 2021-10-25 12:30:37 -07:00
Benjamin Doherty 12abbe2d23 Merge branch 'rc/1.12.10' into release 2021-10-25 11:06:18 -07:00
Benjamin Doherty fb0ee97588 Update RELEASE_NOTES for 1.12.10 2021-10-25 11:00:06 -07:00
Ben Doherty 56ef48c9c3 Fix, call VirtualMachineEnv::JNI_OnLoad for non-Android Java builds (#4749) 2021-10-25 10:39:24 -07:00
Benjamin Doherty 47c3dd3dd1 Revert "refactor colorgrading materials"
This reverts commit fb86a77cf8.
2021-10-25 10:37:52 -07:00
Benjamin Doherty c181648bfa Bump version to 1.12.10 2021-10-20 12:15:51 -07:00
Benjamin Doherty 0cf78b3abe Merge branch 'rc/1.12.9' into release 2021-10-20 12:12:33 -07:00
Ben Doherty 22889a7ad9 Fix VirtualMachineEnv.cpp with older JNI versions (#4752) 2021-10-20 11:16:55 -07:00
Ben Doherty a14451d0ac Fix, call VirtualMachineEnv::JNI_OnLoad for non-Android Java builds (#4749) 2021-10-20 10:41:34 -07:00
Benjamin Doherty 5dfdab10b7 Revert "refactor colorgrading materials"
This reverts commit fb86a77cf8.
2021-10-19 16:13:21 -07:00
Benjamin Doherty d6f2e3b8e9 Update RELEASE_NOTES for 1.12.9 2021-10-14 18:22:20 -07:00
Benjamin Doherty df30517743 Bump version to 1.12.9 2021-10-11 11:06:43 -07:00
Benjamin Doherty 8f80643c1a Merge branch 'rc/1.12.8' into release 2021-10-11 11:02:56 -07:00
Benjamin Doherty 5aea9be2fb Update RELEASE_NOTES for 1.12.8 2021-10-07 11:03:45 -07:00
Benjamin Doherty ad02e483d0 Bump version to 1.12.8 2021-10-04 10:26:57 -07:00
Benjamin Doherty f463d53036 Merge branch 'rc/1.12.7' into release 2021-10-04 10:21:42 -07:00
Benjamin Doherty b8d4408524 Update RELEASE_NOTES for 1.12.7 2021-10-04 10:18:56 -07:00
Benjamin Doherty fef70be848 Bump version to 1.12.7 2021-09-27 11:15:58 -07:00
Benjamin Doherty bdb12d9b24 Merge branch 'rc/1.12.6' into release 2021-09-27 11:12:42 -07:00
Ben Doherty 43ad283a83 Fix, missing call to setTransparencyMode (#4674) 2021-09-24 13:32:49 -07:00
Benjamin Doherty 2e4936afc4 Revert "fix a race in jobsystem"
This reverts commit 2feb0ad325.
2021-09-24 11:24:44 -07:00
Benjamin Doherty 891ffabd11 Update RELEASE_NOTES for 1.12.6 2021-09-23 17:25:25 -07:00
Ben Doherty e2c19498b4 Metal: don't call createTextureViewWithsSwizzle directly (#4662) 2021-09-23 11:28:04 -07:00
Ben Doherty c32630b265 Fix MetalBlitter crash when shader contains warnings (#4663) 2021-09-23 11:27:56 -07:00
Alexey Pelykh bf21e78d02 Podspec: include headers in nested directories (#4658) 2021-09-22 16:48:12 -07:00
Benjamin Doherty 525d4e08a3 Bump version to 1.12.6 2021-09-20 10:17:18 -07:00
Benjamin Doherty 2e9bf6d694 Merge branch 'rc/1.12.5' into release 2021-09-20 10:14:37 -07:00
Benjamin Doherty e845f01d85 Update RELEASE_NOTES for 1.12.5 2021-09-20 10:10:56 -07:00
Benjamin Doherty bef48be7b4 Bump version to 1.12.5 2021-09-13 10:47:09 -07:00
Benjamin Doherty b54fdc9e6e Merge branch 'rc/1.12.4' into release 2021-09-13 10:43:06 -07:00
Benjamin Doherty cedbf2e30b Update RELEASE_NOTES for 1.12.4 2021-09-13 10:40:55 -07:00
Benjamin Doherty 592f8d1b0d Bump version to 1.12.4 2021-09-08 11:05:44 -07:00
Benjamin Doherty 29612a684e Merge branch 'rc/1.12.3' into release 2021-09-08 11:03:53 -07:00
Benjamin Doherty e6d5807399 Bump version to 1.12.3 2021-08-30 11:46:51 -07:00
Benjamin Doherty fa2553251f Merge branch 'rc/1.12.2' into release 2021-08-30 11:44:00 -07:00
Benjamin Doherty 7387718852 Update RELEASE_NOTES for 1.12.2 2021-08-30 11:41:52 -07:00
Ben Doherty a503a6209a Fix regression with clipSpaceTransform (#4552) 2021-08-26 14:14:58 -07:00
Ben Doherty ce3e5f74e8 Fix Metal STREAM buffers (#4543) 2021-08-25 09:48:34 -07:00
Ben Doherty f37112358e Fix missing bookkeeping in bindUniformBufferRange (#4538) 2021-08-24 09:51:40 -07:00
Benjamin Doherty f368b14621 Bump version to 1.12.2 2021-08-23 12:41:33 -07:00
Benjamin Doherty 6960b1148a Merge branch 'rc/1.12.1' into release 2021-08-23 12:39:38 -07:00
Benjamin Doherty 3cc23aac25 Update RELEASE_NOTES for 1.12.1 2021-08-23 10:45:59 -07:00
Benjamin Doherty 11dc8740f2 Fix stack-use-after-scope error 2021-08-20 15:40:06 -07:00
Ben Doherty 4b797cff88 Windows: fix incorrect CRT flags with Visual Studio generators (#4516) 2021-08-20 10:56:41 -07:00
Ben Doherty fe1c1736cd Fix, potential null dereferences in MetalBlitter (#4481) 2021-08-10 16:30:11 -07:00
Benjamin Doherty 4058ef5f09 Bump version to 1.12.1 2021-08-09 12:06:47 -07:00
Benjamin Doherty d25ca01624 Merge branch 'rc/1.12.0' into release 2021-08-09 12:03:33 -07:00
Benjamin Doherty d96f87dbbf Update RELEASE_NOTES for 1.12.0 2021-08-09 12:01:46 -07:00
Ben Doherty 8a2e31023f Attempt to fix TSAN failure in ColorGrading.cpp (#4447) 2021-08-05 11:54:07 -07:00
Benjamin Doherty 1ea8e171d9 Bump version to 1.12.0 2021-08-03 11:18:56 -07:00
Benjamin Doherty e2be3dd0ac Merge branch 'rc/1.11.2' into release 2021-08-03 11:15:19 -07:00
Romain Guy 1c51164e7b Fix inverse tone mapping issues (#4437)
Bring color grading back into the Rec.709 color space to match
previous behaviors. This change also implements an exact inverse
tone map function for the "Filmic" operator.
2021-08-02 20:54:44 -07:00
Benjamin Doherty f190f03530 Update RELEASE_NOTES for 1.11.2 2021-08-02 11:17:42 -07:00
Ben Doherty 055fc7cbc1 Attempt to fix Windows CI by turning off concurrent builds (#4395) 2021-07-30 14:09:07 -07:00
Ben Doherty 9073fc3dc3 Attempt to fix Windows CI by turning off concurrent builds (#4395) 2021-07-28 10:49:37 -07:00
Ben Doherty 2409dc9bc4 Expose Engine::flush (#4385) 2021-07-26 15:09:14 -07:00
Benjamin Doherty 6586c8d70b Bump version to 1.11.2 2021-07-26 12:50:29 -07:00
Benjamin Doherty ac0c94da69 Merge branch 'rc/1.11.1' into release 2021-07-26 12:48:36 -07:00
Ben Doherty d19d6a72b0 Expose Engine::flush (#4385) 2021-07-26 12:10:19 -07:00
Benjamin Doherty c81b5d98ef Update RELEASE_NOTES for 1.11.1 2021-07-26 10:05:41 -07:00
Mathias Agopian 756866675f fix an issue where a sampler could fail to be updated
SamplerGroup was comparing texture handles to decide if a texture needed
to be updated, however, texture handles are (quickly) recycled and
therefore can't be used for that purpose. e.g. if a texture is destroyed,
its handle could be reused quickly by another texture, if that texture 
is now set on the SamplerGroup, it will ignore it, thinking it's not
different.
2021-07-21 14:46:44 -07:00
Benjamin Doherty ebcd4925f7 Bump version to 1.11.1 2021-07-19 10:24:01 -07:00
Benjamin Doherty 13bed4fdf9 Merge branch 'rc/1.11.0' into release 2021-07-19 10:20:29 -07:00
Benjamin Doherty 1dae5c6b6c Update RELEASE_NOTES for 1.11.0 2021-07-19 10:18:07 -07:00
Benjamin Doherty 8e6663e4b0 Bump version to 1.11.0 2021-07-12 10:49:43 -07:00
Benjamin Doherty ba804444b8 Merge branch 'rc/1.10.7' into release 2021-07-12 10:47:12 -07:00
Benjamin Doherty 58cfb85004 Update RELEASE_NOTES for 1.10.7 2021-07-12 10:45:24 -07:00
Mathias Agopian ab46481b45 Fix colorgrading as subpass
We were inserting the colorgrading subpass command between the
refracted and blended objects, instead of after all of them.

Another bad side effect of this was to trigger the refraction pass for
no reason.
2021-07-12 10:35:01 -07:00
Mathias Agopian 4296782399 don't crash when refraction pass is empty 2021-07-12 09:53:37 -07:00
Benjamin Doherty ef375a7103 Bump version to 1.10.7 2021-07-07 11:02:30 -07:00
Benjamin Doherty fd258b7765 Merge branch 'rc/1.10.6' into release 2021-07-07 10:59:12 -07:00
Benjamin Doherty 147de8d372 Update RELEASE_NOTES for 1.10.6 2021-07-07 10:57:25 -07:00
Philip Rideout eb2a1928b6 ShadowMapManager: fix MSAN use-of-uninitialized-value.
The operator!= in std::array compares SPLIT_COUNT elements, which
is potentially greater than cascadeCount, which was the number of
initialized elements in splitPercentages.
2021-07-07 10:51:18 -07:00
Benjamin Doherty 35b033102f Bump version to 1.10.6 2021-06-28 12:07:58 -07:00
Benjamin Doherty 7bc65421a9 Merge branch 'rc/1.10.5' into release 2021-06-28 12:04:31 -07:00
Benjamin Doherty 736514cf37 Update RELEASE_NOTES for 1.10.5 2021-06-28 12:04:27 -07:00
Mathias Agopian db0158dae8 fix webgl build
we need to select opengl on webgl.
2021-06-28 08:27:46 -07:00
Benjamin Doherty e706695ed1 Bump version to 1.10.5 2021-06-21 11:18:26 -07:00
Benjamin Doherty e8877ffe2d Merge branch 'rc/1.10.4' into release 2021-06-21 11:16:10 -07:00
Benjamin Doherty 1fd5d9dae6 Update RELEASE_NOTES for 1.10.4 2021-06-21 11:14:35 -07:00
Ben Doherty cd48089318 filament-utils-android: fix string literal conversions (#4137) 2021-06-15 16:19:32 -06:00
Benjamin Doherty 6379ab22c9 Bump version to 1.10.4 2021-06-14 11:06:42 -06:00
Benjamin Doherty 0bf02b75d5 Merge branch 'rc/1.10.3' into release 2021-06-14 11:04:25 -06:00
Benjamin Doherty c4259b5598 Update RELEASE_NOTES for 1.10.3 2021-06-14 11:02:45 -06:00
Ben Doherty 6b3c1179bc Include sample-gltf-viewer with Android releases (#4099) 2021-06-08 10:41:48 -07:00
Philip Rideout c1a0e61e8e Fix FixedCapacityVector destructor.
std::allocator::deallocate() expects the same value that was given
during allocate().

Interestingly, this bug did not manifest any issues (even with ASAN) on
some platforms.
2021-06-07 15:56:33 -07:00
Benjamin Doherty fc06298ed4 Bump version to 1.10.3 2021-06-07 11:22:04 -07:00
Benjamin Doherty 4ca87b188c Merge branch 'rc/1.10.2' into release 2021-06-07 11:19:51 -07:00
Benjamin Doherty f1f60c3e0d Turn off warnings as errors for spirv-tools 2021-06-07 11:18:56 -07:00
Benjamin Doherty 76d21b56af Update RELEASE_NOTES for 1.10.2 2021-06-07 11:18:09 -07:00
Benjamin Doherty 0ab0e50a4f Turn off warnings as errors for spirv-tools 2021-06-02 11:16:42 -07:00
Benjamin Doherty 34f4c06a5c Bump version to 1.10.2 2021-06-01 11:17:32 -07:00
Benjamin Doherty 6de36f1e53 Merge branch 'rc/1.10.1' into release 2021-06-01 11:15:49 -07:00
Benjamin Doherty 2a9a3b1ac2 Update RELEASE_NOTES for 1.10.1 2021-06-01 11:13:04 -07:00
Benjamin Doherty 84b73a3770 Bump version to 1.10.1 2021-05-24 10:52:02 -07:00
Benjamin Doherty 662a10e273 Merge branch 'rc/1.10.0' into release 2021-05-24 10:49:10 -07:00
Benjamin Doherty ecce02502e Update RELEASE_NOTES for 1.10.0 2021-05-24 10:47:39 -07:00
Philip Rideout d17875aea1 ImGuiHelper: fix support for custom images.
The texture binding in the material instance needs to be restored to the
glyph atlas when a custom image is not in use.
2021-05-21 12:49:37 -07:00
Philip Rideout b8897a68f9 matc: detect missing end brace.
matc was failing to report certain kinds of syntax errors and would
read out-of-bounds memory.

This change casuses the flare material to fail.
2021-05-21 09:20:33 -07:00
Ben Doherty 84efd4871e API CHANGE: remove some Camera, Engine, and View deprecated APIs (#3965) 2021-05-19 12:02:13 -07:00
Benjamin Doherty 85ea5a6b70 Bump version to 1.10.0 2021-05-17 11:00:42 -07:00
Benjamin Doherty 77891acb92 Merge branch 'rc/1.9.25' into release 2021-05-17 10:57:30 -07:00
Benjamin Doherty 74fe102035 Update RELEASE_NOTES for 1.9.25 2021-05-17 10:54:38 -07:00
Philip Rideout 25cc554925 WASM: fix "Missing field" error for lensFlare. 2021-05-17 10:06:56 -07:00
Ben Doherty d787a521b5 Fix DIST_DIR setting for Windows builds (#3945) 2021-05-12 11:16:30 -07:00
Ben Doherty 46e52c71e1 Fix DIST_DIR setting for Windows builds (#3945) 2021-05-12 11:15:49 -07:00
Philip Rideout 1dad27a172 Repair WebGL and fix potential INVALID_OPERATION.
We should take care not to call glVertexAttribPointer when there is
no bound ARRAY_BUFFER (i.e. when its binding is zero).

This fixes the black screen seen with some WebGL samples after
the recent memory leak fix related to the new BufferObject API.
2021-05-10 13:38:56 -07:00
Benjamin Doherty 60d230b380 Bump version to 1.9.25 2021-05-07 21:42:48 -07:00
Benjamin Doherty d7cb38e706 Merge branch 'rc/1.9.24' into release 2021-05-07 21:39:17 -07:00
Benjamin Doherty ce00cca6ee Update RELEASE_NOTES for 1.9.24 2021-05-07 21:36:49 -07:00
Philip Rideout d627d57bad Second memory leak fix. (#3906)
Fixes #3888.
2021-05-06 14:25:46 -07:00
Philip Rideout 8ffc776f1c Fix horrible memory leak in the GL driver. (#3894)
This leak was introduced in the following PR on April 7.
https://github.com/google/filament/pull/3775

The guilty party has been contacted and properly admonished for his
transgression.

This was tested by adding the following code after applyAnimation in
gltf_viewer.cpp

        static int nframes = 0;
        if (!gpath.empty() && nframes++ > 100) {
            static int count = 0;
            printf("reloading %d\n", count++);
            nframes = 0;
            app.resourceLoader->asyncCancelLoad();
            app.resourceLoader->evictResourceData();
            app.viewer->removeAsset();
            app.assetLoader->destroyAsset(app.asset);
            loadAsset(gpath, app);
            loadResources(gpath, app);
        }
2021-05-04 18:22:08 -07:00
Benjamin Doherty be032b52c1 Bump version to 1.9.24 2021-05-03 10:42:19 -07:00
Benjamin Doherty 4388e81e5f Merge branch 'rc/1.9.23' into release 2021-05-03 10:40:49 -07:00
Benjamin Doherty 71a185d139 Update RELEASE_NOTES for 1.9.23 2021-05-03 10:38:59 -07:00
Benjamin Doherty d2cf5985ac Bump version to 1.9.23 2021-04-26 10:55:10 -07:00
Benjamin Doherty debcbb8e5c Merge branch 'rc/1.9.22' into release 2021-04-26 10:52:43 -07:00
Benjamin Doherty b9dd62c7d3 Update RELEASE_NOTES for 1.9.22 2021-04-26 10:47:11 -07:00
Benjamin Doherty dc2b430f34 Bump version to 1.9.22 2021-04-26 10:39:16 -07:00
Benjamin Doherty e5ef4e8868 Update RELEASE_NOTES for 1.9.21 2021-04-19 11:36:37 -07:00
Benjamin Doherty c0d6cd3ac3 Merge branch 'rc/1.9.21' into release 2021-04-19 11:34:23 -07:00
Benjamin Doherty b63ab2dc19 Update RELEASE_NOTES for 1.9.21 2021-04-19 11:32:31 -07:00
Benjamin Doherty 5d8dad561c Bump version to 1.9.21 2021-04-12 11:38:27 -07:00
Benjamin Doherty 8933be1ae2 Merge branch 'rc/1.9.20' into release 2021-04-12 11:36:17 -07:00
Benjamin Doherty 6b66b48b1d Update RELEASE_NOTES for 1.9.20 2021-04-12 11:35:45 -07:00
Benjamin Doherty 9c23eb6e33 Release Filament 1.9.20 2021-04-12 11:34:39 -07:00
Benjamin Doherty baea54a3fc Update RELEASE_NOTES for 1.9.20 2021-04-12 09:20:31 -07:00
Benjamin Doherty d9f800454c Bump version to 1.9.20 2021-04-05 11:14:17 -07:00
Benjamin Doherty f9ee0de07a Merge branch 'rc/1.9.19' into release 2021-04-05 11:11:13 -07:00
Benjamin Doherty 2786d0a9f7 Update RELEASE_NOTES for 1.9.19 2021-04-05 11:10:50 -07:00
Benjamin Doherty 491e8032e6 Release Filament 1.9.19 2021-04-05 11:10:20 -07:00
Benjamin Doherty ef3f13f5d3 Update RELEASE_NOTES for 1.9.19 2021-04-05 11:09:38 -07:00
Benjamin Doherty bcb5b2d790 Implement Metal BufferObjects 2021-04-05 11:01:36 -07:00
Ben Doherty 02de3f2e2a Fix, regression with Metal buffers (#3715) 2021-03-29 14:21:34 -07:00
Benjamin Doherty 0e7bb53c07 Bump version to 1.9.19 2021-03-29 11:09:32 -07:00
Benjamin Doherty 759109d478 Merge branch 'rc/1.9.18' into release 2021-03-29 11:06:55 -07:00
Benjamin Doherty 54d5af6edf Update RELEASE_NOTES for 1.9.18 2021-03-29 11:04:57 -07:00
Philip Rideout 38fbe47ced RenderTarget: fix NPE when depth is not present.
This fixes a recent regression that would occur when a RenderTarget
does not have a depth attachment.
2021-03-29 10:32:22 -07:00
Benjamin Doherty f066c925ba Bump version to 1.9.18 2021-03-22 10:16:34 -07:00
Benjamin Doherty 994fdf4e1d Merge branch 'rc/1.9.17' into release 2021-03-22 10:12:20 -07:00
Benjamin Doherty 50b50d65e3 Update RELEASE_NOTES for 1.9.17 2021-03-22 10:11:02 -07:00
Mathias Agopian 0aaa985649 Fix a hang in JobSystem
The hang was caused by a subtle race. When a job is completed, its 
thread must signal all the threads that might be waiting on this job.
The signaling code was attempting to signal only the minimum number
of threads -- this was important especially in the case where no threads
were waiting, then the call to notify() could be avoided.

Unfortunately, for performance reasons we're not calling notify() with
the condition lock held, this meant that between the time the number of 
waiting threads was latched and the time of the notify() call, more
threads could enter their condition variable wait(), and it would
then be possible for these threads to wake up, instead of the thread
we were trying to wake up (the one waiting on the job).

It would then get stuck forever.

This bug was introduced in 2df639133b


Also add some debugging code for this kind of failure (disabled)
2021-03-18 09:57:25 -07:00
Benjamin Doherty 29564f8eae Bump version to 1.9.17 2021-03-15 10:15:25 -07:00
Benjamin Doherty c15db68a5b Merge branch 'rc/1.9.16' into release 2021-03-15 10:12:56 -07:00
Benjamin Doherty 3452fb3e56 Update RELEASE_NOTES for 1.9.16 2021-03-15 10:10:40 -07:00
Mathias Agopian 35eb8e7be1 Revert GL backend handle tracking
This wasn't very useful in the first place because we're recycling
handles very quickly. Additionally there was a race condition
which cause false positives.

This reverts commit bc6acd5c5a.
This reverts commit 3a15756c78.
2021-03-12 13:02:55 -08:00
Mathias Agopian 834b774128 Fixes some issues with imported rendertargets
We were not declaring the attachments it was using.

Fixes #3628
2021-03-12 08:26:16 -08:00
Benjamin Doherty 5aa0eb9f9d Bump version to 1.9.16 2021-03-08 10:09:14 -08:00
Benjamin Doherty d9a6e2e649 Merge branch 'rc/1.9.15' into release 2021-03-08 10:07:00 -08:00
Benjamin Doherty cb823b16a1 Update RELEASE_NOTES for 1.9.15 2021-03-08 10:05:19 -08:00
Ben Doherty 0bd41e877e Downgrade Linux GitHub Actions environment to fix error (#3588) 2021-03-01 11:21:11 -08:00
Benjamin Doherty ecc3e73967 Bump version to 1.9.15 2021-03-01 11:13:44 -08:00
Benjamin Doherty 464b4c24f9 Merge branch 'rc/1.9.14' into release 2021-03-01 11:11:53 -08:00
Benjamin Doherty 32367516e8 Update RELEASE_NOTES for 1.9.14 2021-03-01 11:10:06 -08:00
Philip Rideout 1709a55606 filamat: Fix data race with SPIRV error registrations. 2021-02-26 10:34:36 -08:00
Benjamin Doherty 58b4455979 Bump version to 1.9.14 2021-02-22 10:32:56 -08:00
Benjamin Doherty ea1dede19c Merge branch 'rc/1.9.13' into release 2021-02-22 10:29:57 -08:00
Benjamin Doherty 20ea3381fa Update RELEASE_NOTES for 1.9.13 2021-02-22 10:28:21 -08:00
Philip Rideout 7aa6fccd7c Modernize Python print syntax to appease external codebase. 2021-02-19 11:38:18 -08:00
Philip Rideout adbd54f4f8 Change abs() to std::abs to appease external codebase. 2021-02-19 11:38:18 -08:00
Philip Rideout 9d54261f18 Move vk_mem_alloc to its own cpp.
This will improve parity between the GitHub repo and its sister codebase
within Google.
2021-02-19 11:38:18 -08:00
Philip Rideout a97757c9ae Avoid uninitialized reads in computeVisibilityMasks.
I verified that this code is not enabled in our GitHub builds, and I
verified that the MSAN error goes away.
2021-02-19 11:38:18 -08:00
Philip Rideout 7c79d9f89d Remove some Windows line endings.
These line endings cause annoying diffs when comparing Filament's GitHub
source with its twin sister within Google.
2021-02-19 11:38:18 -08:00
Benjamin Doherty bf0914f813 Bump version to 1.9.13 2021-02-16 10:48:24 -08:00
Benjamin Doherty b96bc30fbd Merge branch 'rc/1.9.12' into release 2021-02-16 10:44:13 -08:00
Benjamin Doherty 62b50eb8ba Update RELEASE_NOTES for 1.9.12 2021-02-16 10:42:41 -08:00
Ben Doherty b4932e384a matc: Use consistent params for semantic code analysis (#3524)
When running semantic analysis on a material, we were arbitrarily choosing the first code gen permutation to analyze. So, running matc with arguments --api metal versus --api all would run analysis on slightly different shader code. This causes bugs when flags passed to glslang differ during semantic analysis. This change updates all semantic analysis to always use the same shader code.
2021-02-08 14:06:47 -08:00
Benjamin Doherty 5e68dc5f8d Bump version to 1.9.12 2021-02-08 09:58:15 -08:00
Benjamin Doherty f222f1b925 Merge branch 'rc/1.9.11' into release 2021-02-08 09:51:08 -08:00
Ben Doherty 22e4a54782 Update RELEASE_NOTES for 1.9.11 2021-02-08 09:50:23 -08:00
Benjamin Doherty 1289922c5f Release Filament 1.9.11 2021-02-08 09:48:50 -08:00
Ben Doherty 2839c352b8 Update RELEASE_NOTES for 1.9.11 2021-02-08 09:47:18 -08:00
Ben Doherty 6a01cbc312 Draft: fix TSAN issue by using lock in ColorGrading constructor (#3510)
This is a second attempt to fix Google3 TSAN failures seen inside of the ColorGrading constructor.

Related first attempt: #3462
2021-02-05 14:06:40 -08:00
Benjamin Doherty 6193156556 Bump version to 1.9.11 2021-02-01 11:49:12 -08:00
Benjamin Doherty fe23aa917d Merge branch 'rc/1.9.10' into release 2021-02-01 11:45:47 -08:00
Benjamin Doherty eb8a29a332 Update RELEASE_NOTES for 1.9.10 2021-02-01 11:45:17 -08:00
Ben Doherty 0626902530 Fix sporatic data race warning seen in Google3 (#3462) 2021-01-27 16:40:16 -08:00
Philip Rideout 042bfe2597 Partial fix for MSVC build. 2020-12-14 12:15:06 -08:00
Ben Doherty 97133f3591 Fix Windows iterator issue in Zip2Iterator and StructureOfArrays (#3322) 2020-12-14 12:14:53 -08:00
Philip Rideout d06cc4390e filamat: minify struct fields.
This shrinks the arm64 so file by 24 KiB.
2020-12-14 11:19:43 -08:00
Philip Rideout 6047d3235f Remove VSM variant from Skybox material. 2020-12-14 11:19:31 -08:00
Philip Rideout 2cda6e35bd math: reduce template bloat for matrices
This does not change our API, it merely reduces the number of
non-inlined function instantiations appearing in non-optimized binaries.
2020-12-14 11:19:22 -08:00
Philip Rideout 8f8d51e17b Code review fixups for libibl_lite. 2020-12-14 11:19:16 -08:00
Philip Rideout 6919e3b274 libibl: use C callback for progress 2020-12-14 11:19:09 -08:00
Philip Rideout 10bf944410 Add libibl_lite. 2020-12-14 11:19:03 -08:00
Philip Rideout 9a2f6fdb53 Vulkan: change vkWaitForFences usage for SwiftShader.
When passing only 1 fence to vkWaitForFences, the `waitAll` argument
should not have any effect, but SwiftShader seems to skip the wait
when this argument is set to VK_FALSE.

More specifically, the failure to wait in `acquireWorkCommandBuffer`
causes the subsequent destruction of an in-use fence, which causes
a TSAN failure with Google's internal tests.

I am consulting with the SwiftShader team on a real fix, meanwhile
we can commit this easy workaround.

We have 5 usages of vkWaitForFences, one of which uses multiple fences
and should have used VK_TRUE anyway.
2020-11-20 09:37:54 -08:00
Philip Rideout 761977d385 Filament should always bind an IBL texture.
This prevents a SwiftShader crash and/or a slew of "no texture bound"
warnings that would appear when the client provides an IBL without
providing reflections texture, which should be a valid thing to do.

Note that it is okay to declare a sampler in GLSL that never gets bound,
as long as it is never sampled from. Since we always sample from the
IBL specular texture, we should always bind something to it.
2020-11-19 13:28:19 -08:00
Ben Doherty 21248f15b5 Fix, matc crash when building mobile materials (#3296) 2020-11-16 14:37:55 -08:00
Benjamin Doherty 4f32817f6d Bump version to 1.9.10 2020-11-16 12:37:49 -08:00
Benjamin Doherty cc9e05e711 Merge branch 'rc/1.9.9' into release 2020-11-16 12:34:13 -08:00
Benjamin Doherty 419d68d4db Update RELEASE_NOTES for 1.9.9 2020-11-16 12:17:02 -08:00
Philip Rideout 8450232448 Improve the "unbound texture" warnings.
With Vulkan, this warning would sometimes be a false positive. It could
trigger for internal samplers like `ssao` and `structure`, even though
they were not declared in SPIR-V.

With OpenGL, this warning would never be a false positive because it has
the luxury of calling `glGetUniformLocation`.

This adds a private attribute to our samplers called `strict` that
indicates whether or not a sampler should always have a bound texture.
For now the only strict samplers are the custom ones declared in the
user's material.

At some point I think we should consider adding `spirv-reflect` to our
tree to help with problems like this.
2020-11-12 16:21:13 -08:00
Philip Rideout cc51726590 Vulkan: improve robustness by providing 1x1 fallback. 2020-11-12 10:36:13 -08:00
Philip Rideout 318e22af51 Fix clear behavior with RenderTarget API.
This fixes a bug seen with client applications that use ClearOptions
instead of Skybox, and one or more offscreen RenderTarget objects.
These apps would see junk pixels because Filament would only clear the
first render target in the frame.

The fix is to factor some the flag-setting logic in `beginFrame()` into
a private method, and call this method from `render()` each time
the user-level RenderTarget has been changed.

I wrote a simple C++ demo to reproduce the issue and to verify that
this fix works.
2020-11-11 09:25:36 -08:00
Philip Rideout 68ac87dc24 NOOP backend should not care about GLSL vs SPIRV.
This fixes errors that would occur when using the NOOP backend with
materials that were built without OpenGL support.
2020-11-10 15:44:01 -08:00
Benjamin Doherty acb8f00075 Bump version to 1.9.9 2020-11-09 09:32:55 -08:00
Benjamin Doherty 06d9183aaa Merge branch 'rc/1.9.8' into release 2020-11-09 09:28:58 -08:00
Benjamin Doherty 75af25419d Update RELEASE_NOTES for 1.9.8 2020-11-09 09:26:27 -08:00
Benjamin Doherty f6b90d2a31 Bump version to 1.9.8 2020-11-09 09:21:36 -08:00
Philip Rideout a3822f4af0 Fix FENCE_WAIT_FOR_EVER in Linux.
The number of infinite nanoseconds was negative because we asked
chrono for a signed integer, so "wait forever" really meant "do not
wait at all".
2020-11-02 16:12:53 -08:00
Benjamin Doherty bcdad769ff Merge branch 'rc/1.9.7' into release 2020-11-02 11:03:57 -07:00
Benjamin Doherty be4fb4fdbb Update RELEASE_NOTES for 1.9.7 2020-11-02 10:59:19 -07:00
Benjamin Doherty 65394f6301 Bump version to 1.9.7 2020-10-26 11:34:20 -06:00
Benjamin Doherty b0beee03bc Merge branch 'rc/1.9.6' into release 2020-10-26 11:29:45 -06:00
Benjamin Doherty fe1de41b8e Update RELEASE_NOTES for 1.9.6 2020-10-26 11:25:31 -06:00
Benjamin Doherty a37b431e87 Bump version to 1.9.6 2020-10-19 11:55:13 -06:00
Benjamin Doherty 98107016b9 Merge branch 'rc/1.9.5' into release 2020-10-19 11:51:30 -06:00
Benjamin Doherty 8bccfc2863 Update RELEASE_NOTES for 1.9.5 2020-10-19 11:49:05 -06:00
Benjamin Doherty f54a0a3452 Fix CocoaPod version 2020-10-13 15:15:02 -06:00
Benjamin Doherty 6778ab0624 Fix CocoaPod version 2020-10-13 15:09:59 -06:00
Benjamin Doherty 269d636785 Bump version to 1.9.5 2020-10-12 12:03:29 -06:00
Benjamin Doherty 39862c91ce Merge branch 'rc/1.9.4' into release 2020-10-12 11:56:24 -06:00
Benjamin Doherty 523f4026b4 Update RELEASE_NOTES for 1.9.4 2020-10-12 11:52:01 -06:00
Benjamin Doherty a6bf162431 Bump version to 1.9.4 2020-10-07 16:06:23 -06:00
Benjamin Doherty 826e8d181c Merge branch 'rc/1.9.3' into release 2020-10-05 11:36:16 -06:00
Benjamin Doherty 16dfadbba0 Update RELEASE_NOTES for 1.9.3 2020-10-05 11:29:36 -06:00
Benjamin Doherty 5cbb97551f Bump version to 1.9.3 2020-09-28 11:40:31 -06:00
Benjamin Doherty defee767c3 Merge branch 'rc/1.9.2' into release 2020-09-28 11:27:47 -06:00
Benjamin Doherty 9560318521 Update RELEASE_NOTES for 1.9.2 2020-09-28 11:26:21 -06:00
Benjamin Doherty ef09feb048 Bump version to 1.9.2 2020-09-21 11:16:53 -06:00
Benjamin Doherty 39f323fe09 Merge branch 'rc/1.9.1' into release 2020-09-21 11:00:07 -06:00
Benjamin Doherty 11b95304ea Merge branch 'release' into rc/1.9.1 2020-09-21 10:59:52 -06:00
Benjamin Doherty b7c30a7916 Update RELEASE_NOTES for 1.9.1 2020-09-21 10:59:06 -06:00
Benjamin Doherty 4cae48fc77 Bump version to 1.9.1 2020-09-14 11:51:36 -07:00
Benjamin Doherty d1a93f0557 Update release notes for 1.9.0 2020-09-14 10:54:28 -07:00
Benjamin Doherty b93059fad7 Bump version to 1.9.0 2020-09-08 10:47:23 -07:00
115 changed files with 2032 additions and 3024 deletions
+1 -24
View File
@@ -41,8 +41,6 @@ option(FILAMENT_LINUX_IS_MOBILE "Treat Linux as Mobile" OFF)
option(FILAMENT_ENABLE_ASAN_UBSAN "Enable Address and Undefined Behavior Sanitizers" OFF)
option(FILAMENT_ENABLE_TSAN "Enable Thread Sanitizer" OFF)
option(FILAMENT_ENABLE_FEATURE_LEVEL_0 "Enable Feature Level 0" ON)
set(FILAMENT_NDK_VERSION "" CACHE STRING
@@ -232,21 +230,6 @@ if (WIN32)
# we don't need them on CI.
string(REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" ${LinkerFlag} ${${LinkerFlag}})
endforeach()
# We turn off compile-time optimizations for CI, as options that speed up the compile-time
# (e.g. /MP) might increase memory usage, leading to instabilities on limited CI machines.
option(FILAMENT_SHORTEN_MSVC_COMPILATION "Shorten compile-time in Visual Studio" OFF)
else()
option(FILAMENT_SHORTEN_MSVC_COMPILATION "Shorten compile-time in Visual Studio" ON)
endif()
if (MSVC)
if (FILAMENT_SHORTEN_MSVC_COMPILATION)
# enable multi-processor compilation
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
# disable run-time STL checks to improve tools (e.g. matc) performance
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_ITERATOR_DEBUG_LEVEL=0")
endif()
endif()
endif()
@@ -428,13 +411,7 @@ endif()
if (FILAMENT_ENABLE_ASAN_UBSAN)
set(EXTRA_SANITIZE_OPTIONS "-fsanitize=address -fsanitize=undefined")
endif()
if (FILAMENT_ENABLE_TSAN)
set(EXTRA_SANITIZE_OPTIONS "-fsanitize=thread")
endif()
if (ANDROID)
# keep STL debug infos (mimics what the NDK does)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-limit-debug-info")
endif()
if (NOT MSVC AND NOT WEBGL)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fstack-protector")
endif()
-1
View File
@@ -8,4 +8,3 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- Metal: fix some shader artifacts by disabling fast math optimizations.
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.49.3'
implementation 'com.google.android.filament:filament-android:1.49.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.49.3'
pod 'Filament', '~> 1.49.0'
```
### Snapshots
+1 -13
View File
@@ -7,22 +7,10 @@ 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.50.0
- engine: TAA now supports 4x upscaling [BETA] [⚠️ **New Material Version**]
## v1.49.3
- matc: Generate stereo variants for FL0 materials [⚠️ **Recompile materials**]
## v1.49.2
## v1.49.1
## v1.49.0
- matc: Fix ESSL 1.0 codegen when using external samplers [⚠️ **Recompile materials**]
- matc: Generate skinning variants for FL0 materials [⚠️ **Recompile materials**]
## v1.48.0
+8 -8
View File
@@ -81,14 +81,14 @@ buildscript {
ext.versions = [
'jdk': 17,
'minSdk': 19,
'targetSdk': 34,
'compileSdk': 34,
'kotlin': '1.9.21',
'kotlin_coroutines': '1.7.3',
'targetSdk': 33,
'compileSdk': 33,
'kotlin': '1.9.0',
'kotlin_coroutines': '1.7.2',
'buildTools': '34.0.0',
'ndk': '26.1.10909125',
'androidx_core': '1.12.0',
'androidx_annotations': '1.7.0'
'ndk': '25.1.8937393',
'androidx_core': '1.10.1',
'androidx_annotations': '1.6.0'
]
ext.deps = [
@@ -104,7 +104,7 @@ buildscript {
]
dependencies {
classpath 'com.android.tools.build:gradle:8.2.0'
classpath 'com.android.tools.build:gradle:8.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
}
@@ -849,10 +849,6 @@ public class Texture {
public static final int SAMPLEABLE = 0x10;
/** Texture can be used as a subpass input */
public static final int SUBPASS_INPUT = 0x20;
/** Texture can be used the source of a blit() */
public static final int BLIT_SRC = 0x40;
/** Texture can be used the destination of a blit() */
public static final int BLIT_DST = 0x80;
/** by default textures are <code>UPLOADABLE</code> and <code>SAMPLEABLE</code>*/
public static final int DEFAULT = UPLOADABLE | SAMPLEABLE;
}
@@ -1093,7 +1093,7 @@ public class View {
* @see #setStereoscopicOptions
*/
@NonNull
public StereoscopicOptions getStereoscopicOptions() {
public StereoscopicOptions getStereoscoopicOptions() {
if (mStereoscopicOptions == null) {
mStereoscopicOptions = new StereoscopicOptions();
}
@@ -1637,10 +1637,6 @@ public class View {
* circle of confusion scale factor (amount of blur)
*/
public float cocScale = 1.0f;
/**
* width/height aspect ratio of the circle of confusion (simulate anamorphic lenses)
*/
public float cocAspectRatio = 1.0f;
/**
* maximum aperture diameter in meters (zero to disable rotation)
*/
@@ -1856,7 +1852,7 @@ public class View {
}
/**
* Options for Multi-Sample Anti-aliasing (MSAA)
* Options for Temporal Multi-Sample Anti-aliasing (MSAA)
* @see setMultiSampleAntiAliasingOptions()
*/
public static class MultiSampleAntiAliasingOptions {
@@ -1880,106 +1876,21 @@ public class View {
/**
* Options for Temporal Anti-aliasing (TAA)
* Most TAA parameters are extremely costly to change, as they will trigger the TAA post-process
* shaders to be recompiled. These options should be changed or set during initialization.
* `filterWidth`, `feedback` and `jitterPattern`, however, could be changed at any time.
*
* `feedback` of 0.1 effectively accumulates a maximum of 19 samples in steady state.
* see "A Survey of Temporal Antialiasing Techniques" by Lei Yang and all for more information.
*
* @see setTemporalAntiAliasingOptions()
*/
public static class TemporalAntiAliasingOptions {
public enum BoxType {
/**
* use an AABB neighborhood
*/
AABB,
/**
* use the variance of the neighborhood (not recommended)
*/
VARIANCE,
/**
* use both AABB and variance
*/
AABB_VARIANCE,
}
public enum BoxClipping {
/**
* Accurate box clipping
*/
ACCURATE,
/**
* clamping
*/
CLAMP,
/**
* no rejections (use for debugging)
*/
NONE,
}
public enum JitterPattern {
RGSS_X4,
UNIFORM_HELIX_X4,
HALTON_23_X8,
HALTON_23_X16,
}
/**
* reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother)
* reconstruction filter width typically between 0 (sharper, aliased) and 1 (smoother)
*/
public float filterWidth = 1.0f;
/**
* history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA).
*/
public float feedback = 0.12f;
/**
* texturing lod bias (typically -1 or -2)
*/
public float lodBias = -1.0f;
public float feedback = 0.04f;
/**
* enables or disables temporal anti-aliasing
*/
public boolean enabled = false;
/**
* 4x TAA upscaling. Disables Dynamic Resolution. [BETA]
*/
public boolean upscaling = false;
/**
* whether to filter the history buffer
*/
public boolean filterHistory = true;
/**
* whether to apply the reconstruction filter to the input
*/
public boolean filterInput = true;
/**
* whether to use the YcoCg color-space for history rejection
*/
public boolean useYCoCg = false;
/**
* type of color gamut box
*/
@NonNull
public TemporalAntiAliasingOptions.BoxType boxType = TemporalAntiAliasingOptions.BoxType.AABB;
/**
* clipping algorithm
*/
@NonNull
public TemporalAntiAliasingOptions.BoxClipping boxClipping = TemporalAntiAliasingOptions.BoxClipping.ACCURATE;
@NonNull
public TemporalAntiAliasingOptions.JitterPattern jitterPattern = TemporalAntiAliasingOptions.JitterPattern.HALTON_23_X16;
public float varianceGamma = 1.0f;
/**
* adjust the feedback dynamically to reduce flickering
*/
public boolean preventFlickering = false;
/**
* whether to apply history reprojection (debug option)
*/
public boolean historyReprojection = true;
}
/**
@@ -329,6 +329,7 @@ public class UiHelper {
@Override
public void detach() {
mTextureView.setSurfaceTextureListener(null);
setSurface(null);
}
@@ -381,7 +382,6 @@ public class UiHelper {
@Override
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureDestroyed()");
setSurface(null);
destroySwapChain();
return true;
}
@@ -445,9 +445,6 @@ public class UiHelper {
* {@link #attachTo(TextureView)}, or {@link #attachTo(SurfaceHolder)}.
*/
public void detach() {
if (mRenderSurface != null) {
mRenderSurface.detach();
}
destroySwapChain();
mNativeWindow = null;
mRenderSurface = null;
@@ -593,10 +590,6 @@ public class UiHelper {
// nothing to do
return false;
}
if (mRenderSurface != null) {
mRenderSurface.detach();
mRenderSurface = null;
}
destroySwapChain();
}
mNativeWindow = nativeWindow;
@@ -611,6 +604,9 @@ public class UiHelper {
}
private void destroySwapChain() {
if (mRenderSurface != null) {
mRenderSurface.detach();
}
if (mRenderCallback != null) {
mRenderCallback.onDetachedFromSurface();
}
@@ -144,7 +144,7 @@ public class FilamentInstance {
*
* Ignored if variantIndex is out of bounds.
*/
public void applyMaterialVariant(@IntRange(from = 0) int variantIndex) {
void applyMaterialVariant(@IntRange(from = 0) int variantIndex) {
nApplyMaterialVariant(mNativeObject, variantIndex);
}
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.49.3
VERSION_NAME=1.49.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+1 -1
View File
@@ -1,6 +1,6 @@
#Wed Nov 17 10:40:18 PST 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
File diff suppressed because one or more lines are too long
Binary file not shown.
+1 -14
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
-3
View File
@@ -587,7 +587,6 @@
<li><em>overrides</em> Dictionary with one or more of the following properties: mapSize, shadowCascades, constantBias, normalBias, shadowFar, shadowNearHint, shadowFarHint, stable, polygonOffsetConstant, polygonOffsetSlope, \</li>
</ul>
</li>
<li><strong>engine.setStereoscopicOptions()</strong></li>
<li><strong>engine.setTemporalAntiAliasingOptions()</strong></li>
<li><strong>engine.setVignetteOptions()</strong></li>
</ul>
@@ -1463,8 +1462,6 @@ This defines the following functions:</p>
<li>STENCIL_ATTACHMENT</li>
<li>UPLOADABLE</li>
<li>SAMPLEABLE</li>
<li>BLIT_SRC</li>
<li>BLIT_DST</li>
<li>SUBPASS_INPUT</li>
</ul>
</div>
Binary file not shown.
Binary file not shown.
+19 -20
View File
@@ -209,13 +209,10 @@ set(PRIVATE_HDRS
)
set(MATERIAL_SRCS
src/materials/antiAliasing/fxaa.mat
src/materials/antiAliasing/taa.mat
src/materials/blitLow.mat
src/materials/bloom/bloomDownsample.mat
src/materials/bloom/bloomDownsample2x.mat
src/materials/bloom/bloomDownsample9.mat
src/materials/bloom/bloomUpsample.mat
src/materials/fsr/fsr_easu.mat
src/materials/fsr/fsr_easu_mobile.mat
src/materials/fsr/fsr_easu_mobileF.mat
src/materials/fsr/fsr_rcas.mat
src/materials/colorGrading/colorGrading.mat
src/materials/colorGrading/colorGradingAsSubpass.mat
src/materials/colorGrading/customResolveAsSubpass.mat
@@ -223,27 +220,29 @@ set(MATERIAL_SRCS
src/materials/defaultMaterial.mat
src/materials/dof/dof.mat
src/materials/dof/dofCoc.mat
src/materials/dof/dofCombine.mat
src/materials/dof/dofDilate.mat
src/materials/dof/dofDownsample.mat
src/materials/dof/dofMedian.mat
src/materials/dof/dofMipmap.mat
src/materials/dof/dofCombine.mat
src/materials/dof/dofTiles.mat
src/materials/dof/dofTilesSwizzle.mat
src/materials/dof/dofDilate.mat
src/materials/dof/dofMipmap.mat
src/materials/dof/dofMedian.mat
src/materials/flare/flare.mat
src/materials/fsr/fsr_easu.mat
src/materials/fsr/fsr_easu_mobile.mat
src/materials/fsr/fsr_easu_mobileF.mat
src/materials/fsr/fsr_rcas.mat
src/materials/resolveDepth.mat
src/materials/separableGaussianBlur.mat
src/materials/skybox.mat
src/materials/bloom/bloomDownsample.mat
src/materials/bloom/bloomDownsample2x.mat
src/materials/bloom/bloomDownsample9.mat
src/materials/bloom/bloomUpsample.mat
src/materials/ssao/bilateralBlur.mat
src/materials/ssao/bilateralBlurBentNormals.mat
src/materials/ssao/mipmapDepth.mat
src/materials/skybox.mat
src/materials/ssao/sao.mat
src/materials/ssao/saoBentNormals.mat
src/materials/separableGaussianBlur.mat
src/materials/antiAliasing/fxaa.mat
src/materials/antiAliasing/taa.mat
src/materials/vsmMipmap.mat
src/materials/blitLow.mat
)
set(MATERIAL_FL0_SRCS
@@ -321,7 +320,7 @@ foreach (mat_src ${MATERIAL_SRCS})
list(APPEND MATERIAL_BINS ${output_path})
endforeach()
if (FILAMENT_ENABLE_FEATURE_LEVEL_0)
if (FILAMENT_ENABLE_FEATURE_LEVEL_0 AND FILAMENT_SUPPORTS_OPENGL)
foreach (mat_src ${MATERIAL_FL0_SRCS})
get_filename_component(localname "${mat_src}" NAME_WE)
get_filename_component(fullname "${mat_src}" ABSOLUTE)
@@ -329,7 +328,7 @@ if (FILAMENT_ENABLE_FEATURE_LEVEL_0)
add_custom_command(
OUTPUT ${output_path}
COMMAND matc ${MATC_BASE_FLAGS} -o ${output_path} ${fullname}
COMMAND matc -a opengl -p ${MATC_TARGET} ${MATC_OPT_FLAGS} -o ${output_path} ${fullname}
MAIN_DEPENDENCY ${fullname}
DEPENDS matc
COMMENT "Compiling material ${mat_src} to ${output_path}"
+5 -19
View File
@@ -227,7 +227,6 @@ struct Viewport {
int32_t top() const noexcept { return bottom + int32_t(height); }
};
/**
* Specifies the mapping of the near and far clipping plane to window coordinates.
*/
@@ -659,15 +658,13 @@ enum class TextureFormat : uint16_t {
//! Bitmask describing the intended Texture Usage
enum class TextureUsage : uint8_t {
NONE = 0x00,
COLOR_ATTACHMENT = 0x01, //!< Texture can be used as a color attachment
DEPTH_ATTACHMENT = 0x02, //!< Texture can be used as a depth attachment
STENCIL_ATTACHMENT = 0x04, //!< Texture can be used as a stencil attachment
UPLOADABLE = 0x08, //!< Data can be uploaded into this texture (default)
NONE = 0x0,
COLOR_ATTACHMENT = 0x1, //!< Texture can be used as a color attachment
DEPTH_ATTACHMENT = 0x2, //!< Texture can be used as a depth attachment
STENCIL_ATTACHMENT = 0x4, //!< Texture can be used as a stencil attachment
UPLOADABLE = 0x8, //!< Data can be uploaded into this texture (default)
SAMPLEABLE = 0x10, //!< Texture can be sampled (default)
SUBPASS_INPUT = 0x20, //!< Texture can be used as a subpass input
BLIT_SRC = 0x40, //!< Texture can be used the source of a blit()
BLIT_DST = 0x80, //!< Texture can be used the destination of a blit()
DEFAULT = UPLOADABLE | SAMPLEABLE //!< Default texture usage
};
@@ -695,17 +692,6 @@ static constexpr bool isDepthFormat(TextureFormat format) noexcept {
}
}
static constexpr bool isStencilFormat(TextureFormat format) noexcept {
switch (format) {
case TextureFormat::STENCIL8:
case TextureFormat::DEPTH24_STENCIL8:
case TextureFormat::DEPTH32F_STENCIL8:
return true;
default:
return false;
}
}
static constexpr bool isUnsignedIntFormat(TextureFormat format) {
switch (format) {
case TextureFormat::R8UI:
@@ -300,10 +300,10 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isAutoDepthResolveSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isSRGBSwapChainSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isStereoSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isParallelShaderCompileSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthStencilResolveSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers)
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize)
DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, canGenerateMipmaps)
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage, void*, image)
DECL_DRIVER_API_SYNCHRONOUS_N(bool, getTimerQueryValue, backend::TimerQueryHandle, query, uint64_t*, elapsedTime)
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isWorkaroundNeeded, backend::Workaround, workaround)
@@ -468,7 +468,7 @@ DECL_DRIVER_API_N(readBufferSubData,
* --------------------
*/
DECL_DRIVER_API_N(blitDEPRECATED,
DECL_DRIVER_API_N(blit,
backend::TargetBufferFlags, buffers,
backend::RenderTargetHandle, dst,
backend::Viewport, dstRect,
@@ -476,21 +476,6 @@ DECL_DRIVER_API_N(blitDEPRECATED,
backend::Viewport, srcRect,
backend::SamplerMagFilter, filter)
DECL_DRIVER_API_N(resolve,
backend::TextureHandle, dst,
uint8_t, dstLevel, uint8_t, dstLayer,
backend::TextureHandle, src,
uint8_t, srcLevel, uint8_t, srcLayer)
DECL_DRIVER_API_N(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)
DECL_DRIVER_API_N(draw,
backend::PipelineState, state,
backend::RenderPrimitiveHandle, rph,
+51 -24
View File
@@ -24,7 +24,8 @@
#include <tsl/robin_map.h>
#include <utils/Hash.h>
namespace filament::backend {
namespace filament {
namespace backend {
struct MetalContext;
@@ -36,7 +37,8 @@ public:
struct BlitArgs {
struct Attachment {
id<MTLTexture> texture = nil;
id<MTLTexture> color = nil;
id<MTLTexture> depth = nil;
MTLRegion region = {};
uint8_t level = 0;
uint32_t slice = 0; // must be 0 on source attachment
@@ -44,13 +46,25 @@ public:
// Valid source formats: 2D, 2DArray, 2DMultisample, 3D
// Valid destination formats: 2D, 2DArray, 3D, Cube
Attachment source;
Attachment destination;
Attachment source, destination;
SamplerMagFilter filter;
bool destinationIsFullAttachment() const {
return destination.texture.width == destination.region.size.width &&
destination.texture.height == destination.region.size.height;
bool blitColor() const {
return source.color != nil && destination.color != nil;
}
bool blitDepth() const {
return source.depth != nil && destination.depth != nil;
}
bool colorDestinationIsFullAttachment() const {
return destination.color.width == destination.region.size.width &&
destination.color.height == destination.region.size.height;
}
bool depthDestinationIsFullAttachment() const {
return destination.depth.width == destination.region.size.width &&
destination.depth.height == destination.region.size.height;
}
};
@@ -64,36 +78,48 @@ public:
private:
static void setupAttachment(MTLRenderPassAttachmentDescriptor* descriptor,
const BlitArgs& args, uint32_t depthPlane);
static void setupColorAttachment(const BlitArgs& args, MTLRenderPassDescriptor* descriptor,
uint32_t depthPlane);
static void setupDepthAttachment(const BlitArgs& args, MTLRenderPassDescriptor* descriptor,
uint32_t depthPlane);
struct BlitFunctionKey {
bool msaaColorSource{};
bool sources3D{};
char padding[2]{};
bool blitColor;
bool blitDepth;
bool msaaColorSource;
bool msaaDepthSource;
bool sources3D;
char padding[3];
bool isValid() const noexcept {
// MSAA 3D textures do not exist.
bool const hasMsaa = msaaColorSource;
bool hasMsaa = msaaColorSource || msaaDepthSource;
return !(hasMsaa && sources3D);
}
bool operator==(const BlitFunctionKey& rhs) const noexcept {
return msaaColorSource == rhs.msaaColorSource &&
return blitColor == rhs.blitColor &&
blitDepth == rhs.blitDepth &&
msaaColorSource == rhs.msaaColorSource &&
msaaDepthSource == rhs.msaaDepthSource &&
sources3D == rhs.sources3D;
}
BlitFunctionKey() {
std::memset(this, 0, sizeof(BlitFunctionKey));
}
};
static bool blitFastPath(id<MTLCommandBuffer> cmdBuffer,
void blitFastPath(id<MTLCommandBuffer> cmdBuffer, bool& blitColor, bool& blitDepth,
const BlitArgs& args, const char* label);
void blitSlowPath(id<MTLCommandBuffer> cmdBuffer,
void blitSlowPath(id<MTLCommandBuffer> cmdBuffer, bool& blitColor, bool& blitDepth,
const BlitArgs& args, const char* label);
void blitDepthPlane(id <MTLCommandBuffer> cmdBuffer, const BlitArgs& args,
uint32_t depthPlaneSource, uint32_t depthPlaneDest, const char* label);
id<MTLFunction> compileFragmentFunction(BlitFunctionKey key) const;
void blitDepthPlane(id<MTLCommandBuffer> cmdBuffer, bool blitColor, bool blitDepth,
const BlitArgs& args, uint32_t depthPlaneSource, uint32_t depthPlaneDest,
const char* label);
id<MTLTexture> createIntermediateTexture(id<MTLTexture> t, MTLSize size);
id<MTLFunction> compileFragmentFunction(BlitFunctionKey key);
id<MTLFunction> getBlitVertexFunction();
id<MTLFunction> getBlitFragmentFunction(BlitFunctionKey key);
@@ -104,9 +130,10 @@ private:
tsl::robin_map<BlitFunctionKey, Function, HashFn> mBlitFunctions;
id<MTLFunction> mVertexFunction = nil;
};
} // namespace filament::backend
} // namespace backend
} // namespace filament
#endif //TNT_METALBLITTER_H
+264 -100
View File
@@ -21,7 +21,8 @@
#include <utils/Panic.h>
namespace filament::backend {
namespace filament {
namespace backend {
static const char* functionLibrary = R"(
#include <metal_stdlib>
@@ -36,7 +37,13 @@ struct VertexOut
struct FragmentOut
{
#ifdef BLIT_COLOR
float4 color [[color(0)]];
#endif
#ifdef BLIT_DEPTH
float depth [[depth(any)]];
#endif
};
vertex VertexOut
@@ -60,6 +67,7 @@ fragment FragmentOut
blitterFrag(VertexOut in [[stage_in]],
sampler sourceSampler [[sampler(0)]],
#ifdef BLIT_COLOR
#ifdef MSAA_COLOR_SOURCE
texture2d_ms<float, access::read> sourceColor [[texture(0)]],
#elif SOURCES_3D
@@ -67,18 +75,32 @@ blitterFrag(VertexOut in [[stage_in]],
#else
texture2d<float, access::sample> sourceColor [[texture(0)]],
#endif // MSAA_COLOR_SOURCE
#endif // BLIT_COLOR
#ifdef BLIT_DEPTH
#ifdef MSAA_DEPTH_SOURCE
texture2d_ms<float, access::read> sourceDepth [[texture(1)]],
#elif SOURCES_3D
texture3d<float, access::sample> sourceDepth [[texture(1)]],
#else
texture2d<float, access::sample> sourceDepth [[texture(1)]],
#endif // MSAA_DEPTH_SOURCE
#endif // BLIT_DEPTH
constant FragmentArgs* args [[buffer(0)]])
{
FragmentOut out = {};
#if defined(BLIT_COLOR) || defined(BLIT_DEPTH)
// These coordinates match the Vulkan vkCmdBlitImage spec:
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCmdBlitImage.html
float2 uvbase = in.position.xy; // unnormalized coordinates at center of texel: (1.5, 2.5, etc)
float2 uvoffset = uvbase - args->dstOffset;
float2 uvscaled = uvoffset * args->scale;
float2 uv = uvscaled + args->srcOffset;
#endif
#ifdef BLIT_COLOR
#ifdef MSAA_COLOR_SOURCE
out.color = float4(0.0);
for (uint s = 0; s < sourceColor.get_num_samples(); s++) {
@@ -94,106 +116,201 @@ blitterFrag(VertexOut in [[stage_in]],
float2 uvnorm = uv / float2(sourceColor.get_width(args->lod), sourceColor.get_height(args->lod));
out.color += sourceColor.sample(sourceSampler, uvnorm, level(args->lod));
#endif // MSAA_COLOR_SOURCE
#endif // BLIT_COLOR
#ifdef BLIT_DEPTH
#ifdef MSAA_DEPTH_SOURCE
out.depth = 0.0;
for (uint s = 0; s < sourceDepth.get_num_samples(); s++) {
out.depth += sourceDepth.read(static_cast<uint2>(uv), s).r;
}
out.depth /= sourceDepth.get_num_samples();
#elif SOURCES_3D
float2 uvnormd = uv / float2(sourceDepth.get_width(args->lod), sourceDepth.get_height(args->lod));
float3 coords = float3(uvnormd, (static_cast<float>(args->depthPlane) + 0.5) /
sourceDepth.get_depth(args->lod));
out.depth = sourceDepth.sample(sourceSampler, coords, level(args->lod)).r;
#else
float2 uvnormd = uv / float2(sourceDepth.get_width(args->lod), sourceDepth.get_height(args->lod));
out.depth = sourceDepth.sample(sourceSampler, uvnormd, level(args->lod)).r;
#endif // MSAA_DEPTH_SOURCE
#endif // BLIT_DEPTH
return out;
}
)";
template<typename T>
inline bool MTLSizeEqual(T a, T b) noexcept {
return (a.width == b.width && a.height == b.height && a.depth == b.depth);
}
MetalBlitter::MetalBlitter(MetalContext& context) noexcept : mContext(context) { }
#define MTLSizeEqual(a, b) (a.width == b.width && a.height == b.height && a.depth == b.depth)
void MetalBlitter::blit(id<MTLCommandBuffer> cmdBuffer, const BlitArgs& args, const char* label) {
bool blitColor = args.blitColor();
bool blitDepth = args.blitDepth();
ASSERT_PRECONDITION(args.source.region.size.depth == args.destination.region.size.depth,
"Blitting requires the source and destination regions to have the same depth.");
if (args.source.color && args.source.depth) {
MTLTextureType colorType = args.source.color.textureType;
MTLTextureType depthType = args.source.depth.textureType;
if (colorType == MTLTextureType2DMultisample) colorType = MTLTextureType2D;
if (depthType == MTLTextureType2DMultisample) depthType = MTLTextureType2D;
ASSERT_PRECONDITION(colorType == depthType,
"Blitting requires color and depth sources to be the same texture type.");
}
// Determine if the blit for color or depth are eligible to use a MTLBlitCommandEncoder.
// blitFastPath returns true upon success.
// blitFastPath fails if either the format or sampleCount don't match (i.e. resolve)
if (blitFastPath(cmdBuffer, args, label)) {
// blitColor and / or blitDepth are set to false upon success, to indicate that no more work is
// necessary for that attachment.
blitFastPath(cmdBuffer, blitColor, blitDepth, args, label);
if (!blitColor && !blitDepth) {
return;
}
// If we end-up here, it means that either:
// - we're resolving a color texture
// - src/dest formats didn't match, or we're scaling -- this can only happen with the legacy
// blit() path and implies that the format is not depth.
// note: in the future we will support a fast-path resolve
// If the destination is MSAA and we weren't able to use the fast path, report an error, as
// blitting to a MSAA texture isn't supported through the "slow path" yet.
const bool colorDestinationIsMultisample =
blitColor && args.destination.color.textureType == MTLTextureType2DMultisample;
const bool depthDestinationIsMultisample =
blitDepth && args.destination.depth.textureType == MTLTextureType2DMultisample;
ASSERT_PRECONDITION(!colorDestinationIsMultisample && !depthDestinationIsMultisample,
"Blitting between MSAA render targets with differing pixel formats and/or regions is not supported.");
UTILS_UNUSED_IN_RELEASE
const bool destinationIsMultisample =
args.destination.texture.textureType == MTLTextureType2DMultisample;
// If the destination texture doesn't have the MTLTextureUsageRenderTarget flag, we have to blit
// to an intermediate texture first to perform the format conversion. Then, we can perform a
// "fast blit" to the final destination texture.
assert_invariant(!destinationIsMultisample);
assert_invariant((args.destination.texture.usage & MTLTextureUsageRenderTarget));
blitSlowPath(cmdBuffer, args, label);
}
id<MTLTexture> intermediateColor = nil;
id<MTLTexture> intermediateDepth = nil;
BlitArgs slowBlit = args;
BlitArgs finalBlit = args;
bool MetalBlitter::blitFastPath(id<MTLCommandBuffer> cmdBuffer,
const BlitArgs& args, const char* label) {
MTLRegion sourceRegionNoOffset = MTLRegionMake3D(0, 0, 0,
args.source.region.size.width, args.source.region.size.height,
args.source.region.size.depth);
if (args.source.texture.sampleCount == args.destination.texture.sampleCount &&
args.source.texture.pixelFormat == args.destination.texture.pixelFormat &&
MTLSizeEqual(args.source.region.size, args.destination.region.size)) {
id<MTLBlitCommandEncoder> const blitEncoder = [cmdBuffer blitCommandEncoder];
blitEncoder.label = @(label);
[blitEncoder copyFromTexture:args.source.texture
sourceSlice:args.source.slice
sourceLevel:args.source.level
sourceOrigin:args.source.region.origin
sourceSize:args.source.region.size
toTexture:args.destination.texture
destinationSlice:args.destination.slice
destinationLevel:args.destination.level
destinationOrigin:args.destination.region.origin];
[blitEncoder endEncoding];
return true;
if (blitColor && !(args.destination.color.usage & MTLTextureUsageRenderTarget)) {
intermediateColor = createIntermediateTexture(args.destination.color, args.source.region.size);
slowBlit.destination.color = finalBlit.source.color = intermediateColor;
slowBlit.destination.level = finalBlit.source.level = 0;
slowBlit.destination.slice = finalBlit.source.slice = 0;
slowBlit.destination.region = finalBlit.source.region = sourceRegionNoOffset;
}
return false;
if (blitDepth && !(args.destination.depth.usage & MTLTextureUsageRenderTarget)) {
intermediateDepth = createIntermediateTexture(args.destination.depth, args.source.region.size);
slowBlit.destination.depth = finalBlit.source.depth = intermediateDepth;
slowBlit.destination.level = finalBlit.source.level = 0;
slowBlit.destination.slice = finalBlit.source.slice = 0;
slowBlit.destination.region = finalBlit.source.region = sourceRegionNoOffset;
}
blitSlowPath(cmdBuffer, blitColor, blitDepth, slowBlit, label);
bool finalBlitColor = intermediateColor != nil;
bool finalBlitDepth = intermediateDepth != nil;
blitFastPath(cmdBuffer, finalBlitColor, finalBlitDepth, finalBlit, label);
}
void MetalBlitter::blitSlowPath(id<MTLCommandBuffer> cmdBuffer,
void MetalBlitter::blitFastPath(id<MTLCommandBuffer> cmdBuffer, bool& blitColor, bool& blitDepth,
const BlitArgs& args, const char* label) {
// scaling in any dimension is not allowed
assert_invariant(args.source.region.size.depth == args.destination.region.size.depth);
// we're always blitting a single plane
if (blitColor) {
if (args.source.color.sampleCount == args.destination.color.sampleCount &&
args.source.color.pixelFormat == args.destination.color.pixelFormat &&
MTLSizeEqual(args.source.region.size, args.destination.region.size)) {
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
blitEncoder.label = @(label);
[blitEncoder copyFromTexture:args.source.color
sourceSlice:args.source.slice
sourceLevel:args.source.level
sourceOrigin:args.source.region.origin
sourceSize:args.source.region.size
toTexture:args.destination.color
destinationSlice:args.destination.slice
destinationLevel:args.destination.level
destinationOrigin:args.destination.region.origin];
[blitEncoder endEncoding];
blitColor = false;
}
}
if (blitDepth) {
if (args.source.depth.sampleCount == args.destination.depth.sampleCount &&
args.source.depth.pixelFormat == args.destination.depth.pixelFormat &&
MTLSizeEqual(args.source.region.size, args.destination.region.size)) {
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
blitEncoder.label = @(label);
[blitEncoder copyFromTexture:args.source.depth
sourceSlice:args.source.slice
sourceLevel:args.source.level
sourceOrigin:args.source.region.origin
sourceSize:args.source.region.size
toTexture:args.destination.depth
destinationSlice:args.destination.slice
destinationLevel:args.destination.level
destinationOrigin:args.destination.region.origin];
[blitEncoder endEncoding];
blitDepth = false;
}
}
}
void MetalBlitter::blitSlowPath(id<MTLCommandBuffer> cmdBuffer, bool& blitColor, bool& blitDepth,
const BlitArgs& args, const char* label) {
uint32_t depthPlaneSource = args.source.region.origin.z;
uint32_t depthPlaneDest = args.destination.region.origin.z;
for (NSUInteger d = 0; d < args.source.region.size.depth; d++) {
blitDepthPlane(cmdBuffer, args,
depthPlaneSource++, depthPlaneDest++, label);
assert_invariant(args.source.region.size.depth == args.destination.region.size.depth);
uint32_t depthPlaneCount = args.source.region.size.depth;
for (NSUInteger d = 0; d < depthPlaneCount; d++) {
blitDepthPlane(cmdBuffer, blitColor, blitDepth, args, depthPlaneSource++, depthPlaneDest++,
label);
}
blitColor = false;
blitDepth = false;
}
void MetalBlitter::blitDepthPlane(id<MTLCommandBuffer> cmdBuffer, const BlitArgs& args,
uint32_t depthPlaneSource, uint32_t depthPlaneDest, const char* label) {
void MetalBlitter::blitDepthPlane(id<MTLCommandBuffer> cmdBuffer, bool blitColor, bool blitDepth,
const BlitArgs& args, uint32_t depthPlaneSource, uint32_t depthPlaneDest,
const char* label) {
MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
MTLRenderPassDescriptor* const descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
if (blitColor) {
setupColorAttachment(args, descriptor, depthPlaneDest);
}
setupAttachment(descriptor.colorAttachments[0], args, depthPlaneDest);
if (blitDepth) {
setupDepthAttachment(args, descriptor, depthPlaneDest);
}
id<MTLRenderCommandEncoder> const encoder =
[cmdBuffer renderCommandEncoderWithDescriptor:descriptor];
id<MTLRenderCommandEncoder> encoder = [cmdBuffer renderCommandEncoderWithDescriptor:descriptor];
encoder.label = @(label);
BlitFunctionKey key;
key.msaaColorSource = args.source.texture.textureType == MTLTextureType2DMultisample;
key.sources3D = args.source.texture.textureType == MTLTextureType3D;
id<MTLFunction> const fragmentFunction = getBlitFragmentFunction(key);
key.blitColor = blitColor;
key.blitDepth = blitDepth;
key.msaaColorSource = blitColor && args.source.color.textureType == MTLTextureType2DMultisample;
key.msaaDepthSource = blitDepth && args.source.depth.textureType == MTLTextureType2DMultisample;
key.sources3D = blitColor && args.source.color.textureType == MTLTextureType3D;
if (key.sources3D && blitDepth) {
assert_invariant(args.source.depth.textureType == MTLTextureType3D);
}
id<MTLFunction> fragmentFunction = getBlitFragmentFunction(key);
MetalPipelineState const pipelineState {
MetalPipelineState pipelineState {
.vertexFunction = getBlitVertexFunction(),
.fragmentFunction = fragmentFunction,
.vertexDescription = {},
.colorAttachmentPixelFormat = {
args.destination.texture.pixelFormat,
blitColor ? args.destination.color.pixelFormat : MTLPixelFormatInvalid,
MTLPixelFormatInvalid,
MTLPixelFormatInvalid,
MTLPixelFormatInvalid,
@@ -202,21 +319,31 @@ void MetalBlitter::blitDepthPlane(id<MTLCommandBuffer> cmdBuffer, const BlitArgs
MTLPixelFormatInvalid,
MTLPixelFormatInvalid
},
.depthAttachmentPixelFormat = MTLPixelFormatInvalid,
.depthAttachmentPixelFormat =
blitDepth ? args.destination.depth.pixelFormat : MTLPixelFormatInvalid,
.sampleCount = 1,
.blendState = {}
};
id<MTLRenderPipelineState> const pipeline =
mContext.pipelineStateCache.getOrCreateState(pipelineState);
id<MTLRenderPipelineState> pipeline = mContext.pipelineStateCache.getOrCreateState(pipelineState);
[encoder setRenderPipelineState:pipeline];
// For texture arrays, create a view of the texture at the given slice (layer).
id<MTLTexture> srcTextureColor = args.source.texture;
id<MTLTexture> srcTextureColor = args.source.color;
if (srcTextureColor && srcTextureColor.textureType == MTLTextureType2DArray) {
srcTextureColor = createTextureViewWithSingleSlice(srcTextureColor, args.source.slice);
}
[encoder setFragmentTexture:srcTextureColor atIndex:0];
id<MTLTexture> srcTextureDepth = args.source.depth;
if (srcTextureDepth && srcTextureDepth.textureType == MTLTextureType2DArray) {
srcTextureDepth = createTextureViewWithSingleSlice(srcTextureDepth, args.source.slice);
}
if (blitColor) {
[encoder setFragmentTexture:srcTextureColor atIndex:0];
}
if (blitDepth) {
[encoder setFragmentTexture:srcTextureDepth atIndex:1];
}
SamplerMinFilter filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST;
if (args.filter == SamplerMagFilter::NEAREST) {
@@ -225,13 +352,13 @@ void MetalBlitter::blitDepthPlane(id<MTLCommandBuffer> cmdBuffer, const BlitArgs
filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST;
}
SamplerState const s {
SamplerState s {
.samplerParams = {
.filterMag = args.filter,
.filterMin = filterMin
}
};
id<MTLSamplerState> const sampler = mContext.samplerStateCache.getOrCreateState(s);
id<MTLSamplerState> sampler = mContext.samplerStateCache.getOrCreateState(s);
[encoder setFragmentSamplerState:sampler atIndex:0];
MTLViewport viewport;
@@ -243,11 +370,11 @@ void MetalBlitter::blitDepthPlane(id<MTLCommandBuffer> cmdBuffer, const BlitArgs
viewport.zfar = 1.0;
[encoder setViewport:viewport];
DepthStencilState const depthStencilState {
DepthStencilState depthStencilState {
.depthCompare = MTLCompareFunctionAlways,
.depthWriteEnabled = false
.depthWriteEnabled = blitDepth
};
id<MTLDepthStencilState> const depthStencil =
id<MTLDepthStencilState> depthStencil =
mContext.depthStencilStateCache.getOrCreateState(depthStencilState);
[encoder setDepthStencilState:depthStencil];
@@ -283,42 +410,80 @@ void MetalBlitter::blitDepthPlane(id<MTLCommandBuffer> cmdBuffer, const BlitArgs
[encoder endEncoding];
}
id<MTLTexture> MetalBlitter::createIntermediateTexture(id<MTLTexture> t, MTLSize size) {
MTLTextureDescriptor* descriptor = [MTLTextureDescriptor new];
descriptor.textureType = size.depth == 1 ? MTLTextureType2D : MTLTextureType3D;
descriptor.pixelFormat = t.pixelFormat;
descriptor.width = size.width;
descriptor.height = size.height;
descriptor.depth = size.depth;
descriptor.usage = t.usage & MTLTextureUsageRenderTarget;
return [mContext.device newTextureWithDescriptor:descriptor];
}
void MetalBlitter::shutdown() noexcept {
mBlitFunctions.clear();
mVertexFunction = nil;
}
void MetalBlitter::setupAttachment(MTLRenderPassAttachmentDescriptor* descriptor,
const BlitArgs& args, uint32_t depthPlane) {
descriptor.texture = args.destination.texture;
descriptor.level = args.destination.level;
descriptor.slice = args.destination.slice;
descriptor.depthPlane = depthPlane;
descriptor.loadAction = MTLLoadActionLoad;
void MetalBlitter::setupColorAttachment(const BlitArgs& args,
MTLRenderPassDescriptor* descriptor, uint32_t depthPlane) {
descriptor.colorAttachments[0].texture = args.destination.color;
descriptor.colorAttachments[0].level = args.destination.level;
descriptor.colorAttachments[0].slice = args.destination.slice;
descriptor.colorAttachments[0].depthPlane = depthPlane;
descriptor.colorAttachments[0].loadAction = MTLLoadActionLoad;
// We don't need to load the contents of the attachment if we're blitting over all of it.
if (args.destinationIsFullAttachment()) {
descriptor.loadAction = MTLLoadActionDontCare;
if (args.colorDestinationIsFullAttachment()) {
descriptor.colorAttachments[0].loadAction = MTLLoadActionDontCare;
}
descriptor.storeAction = MTLStoreActionStore;
descriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
}
id<MTLFunction> MetalBlitter::compileFragmentFunction(BlitFunctionKey key) const {
MTLCompileOptions* const options = [MTLCompileOptions new];
NSMutableDictionary* const macros = [NSMutableDictionary dictionary];
void MetalBlitter::setupDepthAttachment(const BlitArgs& args, MTLRenderPassDescriptor* descriptor,
uint32_t depthPlane) {
descriptor.depthAttachment.texture = args.destination.depth;
descriptor.depthAttachment.level = args.destination.level;
descriptor.depthAttachment.slice = args.destination.slice;
descriptor.depthAttachment.depthPlane = depthPlane;
descriptor.depthAttachment.loadAction = MTLLoadActionLoad;
// We don't need to load the contents of the attachment if we're blitting over all of it.
if (args.depthDestinationIsFullAttachment()) {
descriptor.depthAttachment.loadAction = MTLLoadActionDontCare;
}
descriptor.depthAttachment.storeAction = MTLStoreActionStore;
}
id<MTLFunction> MetalBlitter::compileFragmentFunction(BlitFunctionKey key) {
MTLCompileOptions* options = [MTLCompileOptions new];
NSMutableDictionary* macros = [NSMutableDictionary dictionary];
if (key.blitColor) {
macros[@"BLIT_COLOR"] = @"1";
}
if (key.blitDepth) {
macros[@"BLIT_DEPTH"] = @"1";
}
if (key.msaaColorSource) {
macros[@"MSAA_COLOR_SOURCE"] = @"1";
}
if (key.msaaDepthSource) {
macros[@"MSAA_DEPTH_SOURCE"] = @"1";
}
if (key.sources3D) {
macros[@"SOURCES_3D"] = @"1";
}
options.preprocessorMacros = macros;
NSString* const objcSource = [NSString stringWithCString:functionLibrary
encoding:NSUTF8StringEncoding];
NSString* objcSource = [NSString stringWithCString:functionLibrary
encoding:NSUTF8StringEncoding];
NSError* error = nil;
id <MTLLibrary> const library = [mContext.device newLibraryWithSource:objcSource
options:options
error:&error];
id <MTLFunction> const function = [library newFunctionWithName:@"blitterFrag"];
id<MTLLibrary> library = [mContext.device newLibraryWithSource:objcSource
options:options
error:&error];
id<MTLFunction> function = [library newFunctionWithName:@"blitterFrag"];
if (!library || !function) {
if (error) {
@@ -336,14 +501,13 @@ id<MTLFunction> MetalBlitter::getBlitVertexFunction() {
return mVertexFunction;
}
NSString* const objcSource = [NSString stringWithCString:functionLibrary
encoding:NSUTF8StringEncoding];
NSString* objcSource = [NSString stringWithCString:functionLibrary
encoding:NSUTF8StringEncoding];
NSError* error = nil;
id <MTLLibrary> const library = [mContext.device newLibraryWithSource:objcSource
options:nil
error:&error];
id<MTLFunction> const function = [library newFunctionWithName:@"blitterVertex"];
id<MTLLibrary> library = [mContext.device newLibraryWithSource:objcSource
options:nil
error:&error];
id<MTLFunction> function = [library newFunctionWithName:@"blitterVertex"];
if (!library || !function) {
if (error) {
@@ -371,5 +535,5 @@ id<MTLFunction> MetalBlitter::getBlitFragmentFunction(BlitFunctionKey key) {
return function;
}
} // namespace filament::backend
} // namespace backend
} // namespace filament
+1 -4
View File
@@ -73,10 +73,7 @@ private:
std::unordered_set<MetalBufferPoolEntry const*> mUsedStages;
// Store the current "time" (really just a frame count) and LRU eviction parameters.
// An atomic is necessary as mCurrentFrame is incremented in gc() (called on
// the driver thread) and read from acquireBuffer() and releaseBuffer(),
// which may be called on non-driver threads.
std::atomic<uint64_t> mCurrentFrame = 0;
uint64_t mCurrentFrame = 0;
static constexpr uint32_t TIME_BEFORE_EVICTION = 10;
};
+1 -4
View File
@@ -142,10 +142,7 @@ struct MetalContext {
// Fences, only supported on macOS 10.14 and iOS 12 and above.
API_AVAILABLE(macos(10.14), ios(12.0))
MTLSharedEventListener* eventListener = nil;
// signalId is incremented in the MetalFence constructor, which is called on
// both the driver (MetalTimerQueryFence::beginTimeElapsedQuery) and main
// threads (in createFenceS), so an atomic is necessary.
std::atomic<uint64_t> signalId = 1;
uint64_t signalId = 1;
MetalTimerQueryInterface* timerQueryImpl;
+1 -12
View File
@@ -28,10 +28,6 @@
#include <utils/Log.h>
#include <utils/debug.h>
#include <functional>
#include <mutex>
#include <vector>
namespace filament {
namespace backend {
@@ -56,13 +52,13 @@ class MetalDriver final : public DriverBase {
public:
static Driver* create(MetalPlatform* platform, const Platform::DriverConfig& driverConfig);
void runAtNextTick(const std::function<void()>& fn) noexcept;
private:
friend class MetalSwapChain;
MetalPlatform& mPlatform;
MetalContext* mContext;
ShaderModel getShaderModel() const noexcept final;
@@ -70,13 +66,6 @@ private:
// Overrides the default implementation by wrapping the call to fn in an @autoreleasepool block.
void execute(std::function<void(void)> const& fn) noexcept final;
/*
* Tasks run regularly on the driver thread.
*/
void executeTickOps() noexcept;
std::vector<std::function<void()>> mTickOps;
std::mutex mTickOpsLock;
/*
* Driver interface
*/
+69 -160
View File
@@ -166,7 +166,6 @@ MetalDriver::~MetalDriver() noexcept {
}
void MetalDriver::tick(int) {
executeTickOps();
}
void MetalDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) {
@@ -584,8 +583,6 @@ void MetalDriver::terminate() {
// This must be done before calling bufferPool->reset() to ensure no buffers are in flight.
finish();
executeTickOps();
mContext->bufferPool->reset();
mContext->commandQueue = nil;
@@ -730,10 +727,6 @@ bool MetalDriver::isParallelShaderCompileSupported() {
return true;
}
bool MetalDriver::isDepthStencilResolveSupported() {
return false;
}
bool MetalDriver::isWorkaroundNeeded(Workaround workaround) {
switch (workaround) {
case Workaround::SPLIT_EASU:
@@ -872,6 +865,10 @@ void MetalDriver::generateMipmaps(Handle<HwTexture> th) {
tex->generateMipmaps();
}
bool MetalDriver::canGenerateMipmaps() {
return true;
}
void MetalDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh, BufferDescriptor&& data) {
ASSERT_PRECONDITION(!isInRenderPass(mContext),
"updateSamplerGroup must be called outside of a render pass.");
@@ -1259,14 +1256,14 @@ void MetalDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y,
textureDescriptor.usage = MTLTextureUsageShaderWrite | MTLTextureUsageRenderTarget;
id<MTLTexture> readPixelsTexture = [mContext->device newTextureWithDescriptor:textureDescriptor];
MetalBlitter::BlitArgs args{};
MetalBlitter::BlitArgs args;
args.filter = SamplerMagFilter::NEAREST;
args.source.level = miplevel;
args.source.region = MTLRegionMake2D(0, 0, srcTexture.width >> miplevel, srcTexture.height >> miplevel);
args.source.texture = srcTexture;
args.destination.level = 0;
args.destination.region = MTLRegionMake2D(0, 0, readPixelsTexture.width, readPixelsTexture.height);
args.destination.texture = readPixelsTexture;
args.source.color = srcTexture;
args.destination.color = readPixelsTexture;
mContext->blitter->blit(getPendingCommandBuffer(mContext), args, "readPixels blit");
@@ -1302,123 +1299,24 @@ void MetalDriver::readBufferSubData(backend::BufferObjectHandle boh,
scheduleDestroy(std::move(p));
}
void MetalDriver::resolve(
Handle<HwTexture> dst, uint8_t srcLevel, uint8_t srcLayer,
Handle<HwTexture> src, uint8_t dstLevel, uint8_t dstLayer) {
auto* const srcTexture = handle_cast<MetalTexture>(src);
auto* const dstTexture = handle_cast<MetalTexture>(dst);
assert_invariant(srcTexture);
assert_invariant(dstTexture);
ASSERT_PRECONDITION(mContext->currentRenderPassEncoder == nil,
"resolve() cannot be invoked inside a render pass.");
ASSERT_PRECONDITION(
dstTexture->width == srcTexture->width && dstTexture->height == srcTexture->height,
"invalid resolve: src and dst sizes don't match");
ASSERT_PRECONDITION(srcTexture->samples > 1 && dstTexture->samples == 1,
"invalid resolve: src.samples=%u, dst.samples=%u",
+srcTexture->samples, +dstTexture->samples);
ASSERT_PRECONDITION(srcTexture->format == dstTexture->format,
"src and dst texture format don't match");
ASSERT_PRECONDITION(!isDepthFormat(srcTexture->format),
"can't resolve depth formats");
ASSERT_PRECONDITION(!isStencilFormat(srcTexture->format),
"can't resolve stencil formats");
ASSERT_PRECONDITION(any(dstTexture->usage & TextureUsage::BLIT_DST),
"texture doesn't have BLIT_DST");
ASSERT_PRECONDITION(any(srcTexture->usage & TextureUsage::BLIT_SRC),
"texture doesn't have BLIT_SRC");
// FIXME: on metal the blit() call below always take the slow path (using a shader)
blit( dst, dstLevel, dstLayer, {},
src, srcLevel, srcLayer, {},
{ dstTexture->width, dstTexture->height });
}
void MetalDriver::blit(
Handle<HwTexture> dst, uint8_t srcLevel, uint8_t srcLayer, math::uint2 dstOrigin,
Handle<HwTexture> src, uint8_t dstLevel, uint8_t dstLayer, math::uint2 srcOrigin,
math::uint2 size) {
auto isBlitableTextureType = [](MTLTextureType t) -> bool {
return t == MTLTextureType2D || t == MTLTextureType2DMultisample ||
t == MTLTextureType2DArray;
};
auto* const srcTexture = handle_cast<MetalTexture>(src);
auto* const dstTexture = handle_cast<MetalTexture>(dst);
assert_invariant(srcTexture);
assert_invariant(dstTexture);
ASSERT_PRECONDITION(mContext->currentRenderPassEncoder == nil,
"blit() cannot be invoked inside a render pass.");
ASSERT_PRECONDITION(any(dstTexture->usage & TextureUsage::BLIT_DST),
"texture doesn't have BLIT_DST");
ASSERT_PRECONDITION(any(srcTexture->usage & TextureUsage::BLIT_SRC),
"texture doesn't have BLIT_SRC");
ASSERT_PRECONDITION(srcTexture->format == dstTexture->format,
"src and dst texture format don't match");
ASSERT_PRECONDITION(isBlitableTextureType(srcTexture->getMtlTextureForRead().textureType) &&
isBlitableTextureType(dstTexture->getMtlTextureForWrite().textureType),
"Metal does not support blitting to/from non-2D textures.");
MetalBlitter::BlitArgs args{};
args.filter = SamplerMagFilter::NEAREST;
args.source.region = MTLRegionMake2D(
(NSUInteger)srcOrigin.x,
std::max(srcTexture->height - (int64_t)srcOrigin.y - size.y, (int64_t)0),
size.x, size.y);
args.destination.region = MTLRegionMake2D(
(NSUInteger)dstOrigin.x,
std::max(dstTexture->height - (int64_t)dstOrigin.y - size.y, (int64_t)0),
size.x, size.y);
// FIXME: we shouldn't need to know the type here. This is an artifact of using the old API.
args.source.texture = srcTexture->getMtlTextureForRead();
args.destination.texture = dstTexture->getMtlTextureForWrite();
args.source.level = srcLevel;
args.source.slice = srcLayer;
args.destination.level = dstLevel;
args.destination.slice = dstLayer;
// TODO: The blit() call below always take the fast path.
mContext->blitter->blit(getPendingCommandBuffer(mContext), args, "blit/resolve");
dstTexture->extendLodRangeTo(dstLevel);
}
void MetalDriver::blitDEPRECATED(TargetBufferFlags buffers,
void MetalDriver::blit(TargetBufferFlags buffers,
Handle<HwRenderTarget> dst, Viewport dstRect,
Handle<HwRenderTarget> src, Viewport srcRect,
SamplerMagFilter filter) {
// Note: blitDEPRECATED is only used by Renderer::copyFrame
// It is called between beginFrame and endFrame, but should never be called in the middle of
// a render pass.
ASSERT_PRECONDITION(mContext->currentRenderPassEncoder == nil,
"blitDEPRECATED() cannot be invoked inside a render pass.");
// If we're the in middle of a render pass, finish it.
// This condition should only occur during copyFrame. It's okay to end the render pass because
// we don't issue any other rendering commands.
if (mContext->currentRenderPassEncoder) {
[mContext->currentRenderPassEncoder endEncoding];
mContext->currentRenderPassEncoder = nil;
}
auto srcTarget = handle_cast<MetalRenderTarget>(src);
auto dstTarget = handle_cast<MetalRenderTarget>(dst);
ASSERT_PRECONDITION(buffers == TargetBufferFlags::COLOR0,
"blitDEPRECATED only supports COLOR0");
ASSERT_PRECONDITION(
!(buffers & (TargetBufferFlags::COLOR_ALL & ~TargetBufferFlags::COLOR0)),
"Blitting only supports COLOR0");
ASSERT_PRECONDITION(srcRect.left >= 0 && srcRect.bottom >= 0 &&
dstRect.left >= 0 && dstRect.bottom >= 0,
@@ -1429,28 +1327,54 @@ void MetalDriver::blitDEPRECATED(TargetBufferFlags buffers,
t == MTLTextureType2DArray;
};
// We always blit from/to the COLOR0 attachment.
MetalRenderTarget::Attachment const srcColorAttachment = srcTarget->getReadColorAttachment(0);
MetalRenderTarget::Attachment const dstColorAttachment = dstTarget->getDrawColorAttachment(0);
// MetalBlitter supports blitting color and depth simultaneously, but for simplicitly we'll blit
// them separately. In practice, Filament only ever blits a single buffer at a time anyway.
if (srcColorAttachment && dstColorAttachment) {
ASSERT_PRECONDITION(isBlitableTextureType(srcColorAttachment.getTexture().textureType) &&
isBlitableTextureType(dstColorAttachment.getTexture().textureType),
"Metal does not support blitting to/from non-2D textures.");
if (any(buffers & TargetBufferFlags::COLOR_ALL)) {
// We always blit from/to the COLOR0 attachment.
MetalRenderTarget::Attachment srcColorAttachment = srcTarget->getReadColorAttachment(0);
MetalRenderTarget::Attachment dstColorAttachment = dstTarget->getDrawColorAttachment(0);
MetalBlitter::BlitArgs args{};
args.filter = filter;
args.source.region = srcTarget->getRegionFromClientRect(srcRect);
args.source.texture = srcColorAttachment.getTexture();
args.source.level = srcColorAttachment.level;
args.source.slice = srcColorAttachment.layer;
if (srcColorAttachment && dstColorAttachment) {
ASSERT_PRECONDITION(isBlitableTextureType(srcColorAttachment.getTexture().textureType) &&
isBlitableTextureType(dstColorAttachment.getTexture().textureType),
"Metal does not support blitting to/from non-2D textures.");
args.destination.region = dstTarget->getRegionFromClientRect(dstRect);
args.destination.texture = dstColorAttachment.getTexture();
args.destination.level = dstColorAttachment.level;
args.destination.slice = dstColorAttachment.layer;
MetalBlitter::BlitArgs args;
args.filter = filter;
args.source.region = srcTarget->getRegionFromClientRect(srcRect);
args.destination.region = dstTarget->getRegionFromClientRect(dstRect);
args.source.color = srcColorAttachment.getTexture();
args.destination.color = dstColorAttachment.getTexture();
args.source.level = srcColorAttachment.level;
args.destination.level = dstColorAttachment.level;
args.source.slice = srcColorAttachment.layer;
args.destination.slice = dstColorAttachment.layer;
mContext->blitter->blit(getPendingCommandBuffer(mContext), args, "Color blit");
}
}
mContext->blitter->blit(getPendingCommandBuffer(mContext), args, "blitDEPRECATED");
if (any(buffers & TargetBufferFlags::DEPTH)) {
MetalRenderTarget::Attachment srcDepthAttachment = srcTarget->getDepthAttachment();
MetalRenderTarget::Attachment dstDepthAttachment = dstTarget->getDepthAttachment();
if (srcDepthAttachment && dstDepthAttachment) {
ASSERT_PRECONDITION(isBlitableTextureType(srcDepthAttachment.getTexture().textureType) &&
isBlitableTextureType(dstDepthAttachment.getTexture().textureType),
"Metal does not support blitting to/from non-2D textures.");
MetalBlitter::BlitArgs args;
args.filter = filter;
args.source.region = srcTarget->getRegionFromClientRect(srcRect);
args.destination.region = dstTarget->getRegionFromClientRect(dstRect);
args.source.depth = srcDepthAttachment.getTexture();
args.destination.depth = dstDepthAttachment.getTexture();
args.source.level = srcDepthAttachment.level;
args.destination.level = dstDepthAttachment.level;
args.source.slice = srcDepthAttachment.layer;
args.destination.slice = dstDepthAttachment.layer;
mContext->blitter->blit(getPendingCommandBuffer(mContext), args, "Depth blit");
}
}
}
@@ -1588,7 +1512,7 @@ void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph, uint32_t
stencilPixelFormat = stencilAttachment.getPixelFormat();
assert_invariant(isMetalFormatStencil(stencilPixelFormat));
}
MetalPipelineState const pipelineState {
MetalPipelineState pipelineState {
.vertexFunction = vertex,
.fragmentFunction = fragment,
.vertexDescription = primitive->vertexDescription,
@@ -1606,13 +1530,13 @@ void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph, uint32_t
.stencilAttachmentPixelFormat = stencilPixelFormat,
.sampleCount = mContext->currentRenderTarget->getSamples(),
.blendState = BlendState {
.alphaBlendOperation = getMetalBlendOperation(rs.blendEquationAlpha),
.rgbBlendOperation = getMetalBlendOperation(rs.blendEquationRGB),
.destinationAlphaBlendFactor = getMetalBlendFactor(rs.blendFunctionDstAlpha),
.destinationRGBBlendFactor = getMetalBlendFactor(rs.blendFunctionDstRGB),
.sourceAlphaBlendFactor = getMetalBlendFactor(rs.blendFunctionSrcAlpha),
.sourceRGBBlendFactor = getMetalBlendFactor(rs.blendFunctionSrcRGB),
.blendingEnabled = rs.hasBlending(),
.rgbBlendOperation = getMetalBlendOperation(rs.blendEquationRGB),
.alphaBlendOperation = getMetalBlendOperation(rs.blendEquationAlpha),
.sourceRGBBlendFactor = getMetalBlendFactor(rs.blendFunctionSrcRGB),
.sourceAlphaBlendFactor = getMetalBlendFactor(rs.blendFunctionSrcAlpha),
.destinationRGBBlendFactor = getMetalBlendFactor(rs.blendFunctionDstRGB),
.destinationAlphaBlendFactor = getMetalBlendFactor(rs.blendFunctionDstAlpha)
},
.colorWrite = rs.colorWrite
};
@@ -1911,21 +1835,6 @@ void MetalDriver::enumerateBoundBuffers(BufferObjectBinding bindingType,
void MetalDriver::resetState(int) {
}
void MetalDriver::runAtNextTick(const std::function<void()>& fn) noexcept {
std::lock_guard<std::mutex> const lock(mTickOpsLock);
mTickOps.push_back(fn);
}
void MetalDriver::executeTickOps() noexcept {
std::vector<std::function<void()>> ops;
mTickOpsLock.lock();
std::swap(ops, mTickOps);
mTickOpsLock.unlock();
for (const auto& f : ops) {
f();
}
}
// explicit instantiation of the Dispatcher
template class ConcreteDispatcher<MetalDriver>;
+14 -46
View File
@@ -39,15 +39,7 @@ namespace filament {
namespace backend {
static inline MTLTextureUsage getMetalTextureUsage(TextureUsage usage) {
NSUInteger u = MTLTextureUsageUnknown;
if (any(usage & TextureUsage::SAMPLEABLE)) {
u |= MTLTextureUsageShaderRead;
}
if (any(usage & TextureUsage::UPLOADABLE)) {
// This is only needed because of the slowpath is MetalBlitter
u |= MTLTextureUsageRenderTarget;
}
NSUInteger u = 0;
if (any(usage & TextureUsage::COLOR_ATTACHMENT)) {
u |= MTLTextureUsageRenderTarget;
}
@@ -57,13 +49,9 @@ static inline MTLTextureUsage getMetalTextureUsage(TextureUsage usage) {
if (any(usage & TextureUsage::STENCIL_ATTACHMENT)) {
u |= MTLTextureUsageRenderTarget;
}
if (any(usage & TextureUsage::BLIT_DST)) {
// This is only needed because of the slowpath is MetalBlitter
u |= MTLTextureUsageRenderTarget;
}
if (any(usage & TextureUsage::BLIT_SRC)) {
u |= MTLTextureUsageShaderRead;
}
// All textures can be blitted from, so they must have the UsageShaderRead flag.
u |= MTLTextureUsageShaderRead;
return MTLTextureUsage(u);
}
@@ -245,30 +233,13 @@ void MetalSwapChain::present() {
}
}
struct PresentDrawableData {
void* drawable = nullptr;
MetalDriver* driver = nullptr;
};
void presentDrawable(bool presentFrame, void* user) {
auto* presentDrawableData = static_cast<PresentDrawableData*>(user);
// CFBridgingRelease here is used to balance the CFBridgingRetain inside acquireDrawable.
id<CAMetalDrawable> drawable =
(id<CAMetalDrawable>)CFBridgingRelease(presentDrawableData->drawable);
// CFBridgingRelease here is used to balance the CFBridgingRetain inside of acquireDrawable.
id<CAMetalDrawable> drawable = (id<CAMetalDrawable>) CFBridgingRelease(user);
if (presentFrame) {
[drawable present];
}
// Schedule the drawable destruction on the driver thread.
void* voidDrawable = (void*) CFBridgingRetain(drawable);
MetalDriver* driver = presentDrawableData->driver;
driver->runAtNextTick([voidDrawable]() {
// The drawable is released here.
CFBridgingRelease(voidDrawable);
});
delete presentDrawableData;
// The drawable will be released here when the "drawable" variable goes out of scope.
}
void MetalSwapChain::scheduleFrameScheduledCallback() {
@@ -283,15 +254,13 @@ void MetalSwapChain::scheduleFrameScheduledCallback() {
// capture the _this_ pointer (MetalSwapChain*) instead of the drawable.
id<CAMetalDrawable> d = drawable;
void* userData = frameScheduledUserData;
MetalDriver* driver = context.driver;
[getPendingCommandBuffer(&context) addScheduledHandler:^(id<MTLCommandBuffer> cb) {
// CFBridgingRetain is used here to give the drawable a +1 retain count before
// casting it to a void*.
auto* presentDrawableData = new PresentDrawableData;
presentDrawableData->drawable = (void*) CFBridgingRetain(d);
presentDrawableData->driver = driver;
PresentCallable callable(presentDrawable, (void*) presentDrawableData);
callback(callable, userData);
PresentCallable callable(presentDrawable, (void*) CFBridgingRetain(d));
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
callback(callable, userData);
});
}];
}
@@ -787,7 +756,6 @@ void MetalTexture::loadWithBlit(uint32_t level, uint32_t slice, MTLRegion region
#endif
id<MTLTexture> stagingTexture = [context.device newTextureWithDescriptor:descriptor];
// FIXME? Why is this not just `MTLRegion sourceRegion = region;` ?
MTLRegion sourceRegion = MTLRegionMake3D(0, 0, 0,
region.size.width, region.size.height, region.size.depth);
[stagingTexture replaceRegion:sourceRegion
@@ -814,16 +782,16 @@ void MetalTexture::loadWithBlit(uint32_t level, uint32_t slice, MTLRegion region
slices:NSMakeRange(0, slices)];
}
MetalBlitter::BlitArgs args{};
MetalBlitter::BlitArgs args;
args.filter = SamplerMagFilter::NEAREST;
args.source.level = 0;
args.source.slice = 0;
args.source.region = sourceRegion;
args.source.texture = stagingTexture;
args.destination.level = level;
args.destination.slice = slice;
args.destination.region = region;
args.destination.texture = destinationTexture;
args.source.color = stagingTexture;
args.destination.color = destinationTexture;
context.blitter->blit(getPendingCommandBuffer(&context), args, "Texture upload blit");
}
@@ -103,19 +103,10 @@ void MetalShaderCompiler::terminate() noexcept {
NSString* objcSource = [[NSString alloc] initWithBytes:source.data()
length:source.size() - 1
encoding:NSUTF8StringEncoding];
// By default, Metal uses the most recent language version.
MTLCompileOptions* options = [MTLCompileOptions new];
// Disable Fast Math optimizations.
// This ensures that operations adhere to IEEE standards for floating-point arithmetic,
// which is crucial for half precision floats in scenarios where fast math optimizations
// lead to inaccuracies, such as in handling special values like NaN or Infinity.
options.fastMathEnabled = NO;
NSError* error = nil;
// When options is nil, Metal uses the most recent language version available.
id<MTLLibrary> library = [device newLibraryWithSource:objcSource
options:options
options:nil
error:&error];
if (library == nil) {
if (error) {
+5 -16
View File
@@ -182,10 +182,6 @@ bool NoopDriver::isParallelShaderCompileSupported() {
return false;
}
bool NoopDriver::isDepthStencilResolveSupported() {
return true;
}
bool NoopDriver::isWorkaroundNeeded(Workaround) {
return false;
}
@@ -256,6 +252,10 @@ void NoopDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
void NoopDriver::generateMipmaps(Handle<HwTexture> th) { }
bool NoopDriver::canGenerateMipmaps() {
return true;
}
void NoopDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
BufferDescriptor&& data) {
scheduleDestroy(std::move(data));
@@ -322,23 +322,12 @@ void NoopDriver::readBufferSubData(backend::BufferObjectHandle boh,
scheduleDestroy(std::move(p));
}
void NoopDriver::blitDEPRECATED(TargetBufferFlags buffers,
void NoopDriver::blit(TargetBufferFlags buffers,
Handle<HwRenderTarget> dst, Viewport dstRect,
Handle<HwRenderTarget> src, Viewport srcRect,
SamplerMagFilter filter) {
}
void NoopDriver::resolve(
Handle<HwTexture> dst, uint8_t srcLevel, uint8_t srcLayer,
Handle<HwTexture> src, uint8_t dstLevel, uint8_t dstLayer) {
}
void NoopDriver::blit(
Handle<HwTexture> dst, uint8_t srcLevel, uint8_t srcLayer, math::uint2 dstOrigin,
Handle<HwTexture> src, uint8_t dstLevel, uint8_t dstLayer, math::uint2 srcOrigin,
math::uint2 size) {
}
void NoopDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> rph,
uint32_t instanceCount) {
}
+3 -14
View File
@@ -274,7 +274,6 @@ void OpenGLContext::setDefaultState() noexcept {
glHint(GL_FRAGMENT_SHADER_DERIVATIVE_HINT, GL_NICEST);
#endif
#if !defined(__EMSCRIPTEN__)
if (ext.EXT_clip_control) {
#if defined(BACKEND_OPENGL_VERSION_GL)
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
@@ -282,7 +281,6 @@ void OpenGLContext::setDefaultState() noexcept {
glClipControlEXT(GL_LOWER_LEFT_EXT, GL_ZERO_TO_ONE_EXT);
#endif
}
#endif
if (ext.EXT_clip_cull_distance) {
glEnable(GL_CLIP_DISTANCE0);
@@ -311,9 +309,7 @@ void OpenGLContext::initProcs(Procs* procs,
# ifdef BACKEND_OPENGL_VERSION_GL
procs->getQueryObjectui64v = glGetQueryObjectui64v; // only core in GL
# elif defined(GL_EXT_disjoint_timer_query)
# ifndef __EMSCRIPTEN__
procs->getQueryObjectui64v = glGetQueryObjectui64vEXT;
# endif
procs->getQueryObjectui64v = glGetQueryObjectui64vEXT;
# endif // BACKEND_OPENGL_VERSION_GL
// core in ES 3.0 and GL 4.3
@@ -325,7 +321,6 @@ void OpenGLContext::initProcs(Procs* procs,
#ifdef BACKEND_OPENGL_VERSION_GLES
# ifndef IOS // IOS is guaranteed to have ES3.x
# ifndef __EMSCRIPTEN__
if (UTILS_UNLIKELY(major == 2)) {
// Runtime OpenGL version is ES 2.x
if (UTILS_LIKELY(ext.OES_vertex_array_object)) {
@@ -353,7 +348,6 @@ void OpenGLContext::initProcs(Procs* procs,
procs->maxShaderCompilerThreadsKHR = glMaxShaderCompilerThreadsKHR;
}
# endif // __EMSCRIPTEN__
# endif // IOS
#else
procs->maxShaderCompilerThreadsKHR = glMaxShaderCompilerThreadsARB;
@@ -482,6 +476,7 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
// (that should be regardless of ANGLE, but we should double-check)
bugs->split_easu = true;
}
// TODO: see if we could use `bugs.allow_read_only_ancillary_feedback_loop = true`
}
#ifdef BACKEND_OPENGL_VERSION_GLES
@@ -586,23 +581,17 @@ void OpenGLContext::initExtensionsGLES(Extensions* ext, GLint major, GLint minor
// figure out and initialize the extensions we need
using namespace std::literals;
ext->APPLE_color_buffer_packed_float = exts.has("GL_APPLE_color_buffer_packed_float"sv);
#ifndef __EMSCRIPTEN__
ext->EXT_clip_control = exts.has("GL_EXT_clip_control"sv);
#endif
ext->EXT_clip_cull_distance = exts.has("GL_EXT_clip_cull_distance"sv);
ext->EXT_color_buffer_float = exts.has("GL_EXT_color_buffer_float"sv);
ext->EXT_color_buffer_half_float = exts.has("GL_EXT_color_buffer_half_float"sv);
#ifndef __EMSCRIPTEN__
ext->EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv);
#endif
ext->EXT_discard_framebuffer = exts.has("GL_EXT_discard_framebuffer"sv);
#ifndef __EMSCRIPTEN__
ext->EXT_disjoint_timer_query = exts.has("GL_EXT_disjoint_timer_query"sv);
ext->EXT_multisampled_render_to_texture = exts.has("GL_EXT_multisampled_render_to_texture"sv);
ext->EXT_multisampled_render_to_texture2 = exts.has("GL_EXT_multisampled_render_to_texture2"sv);
#endif
ext->EXT_shader_framebuffer_fetch = exts.has("GL_EXT_shader_framebuffer_fetch"sv);
#ifndef __EMSCRIPTEN__
#if !defined(__EMSCRIPTEN__)
ext->EXT_texture_compression_etc2 = true;
#endif
ext->EXT_texture_compression_s3tc = exts.has("GL_EXT_texture_compression_s3tc"sv);
+65 -229
View File
@@ -537,7 +537,7 @@ void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
if (UTILS_UNLIKELY(mContext.isES2())) {
// Here we patch the specialization constants to enable or not the rec709 output
// Here we patch the specification constants to enable or not the rec709 output
// color space emulation in this program. Obviously, the backend shouldn't know about
// specific spec-constants, so we need to handle failures gracefully. This cannot be
// done at Material creation time because only the backend has access to
@@ -1064,7 +1064,6 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
}
CHECK_GL_ERROR(utils::slog.e)
} else
#ifndef __EMSCRIPTEN__
#ifdef GL_EXT_multisampled_render_to_texture
// EXT_multisampled_render_to_texture only support GL_COLOR_ATTACHMENT0
if (!attachmentTypeNotSupportedByMSRTT && (t->depth <= 1)
@@ -1077,7 +1076,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
// This extension only exists on OpenGL ES.
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
if (any(t->usage & TextureUsage::SAMPLEABLE)) {
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER,
glext::glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER,
attachment, target, t->gl.id, binfo.level, rt->gl.samples);
} else {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
@@ -1085,8 +1084,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
}
CHECK_GL_ERROR(utils::slog.e)
} else
#endif // GL_EXT_multisampled_render_to_texture
#endif // __EMSCRIPTEN__
#endif
if (!any(t->usage & TextureUsage::SAMPLEABLE) && t->samples > 1) {
assert_invariant(rt->gl.samples > 1);
assert_invariant(glIsRenderbuffer(t->gl.id));
@@ -1185,7 +1183,6 @@ void OpenGLDriver::renderBufferStorage(GLuint rbo, GLenum internalformat, uint32
uint32_t height, uint8_t samples) const noexcept {
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
if (samples > 1) {
#ifndef __EMSCRIPTEN__
#ifdef GL_EXT_multisampled_render_to_texture
auto& gl = mContext;
if (gl.ext.EXT_multisampled_render_to_texture ||
@@ -1193,8 +1190,7 @@ void OpenGLDriver::renderBufferStorage(GLuint rbo, GLenum internalformat, uint32
glext::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER,
samples, internalformat, width, height);
} else
#endif // GL_EXT_multisampled_render_to_texture
#endif // __EMSCRIPTEN__
#endif
{
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
glRenderbufferStorageMultisample(GL_RENDERBUFFER,
@@ -1910,10 +1906,6 @@ bool OpenGLDriver::isParallelShaderCompileSupported() {
return mShaderCompilerService.isParallelShaderCompileSupported();
}
bool OpenGLDriver::isDepthStencilResolveSupported() {
return true;
}
bool OpenGLDriver::isWorkaroundNeeded(Workaround workaround) {
switch (workaround) {
case Workaround::SPLIT_EASU:
@@ -2235,7 +2227,8 @@ void OpenGLDriver::setMinMaxLevels(Handle<HwTexture> th, uint32_t minLevel, uint
t->gl.baseLevel = (int8_t)minLevel;
glTexParameteri(t->gl.target, GL_TEXTURE_BASE_LEVEL, t->gl.baseLevel);
t->gl.maxLevel = (int8_t)maxLevel; // NOTE: according to the GL spec, the default value of this 1000
t->gl
.maxLevel = (int8_t)maxLevel; // NOTE: according to the GL spec, the default value of this 1000
glTexParameteri(t->gl.target, GL_TEXTURE_MAX_LEVEL, t->gl.maxLevel);
}
#endif
@@ -2285,13 +2278,16 @@ void OpenGLDriver::generateMipmaps(Handle<HwTexture> th) {
CHECK_GL_ERROR(utils::slog.e)
}
bool OpenGLDriver::canGenerateMipmaps() {
return true;
}
void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
PixelBufferDescriptor&& p) {
auto& gl = mContext;
assert_invariant(t != nullptr);
assert_invariant(xoffset + width <= std::max(1u, t->width >> level));
assert_invariant(yoffset + height <= std::max(1u, t->height >> level));
assert_invariant(t->samples <= 1);
@@ -2990,18 +2986,16 @@ GLuint OpenGLDriver::getSamplerSlow(SamplerParams params) const noexcept {
#endif
void OpenGLDriver::insertEventMarker(char const* string, uint32_t len) {
#ifndef __EMSCRIPTEN__
#ifdef GL_EXT_debug_marker
auto& gl = mContext;
if (gl.ext.EXT_debug_marker) {
glInsertEventMarkerEXT(GLsizei(len ? len : strlen(string)), string);
}
#endif
#endif
}
void OpenGLDriver::pushGroupMarker(char const* string, uint32_t len) {
#ifndef __EMSCRIPTEN__
#ifdef GL_EXT_debug_marker
#if DEBUG_MARKER_LEVEL & DEBUG_MARKER_OPENGL
if (UTILS_LIKELY(mContext.ext.EXT_debug_marker)) {
@@ -3014,11 +3008,9 @@ void OpenGLDriver::pushGroupMarker(char const* string, uint32_t len) {
SYSTRACE_CONTEXT();
SYSTRACE_NAME_BEGIN(string);
#endif
#endif
}
void OpenGLDriver::popGroupMarker(int) {
#ifndef __EMSCRIPTEN__
#ifdef GL_EXT_debug_marker
#if DEBUG_MARKER_LEVEL & DEBUG_MARKER_OPENGL
if (UTILS_LIKELY(mContext.ext.EXT_debug_marker)) {
@@ -3031,7 +3023,6 @@ void OpenGLDriver::popGroupMarker(int) {
SYSTRACE_CONTEXT();
SYSTRACE_NAME_END();
#endif
#endif
}
void OpenGLDriver::startCapture(int) {
@@ -3447,230 +3438,75 @@ void OpenGLDriver::clearWithRasterPipe(TargetBufferFlags clearFlags,
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::resolve(
Handle<HwTexture> dst, uint8_t srcLevel, uint8_t srcLayer,
Handle<HwTexture> src, uint8_t dstLevel, uint8_t dstLayer) {
DEBUG_MARKER()
GLTexture const* const s = handle_cast<GLTexture*>(src);
GLTexture const* const d = handle_cast<GLTexture*>(dst);
assert_invariant(s);
assert_invariant(d);
ASSERT_PRECONDITION(
d->width == s->width && d->height == s->height,
"invalid resolve: src and dst sizes don't match");
ASSERT_PRECONDITION(s->samples > 1 && d->samples == 1,
"invalid resolve: src.samples=%u, dst.samples=%u",
+s->samples, +d->samples);
blit( dst, dstLevel, dstLayer, {},
src, srcLevel, srcLayer, {},
{ d->width, d->height });
}
void OpenGLDriver::blit(
Handle<HwTexture> dst, uint8_t srcLevel, uint8_t srcLayer, uint2 dstOrigin,
Handle<HwTexture> src, uint8_t dstLevel, uint8_t dstLayer, uint2 srcOrigin,
uint2 size) {
DEBUG_MARKER()
UTILS_UNUSED_IN_RELEASE auto& gl = mContext;
assert_invariant(!gl.isES2());
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
GLTexture* d = handle_cast<GLTexture*>(dst);
GLTexture* s = handle_cast<GLTexture*>(src);
assert_invariant(d);
assert_invariant(s);
ASSERT_PRECONDITION_NON_FATAL(any(d->usage & TextureUsage::BLIT_DST),
"texture doesn't have BLIT_DST");
ASSERT_PRECONDITION_NON_FATAL(any(s->usage & TextureUsage::BLIT_SRC),
"texture doesn't have BLIT_SRC");
ASSERT_PRECONDITION_NON_FATAL(s->format == d->format,
"src and dst texture format don't match");
enum class AttachmentType : GLenum {
COLOR = GL_COLOR_ATTACHMENT0,
DEPTH = GL_DEPTH_ATTACHMENT,
STENCIL = GL_STENCIL_ATTACHMENT,
DEPTH_STENCIL = GL_DEPTH_STENCIL_ATTACHMENT,
};
auto getFormatType = [](TextureFormat format) -> AttachmentType {
bool const depth = isDepthFormat(format);
bool const stencil = isStencilFormat(format);
if (depth && stencil) return AttachmentType::DEPTH_STENCIL;
if (depth) return AttachmentType::DEPTH;
if (stencil) return AttachmentType::STENCIL;
return AttachmentType::COLOR;
};
AttachmentType const type = getFormatType(d->format);
assert_invariant(type == getFormatType(s->format));
// GL_INVALID_OPERATION is generated if mask contains any of the GL_DEPTH_BUFFER_BIT or
// GL_STENCIL_BUFFER_BIT and filter is not GL_NEAREST.
GLbitfield mask = {};
switch (type) {
case AttachmentType::COLOR:
mask = GL_COLOR_BUFFER_BIT;
break;
case AttachmentType::DEPTH:
mask = GL_DEPTH_BUFFER_BIT;
break;
case AttachmentType::STENCIL:
mask = GL_STENCIL_BUFFER_BIT;
break;
case AttachmentType::DEPTH_STENCIL:
mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
break;
};
GLuint fbo[2] = {};
glGenFramebuffers(2, fbo);
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[0]);
switch (d->target) {
case SamplerType::SAMPLER_2D:
if (any(d->usage & TextureUsage::SAMPLEABLE)) {
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GLenum(type),
GL_TEXTURE_2D, d->gl.id, dstLevel);
} else {
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GLenum(type),
GL_RENDERBUFFER, d->gl.id);
}
break;
case SamplerType::SAMPLER_CUBEMAP:
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GLenum(type),
GL_TEXTURE_CUBE_MAP_POSITIVE_X + dstLayer, d->gl.id, dstLevel);
break;
case SamplerType::SAMPLER_2D_ARRAY:
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
case SamplerType::SAMPLER_3D:
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GLenum(type),
d->gl.id, dstLevel, dstLayer);
break;
case SamplerType::SAMPLER_EXTERNAL:
break;
}
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_READ_FRAMEBUFFER)
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, fbo[1]);
switch (s->target) {
case SamplerType::SAMPLER_2D:
if (any(s->usage & TextureUsage::SAMPLEABLE)) {
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GLenum(type),
GL_TEXTURE_2D, s->gl.id, srcLevel);
} else {
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GLenum(type),
GL_RENDERBUFFER, s->gl.id);
}
break;
case SamplerType::SAMPLER_CUBEMAP:
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GLenum(type),
GL_TEXTURE_CUBE_MAP_POSITIVE_X + srcLayer, s->gl.id, srcLevel);
break;
case SamplerType::SAMPLER_2D_ARRAY:
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
case SamplerType::SAMPLER_3D:
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GLenum(type),
s->gl.id, srcLevel, srcLayer);
break;
case SamplerType::SAMPLER_EXTERNAL:
break;
}
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_DRAW_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)
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glDeleteFramebuffers(2, fbo);
if (any(d->usage & TextureUsage::SAMPLEABLE)) {
// In a sense, blitting to a texture level is similar to calling setTextureData on it; in
// both cases, we update the base/max LOD to give shaders access to levels as they become
// available. Note that this can only expand the LOD range (never shrink it), and that
// users can override this range by calling setMinMaxLevels().
updateTextureLodRange(d, int8_t(dstLevel));
}
#endif
}
void OpenGLDriver::blitDEPRECATED(TargetBufferFlags buffers,
void OpenGLDriver::blit(TargetBufferFlags buffers,
Handle<HwRenderTarget> dst, Viewport dstRect,
Handle<HwRenderTarget> src, Viewport srcRect,
SamplerMagFilter filter) {
// Note: blitDEPRECATED is only used by Renderer::copyFrame
DEBUG_MARKER()
UTILS_UNUSED_IN_RELEASE auto& gl = mContext;
assert_invariant(!gl.isES2());
ASSERT_PRECONDITION(buffers == TargetBufferFlags::COLOR0,
"blitDEPRECATED only supports COLOR0");
ASSERT_PRECONDITION(srcRect.left >= 0 && srcRect.bottom >= 0 &&
dstRect.left >= 0 && dstRect.bottom >= 0,
"Source and destination rects must be positive.");
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
GLbitfield const mask = getAttachmentBitfield(buffers);
if (mask) {
GLenum glFilterMode = (filter == SamplerMagFilter::NEAREST) ? GL_NEAREST : GL_LINEAR;
if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
// GL_INVALID_OPERATION is generated if mask contains any of the GL_DEPTH_BUFFER_BIT or
// GL_STENCIL_BUFFER_BIT and filter is not GL_NEAREST.
glFilterMode = GL_NEAREST;
}
GLenum const glFilterMode = (filter == SamplerMagFilter::NEAREST) ? GL_NEAREST : GL_LINEAR;
// note: for msaa RenderTargets with non-msaa attachments, we copy from the msaa sidecar
// buffer -- this should produce the same output that if we copied from the resolved
// texture. EXT_multisampled_render_to_texture seems to allow both behaviours, and this
// is an emulation of that. We cannot use the resolved texture easily because it's not
// actually attached to the RenderTarget. Another implementation would be to do a
// reverse-resolve, but that wouldn't buy us anything.
GLRenderTarget const* s = handle_cast<GLRenderTarget const*>(src);
GLRenderTarget const* d = handle_cast<GLRenderTarget const*>(dst);
// note: for msaa RenderTargets with non-msaa attachments, we copy from the msaa sidecar
// buffer -- this should produce the same output that if we copied from the resolved
// texture. EXT_multisampled_render_to_texture seems to allow both behaviours, and this
// is an emulation of that. We cannot use the resolved texture easily because it's not
// actually attached to the RenderTarget. Another implementation would be to do a
// reverse-resolve, but that wouldn't buy us anything.
GLRenderTarget const* s = handle_cast<GLRenderTarget const*>(src);
GLRenderTarget const* d = handle_cast<GLRenderTarget const*>(dst);
// blit operations are only supported from RenderTargets that have only COLOR0 (or
// no color buffer at all)
assert_invariant(
!(s->targets & (TargetBufferFlags::COLOR_ALL & ~TargetBufferFlags::COLOR0)));
// With GLES 3.x, GL_INVALID_OPERATION is generated if the value of GL_SAMPLE_BUFFERS
// for the draw buffer is greater than zero. This works with OpenGL, so we want to
// make sure to catch this scenario.
assert_invariant(d->gl.samples <= 1);
assert_invariant(
!(d->targets & (TargetBufferFlags::COLOR_ALL & ~TargetBufferFlags::COLOR0)));
// GL_INVALID_OPERATION is generated if GL_SAMPLE_BUFFERS for the read buffer is greater
// than zero and the formats of draw and read buffers are not identical.
// However, it's not well-defined in the spec what "format" means. So it's difficult
// to have an assert here -- especially when dealing with the default framebuffer
// With GLES 3.x, GL_INVALID_OPERATION is generated if the value of GL_SAMPLE_BUFFERS
// for the draw buffer is greater than zero. This works with OpenGL, so we want to
// make sure to catch this scenario.
assert_invariant(d->gl.samples <= 1);
// GL_INVALID_OPERATION is generated if GL_SAMPLE_BUFFERS for the read buffer is greater
// than zero and (...) the source and destination rectangles are not defined with the
// same (X0, Y0) and (X1, Y1) bounds.
// GL_INVALID_OPERATION is generated if GL_SAMPLE_BUFFERS for the read buffer is greater
// than zero and the formats of draw and read buffers are not identical.
// However, it's not well-defined in the spec what "format" means. So it's difficult
// to have an assert here -- especially when dealing with the default framebuffer
// Additionally, the EXT_multisampled_render_to_texture extension doesn't specify what
// happens when blitting from an "implicit" resolve render target (does it work?), so
// to ere on the safe side, we don't allow it.
if (s->gl.samples > 1) {
assert_invariant(!memcmp(&dstRect, &srcRect, sizeof(srcRect)));
// GL_INVALID_OPERATION is generated if GL_SAMPLE_BUFFERS for the read buffer is greater
// than zero and (...) the source and destination rectangles are not defined with the
// same (X0, Y0) and (X1, Y1) bounds.
// Additionally, the EXT_multisampled_render_to_texture extension doesn't specify what
// happens when blitting from an "implicit" resolve render target (does it work?), so
// to ere on the safe side, we don't allow it.
if (s->gl.samples > 1) {
assert_invariant(!memcmp(&dstRect, &srcRect, sizeof(srcRect)));
}
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)
gl.disable(GL_SCISSOR_TEST);
glBlitFramebuffer(
srcRect.left, srcRect.bottom, srcRect.right(), srcRect.top(),
dstRect.left, dstRect.bottom, dstRect.right(), dstRect.top(),
mask, glFilterMode);
CHECK_GL_ERROR(utils::slog.e)
}
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)
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)
#endif
}
@@ -140,37 +140,20 @@ void* ShaderCompilerService::getUserData(const program_token_t& token) noexcept
ShaderCompilerService::ShaderCompilerService(OpenGLDriver& driver)
: mDriver(driver),
mBlobCache(driver.getContext()),
mCallbackManager(driver) {
mCallbackManager(driver),
KHR_parallel_shader_compile(driver.getContext().ext.KHR_parallel_shader_compile) {
}
ShaderCompilerService::~ShaderCompilerService() noexcept = default;
bool ShaderCompilerService::isParallelShaderCompileSupported() const noexcept {
assert_invariant(mMode != Mode::UNDEFINED);
return mMode != Mode::SYNCHRONOUS;
return KHR_parallel_shader_compile || mShaderCompilerThreadCount;
}
void ShaderCompilerService::init() noexcept {
// Here we decide which mode we'll be using. We always prefer our own thread-pool if
// that mode is available because, we have no control on how the compilation queues are
// handled if done by the driver (so at the very least we'd need to decode this per-driver).
// In theory, using Mode::ASYNCHRONOUS (a.k.a. KHR_parallel_shader_compile) could be more
// efficient, since it doesn't require shared contexts.
// In practice, we already know that with ANGLE, Mode::ASYNCHRONOUS can cause very long
// pauses at glDraw() time in the situation where glLinkProgram() has been emitted, but has
// other programs ahead of it in ANGLE's queue.
if (mDriver.mPlatform.isExtraContextSupported()) {
// our thread-pool if possible
mMode = Mode::THREAD_POOL;
} else if (mDriver.getContext().ext.KHR_parallel_shader_compile) {
// if not, async shader compilation and link if the driver supports it
mMode = Mode::ASYNCHRONOUS;
} else {
// fallback to synchronous shader compilation
mMode = Mode::SYNCHRONOUS;
}
if (mMode == Mode::THREAD_POOL) {
// If we have KHR_parallel_shader_compile, we always use it, it should be more resource
// friendly.
if (!KHR_parallel_shader_compile) {
// - on Adreno there is a single compiler object. We can't use a pool > 1
// also glProgramBinary blocks if other threads are compiling.
// - on Mali shader compilation can be multi-threaded, but program linking happens on
@@ -180,42 +163,37 @@ void ShaderCompilerService::init() noexcept {
// - on macOS (M1 MacBook Pro/Ventura) there is global lock around all GL APIs when using
// a shared context, so parallel shader compilation yields no benefit.
// - on windows/linux we could use more threads, tbd.
if (mDriver.mPlatform.isExtraContextSupported()) {
// By default, we use one thread at the same priority as the gl thread. This is the
// safest choice that avoids priority inversions.
uint32_t poolSize = 1;
JobSystem::Priority priority = JobSystem::Priority::DISPLAY;
// By default, we use one thread at the same priority as the gl thread. This is the
// safest choice that avoids priority inversions.
uint32_t poolSize = 1;
JobSystem::Priority priority = JobSystem::Priority::DISPLAY;
auto const& renderer = mDriver.getContext().state.renderer;
if (UTILS_UNLIKELY(strstr(renderer, "PowerVR"))) {
// The PowerVR driver support parallel shader compilation well, so we use 2
// threads, we can use lower priority threads here because urgent compilations
// will most likely happen on the main gl thread. Using too many thread can
// increase memory pressure significantly.
poolSize = 2;
priority = JobSystem::Priority::BACKGROUND;
}
auto const& renderer = mDriver.getContext().state.renderer;
// Some drivers support parallel shader compilation well, so we use N
// threads, we can use lower priority threads here because urgent compilations
// will most likely happen on the main gl thread. Using too many thread can
// increase memory pressure significantly.
if (UTILS_UNLIKELY(strstr(renderer, "PowerVR"))) {
// For PowerVR, it's unclear what the cost of extra shared contexts is, so we only
// use 2 to be safe.
poolSize = 2;
priority = JobSystem::Priority::BACKGROUND;
} else if (UTILS_UNLIKELY(strstr(renderer, "ANGLE"))) {
// Angle shared contexts are not expensive once we have two.
poolSize = (std::thread::hardware_concurrency() + 1) / 2;
priority = JobSystem::Priority::BACKGROUND;
mShaderCompilerThreadCount = poolSize;
mCompilerThreadPool.init(mShaderCompilerThreadCount,
[&platform = mDriver.mPlatform, priority]() {
// give the thread a name
JobSystem::setThreadName("CompilerThreadPool");
// run at a slightly lower priority than other filament threads
JobSystem::setThreadPriority(priority);
// create a gl context current to this thread
platform.createContext(true);
},
[&platform = mDriver.mPlatform]() {
// release context and thread state
platform.releaseContext();
});
}
mShaderCompilerThreadCount = poolSize;
mCompilerThreadPool.init(mShaderCompilerThreadCount,
[&platform = mDriver.mPlatform, priority]() {
// give the thread a name
JobSystem::setThreadName("CompilerThreadPool");
// run at a slightly lower priority than other filament threads
JobSystem::setThreadPriority(priority);
// create a gl context current to this thread
platform.createContext(true);
},
[&platform = mDriver.mPlatform]() {
// release context and thread state
platform.releaseContext();
});
}
}
@@ -249,7 +227,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
token->handle = mCallbackManager.get();
CompilerPriorityQueue const priorityQueue = program.getPriorityQueue();
if (mMode == Mode::THREAD_POOL) {
if (mShaderCompilerThreadCount) {
// queue a compile job
mCompilerThreadPool.queue(priorityQueue, token,
[this, &gl, program = std::move(program), token]() mutable {
@@ -298,8 +276,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
token->shaderSourceCode);
runAtNextTick(priorityQueue, token, [this, token](Job const&) {
assert_invariant(mMode != Mode::THREAD_POOL);
if (mMode == Mode::ASYNCHRONOUS) {
if (KHR_parallel_shader_compile) {
// don't attempt to link this program if all shaders are not done compiling
GLint status;
if (token->gl.program) {
@@ -323,7 +300,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
// link the program, this also cannot fail because status is checked later.
token->gl.program = linkProgram(mDriver.getContext(),
token->gl.shaders, token->attributes);
if (mMode == Mode::ASYNCHRONOUS) {
if (KHR_parallel_shader_compile) {
// wait until the link finishes...
return false;
}
@@ -364,7 +341,7 @@ void ShaderCompilerService::terminate(program_token_t& token) {
bool const canceled = token->compiler.cancelTickOp(token);
if (token->compiler.mMode == Mode::THREAD_POOL) {
if (token->compiler.mShaderCompilerThreadCount) {
auto job = token->compiler.mCompilerThreadPool.dequeue(token);
if (!job) {
// The job is being executed right now. We need to wait for it to finish to avoid a
@@ -398,7 +375,7 @@ void ShaderCompilerService::terminate(program_token_t& token) {
void ShaderCompilerService::tick() {
// we don't need to run executeTickOps() if we're using the thread-pool
if (UTILS_UNLIKELY(mMode != Mode::THREAD_POOL)) {
if (UTILS_UNLIKELY(!mShaderCompilerThreadCount)) {
executeTickOps();
}
}
@@ -423,7 +400,7 @@ void ShaderCompilerService::getProgramFromCompilerPool(program_token_t& token) n
GLuint ShaderCompilerService::initialize(program_token_t& token) noexcept {
SYSTRACE_CALL();
if (!token->gl.program) {
if (mMode == Mode::THREAD_POOL) {
if (mShaderCompilerThreadCount) {
// we need this program right now, remove it from the queue
auto job = mCompilerThreadPool.dequeue(token);
if (job) {
@@ -439,7 +416,7 @@ GLuint ShaderCompilerService::initialize(program_token_t& token) noexcept {
// Block until we get the program from the pool. Generally this wouldn't block
// because we just compiled the program above, when executing job.
ShaderCompilerService::getProgramFromCompilerPool(token);
} else if (mMode == Mode::ASYNCHRONOUS) {
} else if (KHR_parallel_shader_compile) {
// we force the program link -- which might stall, either here or below in
// checkProgramStatus(), but we don't have a choice, we need to use the program now.
token->compiler.cancelTickOp(token);
@@ -547,8 +524,7 @@ void ShaderCompilerService::compileShaders(OpenGLContext& context,
// add support for ARB_shading_language_packing if needed
auto const packingFunctions = process_ARB_shading_language_packing(context);
// split shader source, so we can insert the specialization constants and the packing
// functions
// split shader source, so we can insert the specification constants and the packing functions
auto const [prolog, body] = splitShaderSource(source);
const std::array<const char*, 4> sources = {
@@ -95,42 +95,19 @@ public:
CallbackHandler* handler, CallbackHandler::Callback callback, void* user);
private:
struct Job {
template<typename FUNC>
Job(FUNC&& fn) : fn(std::forward<FUNC>(fn)) {}
Job(std::function<bool(Job const& job)> fn,
CallbackHandler* handler, void* user, CallbackHandler::Callback callback)
: fn(std::move(fn)), handler(handler), user(user), callback(callback) {
}
std::function<bool(Job const& job)> fn;
CallbackHandler* handler = nullptr;
void* user = nullptr;
CallbackHandler::Callback callback{};
};
enum class Mode {
UNDEFINED, // init() has not beed called yet.
SYNCHRONOUS, // synchronous shader compilation
THREAD_POOL, // asynchronous shader compilation using a thread-pool (most common)
ASYNCHRONOUS // asynchronous shader compilation using KHR_parallel_shader_compile
};
OpenGLDriver& mDriver;
OpenGLBlobCache mBlobCache;
CallbackManager mCallbackManager;
CompilerThreadPool mCompilerThreadPool;
const bool KHR_parallel_shader_compile;
uint32_t mShaderCompilerThreadCount = 0u;
Mode mMode = Mode::UNDEFINED; // valid after init() is called
using ContainerType = std::tuple<CompilerPriorityQueue, program_token_t, Job>;
std::vector<ContainerType> mRunAtNextTickOps;
GLuint initialize(ShaderCompilerService::program_token_t& token) noexcept;
static void getProgramFromCompilerPool(program_token_t& token) noexcept;
static void compileShaders(
static void compileShaders(
OpenGLContext& context,
Program::ShaderSource shadersSource,
utils::FixedCapacityVector<Program::SpecializationConstant> const& specializationConstants,
@@ -150,11 +127,27 @@ private:
static bool checkProgramStatus(program_token_t const& token) noexcept;
struct Job {
template<typename FUNC>
Job(FUNC&& fn) : fn(std::forward<FUNC>(fn)) {}
Job(std::function<bool(Job const& job)> fn,
CallbackHandler* handler, void* user, CallbackHandler::Callback callback)
: fn(std::move(fn)), handler(handler), user(user), callback(callback) {
}
std::function<bool(Job const& job)> fn;
CallbackHandler* handler = nullptr;
void* user = nullptr;
CallbackHandler::Callback callback{};
};
void runAtNextTick(CompilerPriorityQueue priority,
const program_token_t& token, Job job) noexcept;
void executeTickOps() noexcept;
bool cancelTickOp(program_token_t token) noexcept;
// order of insertion is important
using ContainerType = std::tuple<CompilerPriorityQueue, program_token_t, Job>;
std::vector<ContainerType> mRunAtNextTickOps;
};
} // namespace filament::backend
+1 -4
View File
@@ -28,7 +28,6 @@ static void getProcAddress(T& pfn, const char* name) noexcept {
}
namespace glext {
#ifndef __EMSCRIPTEN__
#ifdef GL_OES_EGL_image
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
#endif
@@ -73,11 +72,10 @@ PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glMaxShaderCompilerThreadsKHR;
// use getProcAddress for ES3.1 and above entry points.
PFNGLDISPATCHCOMPUTEPROC glDispatchCompute;
#endif
static std::once_flag sGlExtInitialized;
#endif // __EMSCRIPTEN__
void importGLESExtensionsEntryPoints() {
#ifndef __EMSCRIPTEN__
std::call_once(sGlExtInitialized, +[]() {
#ifdef GL_OES_EGL_image
getProcAddress(glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES");
@@ -121,7 +119,6 @@ void importGLESExtensionsEntryPoints() {
getProcAddress(glDispatchCompute, "glDispatchCompute");
#endif
});
#endif // __EMSCRIPTEN__
}
} // namespace glext
-2
View File
@@ -112,7 +112,6 @@ namespace glext {
// it is currently called from PlatformEGL.
void importGLESExtensionsEntryPoints();
#ifndef __EMSCRIPTEN__
#ifdef GL_OES_EGL_image
extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
#endif
@@ -154,7 +153,6 @@ extern PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glMaxShaderCompilerThreadsKHR;
#if defined(__ANDROID__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
extern PFNGLDISPATCHCOMPUTEPROC glDispatchCompute;
#endif
#endif // __EMSCRIPTEN__
} // namespace glext
using namespace glext;
+15 -1
View File
@@ -293,6 +293,20 @@ io::ostream& operator<<(io::ostream& out, TextureFormat format) {
return out;
}
io::ostream& operator<<(io::ostream& out, TextureUsage usage) {
switch (usage) {
CASE(TextureUsage, NONE)
CASE(TextureUsage, DEFAULT)
CASE(TextureUsage, COLOR_ATTACHMENT)
CASE(TextureUsage, DEPTH_ATTACHMENT)
CASE(TextureUsage, STENCIL_ATTACHMENT)
CASE(TextureUsage, UPLOADABLE)
CASE(TextureUsage, SAMPLEABLE)
CASE(TextureUsage, SUBPASS_INPUT)
}
return out;
}
io::ostream& operator<<(io::ostream& out, TextureCubemapFace face) {
switch (face) {
CASE(TextureCubemapFace, NEGATIVE_X)
@@ -455,7 +469,7 @@ io::ostream& operator<<(io::ostream& out, filament::backend::Viewport const& vie
io::ostream& operator<<(io::ostream& out, TargetBufferFlags flags) {
// TODO: implement decoding of enum
out << uint32_t(flags);
out << uint8_t(flags);
return out;
}
+339 -102
View File
@@ -38,68 +38,22 @@ using ImgUtil = VulkanImageUtility;
namespace {
inline void blitFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect, VkFilter filter,
VulkanAttachment src, VulkanAttachment dst,
const VkExtent2D srcExtent, VulkanAttachment src, VulkanAttachment dst,
const VkOffset3D srcRect[2], const VkOffset3D dstRect[2]) {
if constexpr (FVK_ENABLED(FVK_DEBUG_BLITTER)) {
utils::slog.d << "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;
}
const VkImageSubresourceRange srcRange = {
.aspectMask = aspect,
.baseMipLevel = src.level,
.levelCount = 1,
.baseArrayLayer = src.layer,
.layerCount = 1,
};
const VkImageSubresourceRange dstRange = {
.aspectMask = aspect,
.baseMipLevel = dst.level,
.levelCount = 1,
.baseArrayLayer = dst.layer,
.layerCount = 1,
};
VulkanLayout oldSrcLayout = src.getLayout();
VulkanLayout oldDstLayout = dst.getLayout();
src.texture->transitionLayout(cmdbuffer, srcRange, VulkanLayout::TRANSFER_SRC);
dst.texture->transitionLayout(cmdbuffer, dstRange, VulkanLayout::TRANSFER_DST);
const VkImageBlit blitRegions[1] = {{
.srcSubresource = { aspect, src.level, src.layer, 1 },
.srcOffsets = { srcRect[0], srcRect[1] },
.dstSubresource = { aspect, dst.level, dst.layer, 1 },
.dstOffsets = { dstRect[0], dstRect[1] },
}};
vkCmdBlitImage(cmdbuffer,
src.getImage(), ImgUtil::getVkLayout(VulkanLayout::TRANSFER_SRC),
dst.getImage(), ImgUtil::getVkLayout(VulkanLayout::TRANSFER_DST),
1, blitRegions, filter);
.srcSubresource = {aspect, src.level, src.layer, 1},
.srcOffsets = {srcRect[0], srcRect[1]},
.dstSubresource = {aspect, dst.level, dst.layer, 1},
.dstOffsets = {dstRect[0], dstRect[1]},
}};
if (oldSrcLayout == VulkanLayout::UNDEFINED) {
oldSrcLayout = ImgUtil::getDefaultLayout(src.texture->usage);
}
if (oldDstLayout == VulkanLayout::UNDEFINED) {
oldDstLayout = ImgUtil::getDefaultLayout(dst.texture->usage);
}
src.texture->transitionLayout(cmdbuffer, srcRange, oldSrcLayout);
dst.texture->transitionLayout(cmdbuffer, dstRange, oldDstLayout);
}
inline void resolveFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect,
VulkanAttachment src, VulkanAttachment dst) {
if constexpr (FVK_ENABLED(FVK_DEBUG_BLITTER)) {
utils::slog.d << "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;
}
const VkImageResolve resolveRegions[1] = {{
.srcSubresource = {aspect, src.level, src.layer, 1},
.srcOffset = srcRect[0],
.dstSubresource = {aspect, dst.level, dst.layer, 1},
.dstOffset = dstRect[0],
.extent = {srcExtent.width, srcExtent.height, 1},
}};
const VkImageSubresourceRange srcRange = {
.aspectMask = aspect,
@@ -117,25 +71,32 @@ inline void resolveFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspe
.layerCount = 1,
};
if constexpr (FVK_ENABLED(FVK_DEBUG_BLITTER)) {
utils::slog.d << "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;
}
VulkanLayout oldSrcLayout = src.getLayout();
VulkanLayout oldDstLayout = dst.getLayout();
src.texture->transitionLayout(cmdbuffer, srcRange, VulkanLayout::TRANSFER_SRC);
dst.texture->transitionLayout(cmdbuffer, dstRange, VulkanLayout::TRANSFER_DST);
assert_invariant(
aspect != VK_IMAGE_ASPECT_DEPTH_BIT && "Resolve with depth is not yet supported.");
const VkImageResolve resolveRegions[1] = {{
.srcSubresource = { aspect, src.level, src.layer, 1 },
.srcOffset = { 0, 0 },
.dstSubresource = { aspect, dst.level, dst.layer, 1 },
.dstOffset = { 0, 0 },
.extent = { src.getExtent2D().width, src.getExtent2D().height, 1 },
}};
vkCmdResolveImage(cmdbuffer,
src.getImage(), ImgUtil::getVkLayout(VulkanLayout::TRANSFER_SRC),
dst.getImage(), ImgUtil::getVkLayout(VulkanLayout::TRANSFER_DST),
1, resolveRegions);
if (src.texture->samples > 1 && dst.texture->samples == 1) {
assert_invariant(
aspect != VK_IMAGE_ASPECT_DEPTH_BIT && "Resolve with depth is not yet supported.");
vkCmdResolveImage(cmdbuffer,
src.getImage(), ImgUtil::getVkLayout(VulkanLayout::TRANSFER_SRC),
dst.getImage(), ImgUtil::getVkLayout(VulkanLayout::TRANSFER_DST),
1, resolveRegions);
} else {
vkCmdBlitImage(cmdbuffer,
src.getImage(), ImgUtil::getVkLayout(VulkanLayout::TRANSFER_SRC),
dst.getImage(), ImgUtil::getVkLayout(VulkanLayout::TRANSFER_DST),
1, blitRegions, filter);
}
if (oldSrcLayout == VulkanLayout::UNDEFINED) {
oldSrcLayout = ImgUtil::getDefaultLayout(src.texture->usage);
@@ -154,22 +115,52 @@ struct BlitterUniforms {
}// anonymous namespace
VulkanBlitter::VulkanBlitter() noexcept = default;
VulkanBlitter::VulkanBlitter(VulkanStagePool& stagePool, VulkanPipelineCache& pipelineCache,
VulkanFboCache& fboCache, VulkanSamplerCache& samplerCache) noexcept
: mStagePool(stagePool), mPipelineCache(pipelineCache), mFramebufferCache(fboCache),
mSamplerCache(samplerCache) {}
void VulkanBlitter::initialize(VkPhysicalDevice physicalDevice, VkDevice device,
VmaAllocator allocator, VulkanCommands* commands) noexcept {
VmaAllocator allocator, VulkanCommands* commands, VulkanTexture* emptyTexture) noexcept {
mPhysicalDevice = physicalDevice;
mDevice = device;
mAllocator = allocator;
mCommands = commands;
mEmptyTexture = emptyTexture;
}
void VulkanBlitter::resolve(VulkanAttachment dst, VulkanAttachment src) {
void VulkanBlitter::blitColor(BlitArgs args) {
const VulkanAttachment src = args.srcTarget->getColor(args.targetIndex);
const VulkanAttachment dst = args.dstTarget->getColor(0);
const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT;
// src and dst should have the same aspect here
VkImageAspectFlags const aspect = src.texture->getImageAspect();
#if FVK_ENABLED(FVK_DEBUG_BLIT_FORMAT)
VkPhysicalDevice const gpu = mPhysicalDevice;
VkFormatProperties info;
vkGetPhysicalDeviceFormatProperties(gpu, src.getFormat(), &info);
if (!ASSERT_POSTCONDITION_NON_FATAL(info.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT,
"Source format is not blittable %d", src.getFormat())) {
return;
}
vkGetPhysicalDeviceFormatProperties(gpu, dst.getFormat(), &info);
if (!ASSERT_POSTCONDITION_NON_FATAL(info.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT,
"Destination format is not blittable %d", dst.getFormat())) {
return;
}
#endif
VulkanCommandBuffer& commands = mCommands->get();
VkCommandBuffer const cmdbuffer = commands.buffer();
commands.acquire(src.texture);
commands.acquire(dst.texture);
assert_invariant(!(aspect & VK_IMAGE_ASPECT_DEPTH_BIT));
blitFast(cmdbuffer, aspect, args.filter, args.srcTarget->getExtent(), src, dst,
args.srcRectPair, args.dstRectPair);
}
void VulkanBlitter::blitDepth(BlitArgs args) {
const VulkanAttachment src = args.srcTarget->getDepth();
const VulkanAttachment dst = args.dstTarget->getDepth();
const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
#if FVK_ENABLED(FVK_DEBUG_BLIT_FORMAT)
VkPhysicalDevice const gpu = mPhysicalDevice;
@@ -186,40 +177,286 @@ void VulkanBlitter::resolve(VulkanAttachment dst, VulkanAttachment src) {
}
#endif
VulkanCommandBuffer& commands = mCommands->get();
VkCommandBuffer const cmdbuffer = commands.buffer();
commands.acquire(src.texture);
commands.acquire(dst.texture);
resolveFast(cmdbuffer, aspect, src, dst);
}
assert_invariant(src.texture && dst.texture);
void VulkanBlitter::blit(VkFilter filter,
VulkanAttachment dst, const VkOffset3D* dstRectPair,
VulkanAttachment src, const VkOffset3D* srcRectPair) {
#if FVK_ENABLED(FVK_DEBUG_BLIT_FORMAT)
VkPhysicalDevice const gpu = mPhysicalDevice;
VkFormatProperties info;
vkGetPhysicalDeviceFormatProperties(gpu, src.getFormat(), &info);
if (!ASSERT_POSTCONDITION_NON_FATAL(info.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT,
"Depth src format is not blittable %d", src.getFormat())) {
if (src.texture->samples > 1 && dst.texture->samples == 1) {
blitSlowDepth(args.filter, args.srcTarget->getExtent(), src, dst, args.srcRectPair,
args.dstRectPair);
return;
}
vkGetPhysicalDeviceFormatProperties(gpu, dst.getFormat(), &info);
if (!ASSERT_POSTCONDITION_NON_FATAL(info.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT,
"Depth dst format is not blittable %d", dst.getFormat())) {
return;
}
#endif
// src and dst should have the same aspect here
VkImageAspectFlags const aspect = src.texture->getImageAspect();
VulkanCommandBuffer& commands = mCommands->get();
VkCommandBuffer const cmdbuffer = commands.buffer();
commands.acquire(src.texture);
commands.acquire(dst.texture);
blitFast(cmdbuffer, aspect, filter, src, dst, srcRectPair, dstRectPair);
blitFast(cmdbuffer, aspect, args.filter, args.srcTarget->getExtent(), src, dst, args.srcRectPair,
args.dstRectPair);
}
void VulkanBlitter::terminate() noexcept {
if (mDepthResolveProgram) {
delete mDepthResolveProgram;
mDepthResolveProgram = nullptr;
}
if (mTriangleBuffer) {
delete mTriangleBuffer;
mTriangleBuffer = nullptr;
}
if (mParamsBuffer) {
delete mParamsBuffer;
mParamsBuffer = nullptr;
}
}
// If we created these shader modules in the constructor, the device might not be ready yet.
// It is easier to do lazy initialization, which can also improve load time.
void VulkanBlitter::lazyInit() noexcept {
if (mDepthResolveProgram != nullptr) {
return;
}
assert_invariant(mDevice);
auto decode = [device = mDevice](const uint8_t* compressed, int compressedSize) {
const size_t spirvSize = smolv::GetDecodedBufferSize(compressed, compressedSize);
FixedCapacityVector<uint8_t> spirv(spirvSize);
smolv::Decode(compressed, compressedSize, spirv.data(), spirvSize);
VkShaderModuleCreateInfo moduleInfo = {};
moduleInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
moduleInfo.codeSize = spirvSize;
moduleInfo.pCode = (uint32_t*) spirv.data();
VkShaderModule result = VK_NULL_HANDLE;
vkCreateShaderModule(device, &moduleInfo, VKALLOC, &result);
assert_invariant(result);
return result;
};
VkShaderModule vertexShader = decode(VKSHADERS_BLITDEPTHVS_DATA, VKSHADERS_BLITDEPTHVS_SIZE);
VkShaderModule fragmentShader = decode(VKSHADERS_BLITDEPTHFS_DATA, VKSHADERS_BLITDEPTHFS_SIZE);
// Allocate one anonymous sampler at slot 0.
VulkanProgram::CustomSamplerInfoList samplers = {
{0, 0, ShaderStageFlags::FRAGMENT},
};
mDepthResolveProgram = new VulkanProgram(mDevice, vertexShader, fragmentShader, samplers);
#if FVK_ENABLED(FVK_DEBUG_BLITTER)
utils::slog.d << "Created Shader Module for VulkanBlitter "
<< "shaders = (" << vertexShader << ", " << fragmentShader << ")"
<< utils::io::endl;
#endif
static const float kTriangleVertices[] = {
-1.0f, -1.0f,
+1.0f, -1.0f,
-1.0f, +1.0f,
+1.0f, +1.0f,
};
VulkanCommandBuffer& commands = mCommands->get();
VkCommandBuffer const cmdbuffer = commands.buffer();
mTriangleBuffer = new VulkanBuffer(mAllocator, mStagePool, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
sizeof(kTriangleVertices));
mTriangleBuffer->loadFromCpu(cmdbuffer, kTriangleVertices, 0, sizeof(kTriangleVertices));
mParamsBuffer = new VulkanBuffer(mAllocator, mStagePool, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
sizeof(BlitterUniforms));
}
// At a high level, the procedure for resolving depth looks like this:
// 1. Load uniforms
// 2. Begin render pass
// 3. Draw a big triangle
// 4. End render pass.
void VulkanBlitter::blitSlowDepth(VkFilter filter, const VkExtent2D srcExtent, VulkanAttachment src,
VulkanAttachment dst, const VkOffset3D srcRect[2], const VkOffset3D dstRect[2]) {
lazyInit();
VulkanCommandBuffer* commands = &mCommands->get();
VkCommandBuffer const cmdbuffer = commands->buffer();
commands->acquire(src.texture);
commands->acquire(dst.texture);
BlitterUniforms const uniforms = {
.sampleCount = src.texture->samples,
.inverseSampleCount = 1.0f / float(src.texture->samples),
};
mParamsBuffer->loadFromCpu(cmdbuffer, &uniforms, 0, sizeof(uniforms));
VkImageAspectFlags const aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
// We will transition the src into sampler layout and also keep it in sampler layout for
// consistency.
VulkanLayout const samplerLayout = VulkanLayout::DEPTH_SAMPLER;
// BEGIN RENDER PASS
// -----------------
const VulkanFboCache::RenderPassKey rpkey = {
.initialColorLayoutMask = 0,
.initialDepthLayout = VulkanLayout::UNDEFINED,
.renderPassDepthLayout = samplerLayout,
.finalDepthLayout = samplerLayout,
.depthFormat = dst.getFormat(),
.clear = {},
.discardStart = TargetBufferFlags::DEPTH,
.samples = 1,
};
const VkRenderPass renderPass = mFramebufferCache.getRenderPass(rpkey);
mPipelineCache.bindRenderPass(renderPass, 0);
const VulkanFboCache::FboKey fbkey {
.renderPass = renderPass,
.width = (uint16_t) (dst.texture->width >> dst.level),
.height = (uint16_t) (dst.texture->height >> dst.level),
.layers = 1,
.samples = rpkey.samples,
.color = {},
.resolve = {},
.depth = dst.getImageView(aspect),
};
const VkFramebuffer vkfb = mFramebufferCache.getFramebuffer(fbkey);
VkRenderPassBeginInfo renderPassInfo {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = renderPass,
.framebuffer = vkfb,
};
renderPassInfo.renderArea.offset.x = dstRect[0].x;
renderPassInfo.renderArea.offset.y = dstRect[0].y;
renderPassInfo.renderArea.extent.width = dstRect[1].x - dstRect[0].x;
renderPassInfo.renderArea.extent.height = dstRect[1].y - dstRect[0].y;
// We need to transition the source into a sampler since it'll be sampled in the shader.
const VkImageSubresourceRange srcRange = {
.aspectMask = aspect,
.baseMipLevel = src.level,
.levelCount = 1,
.baseArrayLayer = src.layer,
.layerCount = 1,
};
src.texture->transitionLayout(cmdbuffer, srcRange, samplerLayout);
vkCmdBeginRenderPass(cmdbuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport = {
.x = (float) dstRect[0].x,
.y = (float) dstRect[0].y,
.width = (float) renderPassInfo.renderArea.extent.width,
.height = (float) renderPassInfo.renderArea.extent.height,
.minDepth = 0.0f,
.maxDepth = 1.0f
};
vkCmdSetViewport(cmdbuffer, 0, 1, &viewport);
// DRAW THE TRIANGLE
// -----------------
mPipelineCache.bindProgram(mDepthResolveProgram);
mPipelineCache.bindPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
auto vkraster = mPipelineCache.getCurrentRasterState();
vkraster.depthWriteEnable = true;
vkraster.depthCompareOp = SamplerCompareFunc::A;
vkraster.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
vkraster.alphaToCoverageEnable = false,
vkraster.blendEnable = VK_FALSE,
vkraster.srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
vkraster.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
vkraster.colorBlendOp = BlendEquation::ADD,
vkraster.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
vkraster.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
vkraster.alphaBlendOp = BlendEquation::ADD,
vkraster.colorWriteMask = (VkColorComponentFlags) 0,
vkraster.cullMode = VK_CULL_MODE_NONE;
vkraster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
vkraster.depthBiasEnable = VK_FALSE;
vkraster.colorTargetCount = 0;
mPipelineCache.bindRasterState(vkraster);
VkBuffer buffers[1] = {};
VkDeviceSize offsets[1] = {};
buffers[0] = mTriangleBuffer->getGpuBuffer();
VkVertexInputAttributeDescription attribDesc = {
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
};
VkVertexInputBindingDescription bufferDesc = {
.binding = 0,
.stride = sizeof(float) * 2,
};
mPipelineCache.bindVertexArray(&attribDesc, &bufferDesc, 1);
// Select nearest filtering and clamp_to_edge.
VkSampler vksampler = mSamplerCache.getSampler({});
VkDescriptorImageInfo samplers[VulkanPipelineCache::SAMPLER_BINDING_COUNT];
VulkanTexture* textures[VulkanPipelineCache::SAMPLER_BINDING_COUNT] = {nullptr};
for (auto& sampler : samplers) {
sampler = {
.sampler = vksampler,
.imageView = mEmptyTexture->getPrimaryImageView(),
.imageLayout = ImgUtil::getVkLayout(VulkanLayout::READ_WRITE),
};
}
samplers[0] = {
.sampler = vksampler,
.imageView = src.getImageView(VK_IMAGE_ASPECT_DEPTH_BIT),
.imageLayout = ImgUtil::getVkLayout(samplerLayout),
};
textures[0] = src.texture;
mPipelineCache.bindSamplers(samplers, textures,
VulkanPipelineCache::getUsageFlags(0, ShaderStageFlags::FRAGMENT));
auto previousUbo = mPipelineCache.getUniformBufferBinding(0);
mPipelineCache.bindUniformBuffer(0, mParamsBuffer->getGpuBuffer());
if (!mPipelineCache.bindDescriptors(cmdbuffer)) {
assert_invariant(false);
}
const VkRect2D scissor = {
.offset = renderPassInfo.renderArea.offset,
.extent = renderPassInfo.renderArea.extent,
};
mPipelineCache.bindScissor(cmdbuffer, scissor);
if (!mPipelineCache.bindPipeline(commands)) {
assert_invariant(false);
}
vkCmdBindVertexBuffers(cmdbuffer, 0, 1, buffers, offsets);
vkCmdDraw(cmdbuffer, 4, 1, 0, 0);
// END RENDER PASS
// ---------------
vkCmdEndRenderPass(cmdbuffer);
VkMemoryBarrier barrier {
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
};
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
vkCmdPipelineBarrier(cmdbuffer, srcStageMask,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | // <== For Mali
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0, 1, &barrier, 0, nullptr, 0, nullptr);
mPipelineCache.bindUniformBuffer(0, previousUbo.buffer, previousUbo.offset, previousUbo.size);
}
} // namespace filament::backend
+29 -7
View File
@@ -32,24 +32,46 @@ struct VulkanProgram;
class VulkanBlitter {
public:
VulkanBlitter() noexcept;
VulkanBlitter(VulkanStagePool& stagePool, VulkanPipelineCache& pipelineCache,
VulkanFboCache& fboCache, VulkanSamplerCache& samplerCache) noexcept;
void initialize(VkPhysicalDevice physicalDevice, VkDevice device,
VmaAllocator allocator, VulkanCommands* commands) noexcept;
void initialize(VkPhysicalDevice physicalDevice, VkDevice device, VmaAllocator allocator,
VulkanCommands* commands, VulkanTexture* emptyTexture) noexcept;
void blit(VkFilter filter,
VulkanAttachment dst, const VkOffset3D* dstRectPair,
VulkanAttachment src, const VkOffset3D* srcRectPair);
struct BlitArgs {
const VulkanRenderTarget* dstTarget;
const VkOffset3D* dstRectPair;
const VulkanRenderTarget* srcTarget;
const VkOffset3D* srcRectPair;
VkFilter filter = VK_FILTER_NEAREST;
int targetIndex = 0;
};
void resolve(VulkanAttachment dst, VulkanAttachment src);
void blitColor(BlitArgs args);
void blitDepth(BlitArgs args);
void terminate() noexcept;
private:
void lazyInit() noexcept;
void blitSlowDepth(VkFilter filter, const VkExtent2D srcExtent, VulkanAttachment src,
VulkanAttachment dst, const VkOffset3D srcRect[2], const VkOffset3D dstRect[2]);
VulkanBuffer* mTriangleBuffer = nullptr;
VulkanBuffer* mParamsBuffer = nullptr;
VulkanProgram* mDepthResolveProgram = nullptr;
UTILS_UNUSED VkPhysicalDevice mPhysicalDevice;
VkDevice mDevice;
VmaAllocator mAllocator;
VulkanCommands* mCommands;
VulkanTexture* mEmptyTexture;
VulkanStagePool& mStagePool;
VulkanPipelineCache& mPipelineCache;
VulkanFboCache& mFramebufferCache;
VulkanSamplerCache& mSamplerCache;
};
} // namespace filament::backend
+34 -160
View File
@@ -156,6 +156,7 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
mResourceManager(&mResourceAllocator),
mThreadSafeResourceManager(&mResourceAllocator),
mPipelineCache(&mResourceAllocator),
mBlitter(mStagePool, mPipelineCache, mFramebufferCache, mSamplerCache),
mReadPixels(mPlatform->getDevice()),
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported) {
@@ -205,7 +206,7 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
mPipelineCache.setDummyTexture(mEmptyTexture->getPrimaryImageView());
mBlitter.initialize(mPlatform->getPhysicalDevice(), mPlatform->getDevice(), mAllocator,
mCommands.get());
mCommands.get(), mEmptyTexture.get());
}
VulkanDriver::~VulkanDriver() noexcept = default;
@@ -756,7 +757,6 @@ bool VulkanDriver::isFrameTimeSupported() {
}
bool VulkanDriver::isAutoDepthResolveSupported() {
// TODO: this could be supported with vk 1.2 or VK_KHR_depth_stencil_resolve
return false;
}
@@ -772,11 +772,6 @@ bool VulkanDriver::isParallelShaderCompileSupported() {
return false;
}
bool VulkanDriver::isDepthStencilResolveSupported() {
// TODO: apparently it could be supported in core 1.2 and/or with VK_KHR_depth_stencil_resolve
return false;
}
bool VulkanDriver::isWorkaroundNeeded(Workaround workaround) {
switch (workaround) {
case Workaround::SPLIT_EASU: {
@@ -960,43 +955,10 @@ void VulkanDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint
void VulkanDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
}
void VulkanDriver::generateMipmaps(Handle<HwTexture> th) {
auto* const t = mResourceAllocator.handle_cast<VulkanTexture*>(th);
assert_invariant(t);
void VulkanDriver::generateMipmaps(Handle<HwTexture> th) { }
int32_t layerCount = int32_t(t->depth);
if (t->target == SamplerType::SAMPLER_CUBEMAP_ARRAY ||
t->target == SamplerType::SAMPLER_CUBEMAP) {
layerCount *= 6;
}
// FIXME: the loop below can perform many layout transitions and back. We should be
// able to optimize that.
uint8_t level = 0;
int32_t srcw = int32_t(t->width);
int32_t srch = int32_t(t->height);
do {
int32_t const dstw = std::max(srcw >> 1, 1);
int32_t const dsth = std::max(srch >> 1, 1);
const VkOffset3D srcOffsets[2] = {{ 0, 0, 0 }, { srcw, srch, 1 }};
const VkOffset3D dstOffsets[2] = {{ 0, 0, 0 }, { dstw, dsth, 1 }};
// TODO: there should be a way to do this using layerCount in vkBlitImage
// TODO: vkBlitImage should be able to handle 3D textures too
for (int32_t layer = 0; layer < layerCount; layer++) {
mBlitter.blit(VK_FILTER_LINEAR,
{ .texture = t, .level = uint8_t(level + 1), .layer = (uint16_t)layer },
dstOffsets,
{ .texture = t, .level = uint8_t(level ), .layer = (uint16_t)layer },
srcOffsets);
}
level++;
srcw = dstw;
srch = dsth;
} while ((srcw > 1 || srch > 1) && level < t->levels);
t->setPrimaryRange(0, t->levels - 1);
bool VulkanDriver::canGenerateMipmaps() {
return false;
}
void VulkanDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
@@ -1477,138 +1439,50 @@ void VulkanDriver::readBufferSubData(backend::BufferObjectHandle boh,
scheduleDestroy(std::move(p));
}
void VulkanDriver::resolve(
Handle<HwTexture> dst, uint8_t srcLevel, uint8_t srcLayer,
Handle<HwTexture> src, uint8_t dstLevel, uint8_t dstLayer) {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("resolve");
ASSERT_PRECONDITION(mCurrentRenderPass.renderPass == VK_NULL_HANDLE,
"resolve() cannot be invoked inside a render pass.");
auto* const srcTexture = mResourceAllocator.handle_cast<VulkanTexture*>(src);
auto* const dstTexture = mResourceAllocator.handle_cast<VulkanTexture*>(dst);
assert_invariant(srcTexture);
assert_invariant(dstTexture);
ASSERT_PRECONDITION(
dstTexture->width == srcTexture->width && dstTexture->height == srcTexture->height,
"invalid resolve: src and dst sizes don't match");
ASSERT_PRECONDITION(srcTexture->samples > 1 && dstTexture->samples == 1,
"invalid resolve: src.samples=%u, dst.samples=%u",
+srcTexture->samples, +dstTexture->samples);
ASSERT_PRECONDITION(srcTexture->format == dstTexture->format,
"src and dst texture format don't match");
ASSERT_PRECONDITION(!isDepthFormat(srcTexture->format),
"can't resolve depth formats");
ASSERT_PRECONDITION(!isStencilFormat(srcTexture->format),
"can't resolve stencil formats");
ASSERT_PRECONDITION(any(dstTexture->usage & TextureUsage::BLIT_DST),
"texture doesn't have BLIT_DST");
ASSERT_PRECONDITION(any(srcTexture->usage & TextureUsage::BLIT_SRC),
"texture doesn't have BLIT_SRC");
mBlitter.resolve(
{ .texture = dstTexture, .level = dstLevel, .layer = dstLayer },
{ .texture = srcTexture, .level = srcLevel, .layer = srcLayer });
FVK_SYSTRACE_END();
}
void VulkanDriver::blit(
Handle<HwTexture> dst, uint8_t srcLevel, uint8_t srcLayer, math::uint2 dstOrigin,
Handle<HwTexture> src, uint8_t dstLevel, uint8_t dstLayer, math::uint2 srcOrigin,
math::uint2 size) {
void VulkanDriver::blit(TargetBufferFlags buffers, Handle<HwRenderTarget> dst, Viewport dstRect,
Handle<HwRenderTarget> src, Viewport srcRect, SamplerMagFilter filter) {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("blit");
ASSERT_PRECONDITION(mCurrentRenderPass.renderPass == VK_NULL_HANDLE,
"blit() cannot be invoked inside a render pass.");
assert_invariant(mCurrentRenderPass.renderPass == VK_NULL_HANDLE);
auto* const srcTexture = mResourceAllocator.handle_cast<VulkanTexture*>(src);
auto* const dstTexture = mResourceAllocator.handle_cast<VulkanTexture*>(dst);
// blit operation only support COLOR0 color buffer
assert_invariant(
!(buffers & (TargetBufferFlags::COLOR_ALL & ~TargetBufferFlags::COLOR0)));
ASSERT_PRECONDITION(any(dstTexture->usage & TextureUsage::BLIT_DST),
"texture doesn't have BLIT_DST");
ASSERT_PRECONDITION(any(srcTexture->usage & TextureUsage::BLIT_SRC),
"texture doesn't have BLIT_SRC");
ASSERT_PRECONDITION(srcTexture->format == dstTexture->format,
"src and dst texture format don't match");
// The Y inversion below makes it so that Vk matches GL and Metal.
auto const srcLeft = int32_t(srcOrigin.x);
auto const dstLeft = int32_t(dstOrigin.x);
auto const srcTop = int32_t(srcTexture->height - (srcOrigin.y + size.y));
auto const dstTop = int32_t(dstTexture->height - (dstOrigin.y + size.y));
auto const srcRight = int32_t(srcOrigin.x + size.x);
auto const dstRight = int32_t(dstOrigin.x + size.x);
auto const srcBottom = int32_t(srcTop + size.y);
auto const dstBottom = int32_t(dstTop + size.y);
VkOffset3D const srcOffsets[2] = { { srcLeft, srcTop, 0 }, { srcRight, srcBottom, 1 }};
VkOffset3D const dstOffsets[2] = { { dstLeft, dstTop, 0 }, { dstRight, dstBottom, 1 }};
// no scaling guaranteed
mBlitter.blit(VK_FILTER_NEAREST,
{ .texture = dstTexture, .level = dstLevel, .layer = dstLayer }, dstOffsets,
{ .texture = srcTexture, .level = srcLevel, .layer = srcLayer }, srcOffsets);
FVK_SYSTRACE_END();
}
void VulkanDriver::blitDEPRECATED(TargetBufferFlags buffers,
Handle<HwRenderTarget> dst, Viewport dstRect,
Handle<HwRenderTarget> src, Viewport srcRect,
SamplerMagFilter filter) {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("blitDEPRECATED");
// Note: blitDEPRECATED is only used for Renderer::copyFrame()
ASSERT_PRECONDITION(mCurrentRenderPass.renderPass == VK_NULL_HANDLE,
"blitDEPRECATED() cannot be invoked inside a render pass.");
ASSERT_PRECONDITION(buffers == TargetBufferFlags::COLOR0,
"blitDEPRECATED only supports COLOR0");
ASSERT_PRECONDITION(srcRect.left >= 0 && srcRect.bottom >= 0 &&
dstRect.left >= 0 && dstRect.bottom >= 0,
"Source and destination rects must be positive.");
if (UTILS_UNLIKELY(mCurrentRenderPass.renderPass)) {
utils::slog.e << "Blits cannot be invoked inside a render pass." << utils::io::endl;
return;
}
VulkanRenderTarget* dstTarget = mResourceAllocator.handle_cast<VulkanRenderTarget*>(dst);
VulkanRenderTarget* srcTarget = mResourceAllocator.handle_cast<VulkanRenderTarget*>(src);
VkFilter const vkfilter = (filter == SamplerMagFilter::NEAREST) ?
VK_FILTER_NEAREST : VK_FILTER_LINEAR;
VkFilter vkfilter = filter == SamplerMagFilter::NEAREST ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
// The Y inversion below makes it so that Vk matches GL and Metal.
VkExtent2D const srcExtent = srcTarget->getExtent();
VkExtent2D const dstExtent = dstTarget->getExtent();
const VkExtent2D srcExtent = srcTarget->getExtent();
const int32_t srcLeft = srcRect.left;
const int32_t srcTop = srcExtent.height - srcRect.bottom - srcRect.height;
const int32_t srcRight = srcRect.left + srcRect.width;
const int32_t srcBottom = srcTop + srcRect.height;
const VkOffset3D srcOffsets[2] = { { srcLeft, srcTop, 0 }, { srcRight, srcBottom, 1 }};
auto const dstLeft = int32_t(dstRect.left);
auto const srcLeft = int32_t(srcRect.left);
auto const dstTop = int32_t(dstExtent.height - (dstRect.bottom + dstRect.height));
auto const srcTop = int32_t(srcExtent.height - (srcRect.bottom + srcRect.height));
auto const dstRight = int32_t(dstRect.left + dstRect.width);
auto const srcRight = int32_t(srcRect.left + srcRect.width);
auto const dstBottom = int32_t(dstTop + dstRect.height);
auto const srcBottom = int32_t(srcTop + srcRect.height);
VkOffset3D const srcOffsets[2] = { { srcLeft, srcTop, 0 }, { srcRight, srcBottom, 1 }};
VkOffset3D const dstOffsets[2] = { { dstLeft, dstTop, 0 }, { dstRight, dstBottom, 1 }};
const VkExtent2D dstExtent = dstTarget->getExtent();
const int32_t dstLeft = dstRect.left;
const int32_t dstTop = dstExtent.height - dstRect.bottom - dstRect.height;
const int32_t dstRight = dstRect.left + dstRect.width;
const int32_t dstBottom = dstTop + dstRect.height;
const VkOffset3D dstOffsets[2] = { { dstLeft, dstTop, 0 }, { dstRight, dstBottom, 1 }};
mBlitter.blit(vkfilter,
dstTarget->getColor(0), dstOffsets,
srcTarget->getColor(0), srcOffsets);
if (any(buffers & TargetBufferFlags::DEPTH) && srcTarget->hasDepth() && dstTarget->hasDepth()) {
mBlitter.blitDepth({dstTarget, dstOffsets, srcTarget, srcOffsets});
}
if (any(buffers & TargetBufferFlags::COLOR0)) {
mBlitter.blitColor({ dstTarget, dstOffsets, srcTarget, srcOffsets, vkfilter, int(0) });
}
FVK_SYSTRACE_END();
}
@@ -73,7 +73,7 @@
#elif defined(WIN32)
// No platform specific includes
#else
// Not a supported Vulkan platform
#error Not a supported Vulkan platform
#endif
using namespace bluevk;
+283 -7
View File
@@ -233,7 +233,7 @@ TEST_F(BackendTest, ColorMagnify) {
// Do a "magnify" blit from level 1 of the source RT to the level 0 of the destination RT.
const int srcLevel = 1;
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTargets[0],
api.blit(TargetBufferFlags::COLOR0, dstRenderTargets[0],
{0, 0, kDstTexWidth, kDstTexHeight}, srcRenderTargets[srcLevel],
{0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel}, SamplerMagFilter::LINEAR);
@@ -308,8 +308,7 @@ TEST_F(BackendTest, ColorMinify) {
// Do a "minify" blit from level 1 of the source RT to the level 0 of the destination RT.
const int srcLevel = 1;
api.blitDEPRECATED(TargetBufferFlags::COLOR0,
api.blit(TargetBufferFlags::COLOR0,
dstRenderTargets[0], {0, 0, kDstTexWidth, kDstTexHeight},
srcRenderTargets[srcLevel], {0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel},
SamplerMagFilter::LINEAR);
@@ -335,6 +334,147 @@ TEST_F(BackendTest, ColorMinify) {
executeCommands();
}
TEST_F(BackendTest, DepthMinify) {
auto& api = getDriverApi();
constexpr int kSrcTexWidth = 1024;
constexpr int kSrcTexHeight = 1024;
constexpr int kDstTexWidth = 256;
constexpr int kDstTexHeight = 256;
constexpr auto kColorTexFormat = TextureFormat::RGBA8;
constexpr auto kDepthTexFormat = TextureFormat::DEPTH24;
constexpr int kNumLevels = 3;
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
api.makeCurrent(swapChain, swapChain);
// Create a program.
ProgramHandle program;
{
ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform);
Program prog = shaderGen.getProgram(api);
prog.uniformBlockBindings({{"params", 1}});
program = api.createProgram(std::move(prog));
}
// Create a VertexBuffer, IndexBuffer, and RenderPrimitive.
TrianglePrimitive* triangle = new TrianglePrimitive(api);
// Create textures for the first rendering pass.
Handle<HwTexture> srcColorTexture = api.createTexture(
SamplerType::SAMPLER_2D, kNumLevels, kColorTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
Handle<HwTexture> srcDepthTexture = api.createTexture(
SamplerType::SAMPLER_2D, 1, kDepthTexFormat, 1, kSrcTexWidth, kSrcTexHeight,
1, TextureUsage::DEPTH_ATTACHMENT);
// Create textures for the second rendering pass.
Handle<HwTexture> dstColorTexture = api.createTexture(
SamplerType::SAMPLER_2D, kNumLevels, kColorTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
Handle<HwTexture> dstDepthTexture = api.createTexture(
SamplerType::SAMPLER_2D, 1, kDepthTexFormat, 1, kDstTexWidth, kDstTexHeight,
1, TextureUsage::DEPTH_ATTACHMENT);
// Create render targets.
const int level = 0;
Handle<HwRenderTarget> srcRenderTarget = api.createRenderTarget(
TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH,
kSrcTexWidth >> level, kSrcTexHeight >> level, 1,
{{ srcColorTexture, level }},
{ srcDepthTexture, level }, {});
Handle<HwRenderTarget> dstRenderTarget = api.createRenderTarget(
TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH,
kDstTexWidth >> level, kDstTexHeight >> level, 1,
{{ dstColorTexture, level }},
{ dstDepthTexture, level }, {});
// Prep for rendering.
RenderPassParams params = {};
params.flags.clear = TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH;
params.clearColor = float4(1, 1, 0, 1);
params.clearDepth = 1.0;
params.viewport.width = kSrcTexWidth;
params.viewport.height = kSrcTexHeight;
PipelineState state = {};
state.rasterState.colorWrite = true;
state.rasterState.depthWrite = true;
state.rasterState.depthFunc = RasterState::DepthFunc::L;
state.rasterState.culling = RasterState::CullingMode::NONE;
state.program = program;
auto ubuffer = api.createBufferObject(sizeof(MaterialParams),
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
api.makeCurrent(swapChain, swapChain);
api.beginFrame(0, 0);
api.bindUniformBuffer(0, ubuffer);
// Draw red triangle into srcRenderTarget.
uploadUniforms(api, ubuffer, {
.color = float4(1, 0, 0, 1),
.scale = float4(1, 1, 0.5, 0),
});
api.beginRenderPass(srcRenderTarget, params);
api.draw(state, triangle->getRenderPrimitive(), 1);
api.endRenderPass();
api.endFrame(0);
// Copy over the color buffer and the depth buffer.
api.blit(TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, dstRenderTarget,
{0, 0, kDstTexWidth, kDstTexHeight}, srcRenderTarget,
{0, 0, kSrcTexWidth, kSrcTexHeight}, SamplerMagFilter::LINEAR);
// Draw a larger blue triangle into dstRenderTarget. We carefully place it below the red
// triangle in order to exercise depth testing.
api.beginFrame(0, 0);
params.viewport.width = kDstTexWidth;
params.viewport.height = kDstTexHeight;
params.flags.clear = TargetBufferFlags::NONE;
uploadUniforms(api, ubuffer, {
.color = float4(0, 0, 1, 1),
.scale = float4(1.2, 1.2, 0.75, 0),
});
api.beginRenderPass(dstRenderTarget, params);
api.draw(state, triangle->getRenderPrimitive(), 1);
api.endRenderPass();
api.endFrame(0);
// Grab a screenshot.
ScreenshotParams sparams { kDstTexWidth, kDstTexHeight, "DepthMinify.png" };
api.beginFrame(0, 0);
dumpScreenshot(api, dstRenderTarget, &sparams);
api.commit(swapChain);
api.endFrame(0);
// Wait for the ReadPixels result to come back.
api.finish();
executeCommands();
getDriver().purge();
// Check if the image matches perfectly to our golden run.
const uint32_t expected = 0x92b6f5c1;
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", sparams.pixelHashResult, expected);
EXPECT_TRUE(sparams.pixelHashResult == expected);
// Cleanup.
api.destroyBufferObject(ubuffer);
api.destroyProgram(program);
api.destroyTexture(srcColorTexture);
api.destroyTexture(dstColorTexture);
api.destroyTexture(srcDepthTexture);
api.destroyTexture(dstDepthTexture);
api.destroySwapChain(swapChain);
api.destroyRenderTarget(srcRenderTarget);
api.destroyRenderTarget(dstRenderTarget);
delete triangle;
executeCommands();
}
TEST_F(BackendTest, ColorResolve) {
auto& api = getDriverApi();
@@ -410,7 +550,7 @@ TEST_F(BackendTest, ColorResolve) {
api.endFrame(0);
// Resolve the MSAA render target into the single-sample render target.
api.blitDEPRECATED(TargetBufferFlags::COLOR,
api.blit(TargetBufferFlags::COLOR,
dstRenderTarget, {0, 0, kDstTexWidth, kDstTexHeight},
srcRenderTarget, {0, 0, kSrcTexWidth, kSrcTexHeight},
SamplerMagFilter::NEAREST);
@@ -437,6 +577,142 @@ TEST_F(BackendTest, ColorResolve) {
flushAndWait();
}
TEST_F(BackendTest, DepthResolve) {
auto& api = getDriverApi();
constexpr int kSrcTexWidth = 256;
constexpr int kSrcTexHeight = 256;
constexpr int kDstTexWidth = 256;
constexpr int kDstTexHeight = 256;
constexpr auto kColorTexFormat = TextureFormat::RGBA8;
constexpr auto kDepthTexFormat = TextureFormat::DEPTH24;
constexpr int kSampleCount = 4;
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
api.makeCurrent(swapChain, swapChain);
// Create a program.
ProgramHandle program;
{
ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform);
Program prog = shaderGen.getProgram(api);
prog.uniformBlockBindings({{"params", 1}});
program = api.createProgram(std::move(prog));
}
// Create a VertexBuffer, IndexBuffer, and RenderPrimitive.
TrianglePrimitive* triangle = new TrianglePrimitive(api);
// Create 4-sample textures.
Handle<HwTexture> srcColorTexture = api.createTexture(
SamplerType::SAMPLER_2D, 1, kColorTexFormat, kSampleCount, kSrcTexWidth, kSrcTexHeight, 1,
TextureUsage::COLOR_ATTACHMENT);
Handle<HwTexture> srcDepthTexture = api.createTexture(
SamplerType::SAMPLER_2D, 1, kDepthTexFormat, kSampleCount, kSrcTexWidth, kSrcTexHeight, 1,
TextureUsage::DEPTH_ATTACHMENT);
// Create 1-sample textures.
Handle<HwTexture> dstColorTexture = api.createTexture(
SamplerType::SAMPLER_2D, 1, kColorTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
Handle<HwTexture> dstDepthTexture = api.createTexture(
SamplerType::SAMPLER_2D, 1, kDepthTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
TextureUsage::DEPTH_ATTACHMENT);
// Create a 4-sample render target with 4-sample textures.
Handle<HwRenderTarget> srcRenderTarget = api.createRenderTarget(
TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, kSrcTexWidth, kSrcTexHeight,
kSampleCount, {{ srcColorTexture }}, { srcDepthTexture }, {});
// Create a 1-sample render target with 1-sample textures.
Handle<HwRenderTarget> dstRenderTarget = api.createRenderTarget(
TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, kDstTexWidth, kDstTexHeight,
1, {{ dstColorTexture }}, { dstDepthTexture }, {});
// Prep for rendering.
RenderPassParams params = {};
params.flags.clear = TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH;
params.clearColor = float4(1, 1, 0, 1);
params.clearDepth = 1.0;
params.flags.discardEnd = TargetBufferFlags::NONE;
params.viewport.width = kSrcTexWidth;
params.viewport.height = kSrcTexHeight;
PipelineState state = {};
state.rasterState.colorWrite = true;
state.rasterState.depthWrite = true;
state.rasterState.depthFunc = RasterState::DepthFunc::L;
state.rasterState.culling = RasterState::CullingMode::NONE;
state.program = program;
auto ubuffer = api.createBufferObject(sizeof(MaterialParams),
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
api.makeCurrent(swapChain, swapChain);
api.beginFrame(0, 0);
api.bindUniformBuffer(0, ubuffer);
// Draw red triangle into srcRenderTarget.
uploadUniforms(api, ubuffer, {
.color = float4(1, 0, 0, 1),
.scale = float4(1, 1, 0.5, 0),
});
api.beginRenderPass(srcRenderTarget, params);
api.draw(state, triangle->getRenderPrimitive(), 1);
api.endRenderPass();
api.endFrame(0);
// Resolve the MSAA color and depth buffers into the single-sample render target.
api.blit(TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, dstRenderTarget,
{0, 0, kDstTexWidth, kDstTexHeight}, srcRenderTarget,
{0, 0, kSrcTexWidth, kSrcTexHeight}, SamplerMagFilter::LINEAR);
// Draw a larger blue triangle into dstRenderTarget. We carefully place it below the red
// triangle in order to exercise depth testing.
api.beginFrame(0, 0);
params.viewport.width = kDstTexWidth;
params.viewport.height = kDstTexHeight;
params.flags.clear = TargetBufferFlags::NONE;
uploadUniforms(api, ubuffer, {
.color = float4(0, 0, 1, 1),
.scale = float4(1.2, 1.2, 0.75, 0),
});
api.beginRenderPass(dstRenderTarget, params);
api.draw(state, triangle->getRenderPrimitive(), 1);
api.endRenderPass();
// Grab a screenshot.
ScreenshotParams sparams { kDstTexWidth, kDstTexHeight, "DepthResolve.png" };
api.beginFrame(0, 0);
dumpScreenshot(api, dstRenderTarget, &sparams);
api.commit(swapChain);
api.endFrame(0);
// Wait for the ReadPixels result to come back.
api.finish();
executeCommands();
getDriver().purge();
// Check if the image matches perfectly to our golden run.
const uint32_t expected = 0x5a38e6ba;
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", sparams.pixelHashResult, expected);
EXPECT_TRUE(sparams.pixelHashResult == expected);
// Cleanup.
api.destroyBufferObject(ubuffer);
api.destroyProgram(program);
api.destroyTexture(srcColorTexture);
api.destroyTexture(dstColorTexture);
api.destroyTexture(srcDepthTexture);
api.destroyTexture(dstDepthTexture);
api.destroySwapChain(swapChain);
api.destroyRenderTarget(srcRenderTarget);
api.destroyRenderTarget(dstRenderTarget);
delete triangle;
executeCommands();
}
TEST_F(BackendTest, Blit2DTextureArray) {
auto& api = getDriverApi();
@@ -479,7 +755,7 @@ TEST_F(BackendTest, Blit2DTextureArray) {
// Do a blit from kSrcTexLayer of the source RT to kDstTexLayer of the destination RT.
const int srcLevel = 0;
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget,
api.blit(TargetBufferFlags::COLOR0, dstRenderTarget,
{0, 0, kDstTexWidth, kDstTexHeight}, srcRenderTarget,
{0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel}, SamplerMagFilter::LINEAR);
@@ -570,7 +846,7 @@ TEST_F(BackendTest, BlitRegion) {
api.createRenderTarget(TargetBufferFlags::COLOR, kDstTexWidth >> kDstLevel,
kDstTexHeight >> kDstLevel, 1, {dstTexture, kDstLevel, 0}, {}, {});
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget, dstRect, srcRenderTarget, srcRect,
api.blit(TargetBufferFlags::COLOR0, dstRenderTarget, dstRect, srcRenderTarget, srcRect,
SamplerMagFilter::LINEAR);
// Push through an empty frame to allow the texture to upload and the blit to execute.
@@ -657,7 +933,7 @@ TEST_F(BackendTest, BlitRegionToSwapChain) {
api.beginFrame(0, 0);
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget,
api.blit(TargetBufferFlags::COLOR0, dstRenderTarget,
dstRect, srcRenderTargets[srcLevel],
srcRect, SamplerMagFilter::LINEAR);
+3 -43
View File
@@ -293,7 +293,6 @@ struct DepthOfFieldOptions {
MEDIAN
};
float cocScale = 1.0f; //!< circle of confusion scale factor (amount of blur)
float cocAspectRatio = 1.0f; //!< width/height aspect ratio of the circle of confusion (simulate anamorphic lenses)
float maxApertureDiameter = 0.01f; //!< maximum aperture diameter in meters (zero to disable rotation)
bool enabled = false; //!< enable or disable depth of field effect
Filter filter = Filter::MEDIAN; //!< filter to use for filling gaps in the kernel
@@ -402,7 +401,7 @@ struct AmbientOcclusionOptions {
};
/**
* Options for Multi-Sample Anti-aliasing (MSAA)
* Options for Temporal Multi-Sample Anti-aliasing (MSAA)
* @see setMultiSampleAntiAliasingOptions()
*/
struct MultiSampleAntiAliasingOptions {
@@ -425,51 +424,12 @@ struct MultiSampleAntiAliasingOptions {
/**
* Options for Temporal Anti-aliasing (TAA)
* Most TAA parameters are extremely costly to change, as they will trigger the TAA post-process
* shaders to be recompiled. These options should be changed or set during initialization.
* `filterWidth`, `feedback` and `jitterPattern`, however, can be changed at any time.
*
* `feedback` of 0.1 effectively accumulates a maximum of 19 samples in steady state.
* see "A Survey of Temporal Antialiasing Techniques" by Lei Yang and all for more information.
*
* @see setTemporalAntiAliasingOptions()
*/
struct TemporalAntiAliasingOptions {
float filterWidth = 1.0f; //!< reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother)
float feedback = 0.12f; //!< history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA).
float lodBias = -1.0f; //!< texturing lod bias (typically -1 or -2)
float filterWidth = 1.0f; //!< reconstruction filter width typically between 0 (sharper, aliased) and 1 (smoother)
float feedback = 0.04f; //!< history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA).
bool enabled = false; //!< enables or disables temporal anti-aliasing
bool upscaling = false; //!< 4x TAA upscaling. Disables Dynamic Resolution. [BETA]
enum class BoxType : uint8_t {
AABB, //!< use an AABB neighborhood
VARIANCE, //!< use the variance of the neighborhood (not recommended)
AABB_VARIANCE //!< use both AABB and variance
};
enum class BoxClipping : uint8_t {
ACCURATE, //!< Accurate box clipping
CLAMP, //!< clamping
NONE //!< no rejections (use for debugging)
};
enum class JitterPattern : uint8_t {
RGSS_X4, //! 4-samples, rotated grid sampling
UNIFORM_HELIX_X4, //! 4-samples, uniform grid in helix sequence
HALTON_23_X8, //! 8-samples of halton 2,3
HALTON_23_X16 //! 16-samples of halton 2,3
};
bool filterHistory = true; //!< whether to filter the history buffer
bool filterInput = true; //!< whether to apply the reconstruction filter to the input
bool useYCoCg = false; //!< whether to use the YcoCg color-space for history rejection
BoxType boxType = BoxType::AABB; //!< type of color gamut box
BoxClipping boxClipping = BoxClipping::ACCURATE; //!< clipping algorithm
JitterPattern jitterPattern = JitterPattern::HALTON_23_X16; //! Jitter Pattern
float varianceGamma = 1.0f; //! High values increases ghosting artefact, lower values increases jittering, range [0.75, 1.25]
bool preventFlickering = false; //!< adjust the feedback dynamically to reduce flickering
bool historyReprojection = true; //!< whether to apply history reprojection (debug option)
};
/**
-6
View File
@@ -252,12 +252,6 @@ public:
* automatically schedule itself for presentation. Instead, the application must call the
* PresentCallable passed to the FrameScheduledCallback.
*
* If your application delays the call to the PresentCallable by, for example, calling it on a
* separate thread, you must ensure all PresentCallables have been called before shutting down
* the Filament Engine. You can do this by issuing an Engine::flushAndWait before calling
* Engine::shutdown. This is necessary to ensure the Filament Engine has had a chance to clean
* up all memory related to frame presentation.
*
* @param callback A callback, or nullptr to unset.
* @param user An optional pointer to user data passed to the callback function.
*
+2 -3
View File
@@ -450,13 +450,12 @@ public:
/**
* Generates all the mipmap levels automatically. This requires the texture to have a
* color-renderable format and usage set to BLIT_SRC | BLIT_DST. If unspecified,
* usage bits are set automatically.
* color-renderable format.
*
* @param engine Engine this texture is associated to.
*
* @attention \p engine must be the instance passed to Builder::build()
* @attention This Texture instance must NOT use SamplerType::SAMPLER_3D or it has no effect
* @attention This Texture instance must NOT use Sampler::SAMPLER_CUBEMAP or it has no effect
*/
void generateMipmaps(Engine& engine) const noexcept;
+2 -1
View File
@@ -71,7 +71,8 @@ void PerShadowMapUniforms::prepareCamera(Transaction const& transaction,
s.clipControl = engine.getDriverApi().getClipSpaceParams();
}
void PerShadowMapUniforms::prepareLodBias(Transaction const& transaction, float bias) noexcept {
void PerShadowMapUniforms::prepareLodBias(Transaction const& transaction,
float bias) noexcept {
auto& s = edit(transaction);
s.lodBias = bias;
}
+2 -3
View File
@@ -50,7 +50,7 @@ PerViewUniforms::PerViewUniforms(FEngine& engine) noexcept
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
if (engine.getDFG().isValid()) {
TextureSampler const sampler(TextureSampler::MagFilter::LINEAR);
TextureSampler sampler(TextureSampler::MagFilter::LINEAR);
mSamplers.setSampler(PerViewSib::IBL_DFG_LUT,
{ engine.getDFG().getTexture(), sampler.getSamplerParams() });
}
@@ -96,10 +96,9 @@ void PerViewUniforms::prepareCamera(FEngine& engine, const CameraInfo& camera) n
s.clipControl = engine.getDriverApi().getClipSpaceParams();
}
void PerViewUniforms::prepareLodBias(float bias, float2 derivativesScale) noexcept {
void PerViewUniforms::prepareLodBias(float bias) noexcept {
auto& s = mUniforms.edit();
s.lodBias = bias;
s.derivativesScale = derivativesScale;
}
void PerViewUniforms::prepareExposure(float ev100) noexcept {
+1 -1
View File
@@ -69,7 +69,7 @@ public:
void terminate(backend::DriverApi& driver);
void prepareCamera(FEngine& engine, const CameraInfo& camera) noexcept;
void prepareLodBias(float bias, math::float2 derivativesScale) noexcept;
void prepareLodBias(float bias) noexcept;
/*
* @param viewport viewport (should be same as RenderPassParams::viewport)
+169 -323
View File
@@ -27,12 +27,9 @@
#include "details/Engine.h"
#include "fg/FrameGraph.h"
#include "fg/FrameGraphId.h"
#include "fg/FrameGraphResources.h"
#include "fg/FrameGraphTexture.h"
#include "fsr.h"
#include "FrameHistory.h"
#include "PerViewUniforms.h"
#include "RenderPass.h"
@@ -44,44 +41,13 @@
#include "generated/resources/materials.h"
#include <filament/Material.h>
#include <filament/MaterialEnums.h>
#include <filament/Options.h>
#include <filament/Viewport.h>
#include <private/filament/EngineEnums.h>
#include <backend/DriverEnums.h>
#include <backend/DriverApiForward.h>
#include <backend/Handle.h>
#include <backend/PipelineState.h>
#include <backend/PixelBufferDescriptor.h>
#include <private/backend/BackendUtils.h>
#include <math/half.h>
#include <math/mat2.h>
#include <math/mat3.h>
#include <math/mat4.h>
#include <math/scalar.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <utils/algorithm.h>
#include <utils/BitmaskEnum.h>
#include <utils/debug.h>
#include <utils/compiler.h>
#include <utils/FixedCapacityVector.h>
#include <algorithm>
#include <cmath>
#include <limits>
#include <string_view>
#include <variant>
#include <utility>
#include <stddef.h>
#include <stdint.h>
namespace filament {
@@ -201,21 +167,7 @@ FMaterialInstance* PostProcessManager::PostProcessMaterial::getMaterialInstance(
// ------------------------------------------------------------------------------------------------
const PostProcessManager::JitterSequence<4> PostProcessManager::sRGSS4 = {{
{ 0.625f, 0.125f },
{ 0.125f, 0.375f },
{ 0.875f, 0.625f },
{ 0.375f, 0.875f }
}};
const PostProcessManager::JitterSequence<4> PostProcessManager::sUniformHelix4 = {{
{ 0.25f, 0.25f },
{ 0.75f, 0.75f },
{ 0.25f, 0.75f },
{ 0.75f, 0.25f },
}};
const PostProcessManager::JitterSequence<16> PostProcessManager::sHaltonSamples = {{
const math::float2 PostProcessManager::sHaltonSamples[16] = {
{ filament::halton( 0, 2), filament::halton( 0, 3) },
{ filament::halton( 1, 2), filament::halton( 1, 3) },
{ filament::halton( 2, 2), filament::halton( 2, 3) },
@@ -232,7 +184,7 @@ const PostProcessManager::JitterSequence<16> PostProcessManager::sHaltonSamples
{ filament::halton(13, 2), filament::halton(13, 3) },
{ filament::halton(14, 2), filament::halton(14, 3) },
{ filament::halton(15, 2), filament::halton(15, 3) }
}};
};
PostProcessManager::PostProcessManager(FEngine& engine) noexcept
: mEngine(engine),
@@ -248,8 +200,7 @@ void PostProcessManager::registerPostProcessMaterial(std::string_view name, Mate
}
UTILS_NOINLINE
PostProcessManager::PostProcessMaterial& PostProcessManager::getPostProcessMaterial(
std::string_view name) noexcept {
PostProcessManager::PostProcessMaterial& PostProcessManager::getPostProcessMaterial(std::string_view name) noexcept {
assert_invariant(mMaterialRegistry.find(name) != mMaterialRegistry.end());
return mMaterialRegistry[name];
}
@@ -307,7 +258,6 @@ static const PostProcessManager::MaterialInfo sMaterialList[] = {
{ "fsr_easu_mobileF", MATERIAL(FSR_EASU_MOBILEF) },
{ "fsr_rcas", MATERIAL(FSR_RCAS) },
{ "debugShadowCascades", MATERIAL(DEBUGSHADOWCASCADES) },
{ "resolveDepth", MATERIAL(RESOLVEDEPTH) },
};
void PostProcessManager::init() noexcept {
@@ -726,34 +676,32 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
FrameGraphId<FrameGraphTexture> output;
};
// Needed for Vulkan and GLES. Some GLES implementations don't need it. Never needed for Metal.
auto& duplicateDepthPass = fg.addPass<DuplicateDepthPassData>("Duplicate Depth Pass",
[&](FrameGraph::Builder& builder, auto& data) {
// read the depth as an attachment
data.input = builder.read(depth,
FrameGraphTexture::Usage::BLIT_SRC);
FrameGraphTexture::Usage::DEPTH_ATTACHMENT);
auto desc = builder.getDescriptor(data.input);
desc.levels = 1; // only copy the base level
// create a new buffer for the copy
data.output = builder.createTexture("Depth Texture Copy", desc);
// output is an attachment
data.output = builder.write(data.output,
FrameGraphTexture::Usage::BLIT_DST);
FrameGraphTexture::Usage::DEPTH_ATTACHMENT);
builder.declareRenderPass("Depth Copy RenderTarget", {{ .depth = data.output }});
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
auto const& src = resources.getTexture(data.input);
auto const& dst = resources.getTexture(data.output);
auto const& srcSubDesc = resources.getSubResourceDescriptor(data.input);
auto const& dstSubDesc = resources.getSubResourceDescriptor(data.output);
auto const& desc = resources.getDescriptor(data.output);
assert_invariant(desc.samples == resources.getDescriptor(data.input).samples);
// here we can guarantee that src and dst format and size match, by construction.
driver.blit(
dst, dstSubDesc.level, dstSubDesc.layer, { 0, 0 },
src, srcSubDesc.level, srcSubDesc.layer, { 0, 0 },
{ desc.width, desc.height });
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
auto const& desc = resources.getDescriptor(data.input);
auto out = resources.getRenderPassInfo();
// create a temporary render target for source, needed for the blit.
auto inTarget = driver.createRenderTarget(TargetBufferFlags::DEPTH,
desc.width, desc.height, desc.samples, {},
{ resources.getTexture(data.input) }, {});
driver.blit(TargetBufferFlags::DEPTH,
out.target, out.params.viewport,
inTarget, out.params.viewport,
SamplerMagFilter::NEAREST);
driver.destroyRenderTarget(inTarget);
});
auto& SSAOPass = fg.addPass<SSAOPassData>("SSAO Pass",
@@ -804,7 +752,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
auto ssao = resources.getRenderPassInfo();
auto const& desc = resources.getDescriptor(data.depth);
// Estimate of the size in pixel units of a 1m tall/wide object viewed from 1m away (i.e. at z=-1)
// estimate of the size in pixel of a 1m tall/wide object viewed from 1m away (i.e. at z=-1)
const float projectionScale = std::min(
0.5f * cameraInfo.projection[0].x * desc.width,
0.5f * cameraInfo.projection[1].y * desc.height);
@@ -961,7 +909,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::bilateralBlurPass(FrameGraph
auto const& desc = resources.getDescriptor(data.blurred);
// unnormalized gaussian half-kernel of a given standard deviation
// returns number of samples stored in the array (max 16)
// returns number of samples stored in array (max 16)
constexpr size_t kernelArraySize = 16; // limited by bilateralBlur.mat
auto gaussianKernel =
[kernelArraySize](float* outKernel, size_t gaussianWidth, float stdDev) -> uint32_t {
@@ -1005,7 +953,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::generateGaussianMipmap(Frame
auto const subResourceDesc = fg.getSubResourceDescriptor(input);
// Create one subresource per level to be generated from the input. These will be our
// create one subresource per level to be generated from the input. These will be our
// destinations.
struct MipmapPassData {
FixedCapacityVector<FrameGraphId<FrameGraphTexture>> out;
@@ -1166,7 +1114,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
size_t const m = computeGaussianCoefficients(kernel,
std::min(sizeof(kernel) / sizeof(*kernel), kernelStorageSize));
std::string_view const sourceParameterName = is2dArray ? "sourceArray"sv : "source"sv;
std::string_view sourceParameterName = is2dArray ? "sourceArray"sv : "source"sv;
// horizontal pass
mi->setParameter(sourceParameterName, hwIn, {
.filterMag = SamplerMagFilter::LINEAR,
@@ -1212,7 +1160,7 @@ PostProcessManager::ScreenSpaceRefConfig PostProcessManager::prepareMipmapSSR(Fr
// The kernel-size was determined empirically so that we don't get too many artifacts
// due to the down-sampling with a box filter (which happens implicitly).
// Requires only 6 stored coefficients and 11 tap/pass
// requires only 6 stored coefficients and 11 tap/pass
// e.g.: size of 13 (4 stored coefficients)
// +-------+-------+-------*===*-------+-------+-------+
// ... | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ...
@@ -1376,10 +1324,10 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::generateMipmapSSR(
FrameGraphId<FrameGraphTexture> output,
bool needInputDuplication, ScreenSpaceRefConfig const& config) noexcept {
// Descriptor of our actual input image (e.g. reflection buffer or refraction framebuffer)
// descriptor of our actual input image (e.g. reflection buffer or refraction framebuffer)
auto const& desc = fg.getDescriptor(input);
// Descriptor of the destination. `output` is a subresource (i.e. a layer of a 2D array)
// descriptor of the destination. output is a subresource (i.e. a layer of a 2D array)
auto const& outDesc = fg.getDescriptor(output);
/*
@@ -1395,18 +1343,14 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::generateMipmapSSR(
if (desc.samples > 1 &&
outDesc.width == desc.width && outDesc.height == desc.height &&
desc.format == outDesc.format) {
// Resolve directly into the destination. This guarantees a blit/resolve will be
// performed (i.e.: the source is copied) and we also guarantee that format/scaling
// is the same after the forwardResource call below.
input = ppm.resolve(fg, "ssr", input, outDesc);
// resolve directly into the destination
input = ppm.resolveBaseLevelNoCheck(fg, "ssr", input, outDesc);
} else {
// First resolve (if needed), may be a no-op. Guarantees that format/size is unchanged
// by construction.
input = ppm.resolve(fg, "ssr", input, { .levels = 1 });
// Then blit into an appropriate texture, this handles scaling and format conversion.
// The input/output sizes may differ when non-homogenous DSR is enabled.
input = ppm.blit(fg, false, input, { 0, 0, desc.width, desc.height }, outDesc,
SamplerMagFilter::LINEAR, SamplerMinFilter::LINEAR);
// first resolve (if needed)
input = ppm.resolveBaseLevel(fg, "ssr", input);
// then blit into an appropriate texture
// this handles scaling, format conversion and mipmaping
input = ppm.opaqueBlit(fg, input, { 0, 0, desc.width, desc.height }, outDesc);
}
}
@@ -1428,7 +1372,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> depth,
const CameraInfo& cameraInfo,
bool translucent,
float2 bokehScale,
float bokehAspectRatio,
const DepthOfFieldOptions& dofOptions) noexcept {
assert_invariant(depth);
@@ -1439,7 +1383,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
const TextureFormat format = translucent ? TextureFormat::RGBA16F
: TextureFormat::R11F_G11F_B10F;
// Rotate the bokeh based on the aperture diameter (i.e. angle of the blades)
// rotate the bokeh based on the aperture diameter (i.e. angle of the blades)
float bokehAngle = f::PI / 6.0f;
if (dofOptions.maxApertureDiameter > 0.0f) {
bokehAngle += f::PI_2 * saturate(cameraInfo.A / dofOptions.maxApertureDiameter);
@@ -1818,8 +1762,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
mi->setParameter("tiles", tilesCocMinMax,
{ .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("cocToTexelScale", float2{
bokehScale.x / (inputDesc.width * dofResolution),
bokehScale.y / (inputDesc.height * dofResolution)
bokehAspectRatio / (inputDesc.width * dofResolution),
1.0 / (inputDesc.height * dofResolution)
});
mi->setParameter("cocToPixelScale", (1.0f / float(dofResolution)));
mi->setParameter("ringCounts", float4{
@@ -1925,6 +1869,14 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
return ppDoFCombine->output;
}
PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input,
BloomOptions& inoutBloomOptions,
backend::TextureFormat outFormat,
math::float2 scale) noexcept {
return bloomPass(fg, input, outFormat, inoutBloomOptions, scale);
}
FrameGraphId<FrameGraphTexture> PostProcessManager::downscalePass(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input,
FrameGraphTexture::Descriptor const& outDesc,
@@ -1956,11 +1908,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::downscalePass(FrameGraph& fg
return downsamplePass->output;
}
PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
PostProcessManager::BloomPassOutput PostProcessManager::bloomPass(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input, TextureFormat outFormat,
BloomOptions& inoutBloomOptions,
TemporalAntiAliasingOptions const& taaOptions,
float2 scale) noexcept {
BloomOptions& inoutBloomOptions, float2 scale) noexcept {
// Figure out a good size for the bloom buffer. We must use a fixed bloom buffer size so
// that the size/strength of the bloom doesn't vary much with the resolution, otherwise
@@ -2002,9 +1952,6 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
bool threshold = inoutBloomOptions.threshold;
// we don't need to do the fireflies reduction if we have TAA (it already does it)
bool fireflies = threshold && !taaOptions.enabled;
while (2 * bloomWidth < float(desc.width) || 2 * bloomHeight < float(desc.height)) {
if (inoutBloomOptions.quality == QualityLevel::LOW ||
inoutBloomOptions.quality == QualityLevel::MEDIUM) {
@@ -2013,9 +1960,8 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
.height = (desc.height = std::max(1u, desc.height / 2)),
.format = outFormat
},
threshold, inoutBloomOptions.highlight, fireflies);
threshold, inoutBloomOptions.highlight, threshold);
threshold = false; // we do the thresholding only once during down sampling
fireflies = false; // we do the fireflies reduction only once during down sampling
} else if (inoutBloomOptions.quality == QualityLevel::HIGH ||
inoutBloomOptions.quality == QualityLevel::ULTRA) {
// In high quality mode, we increase the size of the bloom buffer such that the
@@ -2036,7 +1982,7 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
input = downscalePass(fg, input,
{ .width = width, .height = height, .format = outFormat },
threshold, inoutBloomOptions.highlight, fireflies);
threshold, inoutBloomOptions.highlight, threshold);
struct BloomPassData {
FrameGraphId<FrameGraphTexture> out;
@@ -2545,9 +2491,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::fxaa(FrameGraph& fg,
return ppFXAA->output;
}
void PostProcessManager::prepareTaa(FrameGraph& fg,
filament::Viewport const& svp,
TemporalAntiAliasingOptions const& taaOptions,
void PostProcessManager::prepareTaa(FrameGraph& fg, filament::Viewport const& svp,
FrameHistory& frameHistory,
FrameHistoryEntry::TemporalAA FrameHistoryEntry::*pTaa,
CameraInfo* inoutCameraInfo,
@@ -2559,33 +2503,9 @@ void PostProcessManager::prepareTaa(FrameGraph& fg,
current.projection = inoutCameraInfo->projection * inoutCameraInfo->getUserViewMatrix();
current.frameId = previous.frameId + 1;
auto jitterPosition = [pattern = taaOptions.jitterPattern](size_t frameIndex){
using JitterPattern = TemporalAntiAliasingOptions::JitterPattern;
switch (pattern) {
case JitterPattern::RGSS_X4:
return sRGSS4(frameIndex);
case JitterPattern::UNIFORM_HELIX_X4:
return sUniformHelix4(frameIndex);
case JitterPattern::HALTON_23_X8:
return sHaltonSamples(frameIndex % 8);
case JitterPattern::HALTON_23_X16:
return sHaltonSamples(frameIndex);
}
};
// sample position within a pixel [-0.5, 0.5]
// for metal/vulkan we need to reverse the y-offset
current.jitter = jitterPosition(previous.frameId);
float2 jitter = current.jitter;
switch (mEngine.getBackend()) {
case Backend::VULKAN:
case Backend::METAL:
jitter.y = -jitter.y;
UTILS_FALLTHROUGH;
case Backend::OPENGL:
default:
break;
}
float2 const jitter = halton(previous.frameId) - 0.5f;
current.jitter = jitter;
float2 const jitterInClipSpace = jitter * (2.0f / float2{ svp.width, svp.height });
@@ -2602,37 +2522,6 @@ void PostProcessManager::prepareTaa(FrameGraph& fg,
});
}
void PostProcessManager::configureTemporalAntiAliasingMaterial(
TemporalAntiAliasingOptions const& taaOptions) noexcept {
FMaterial* const ma = getPostProcessMaterial("taa").getMaterial(mEngine);
bool dirty = false;
auto setConstantParameter =
[&dirty](FMaterial* const ma, std::string_view name, auto value) noexcept {
auto id = ma->getSpecializationConstantId(name);
if (id.has_value()) {
if (ma->setConstant(id.value(), value)) {
dirty = true;
}
}
};
setConstantParameter(ma, "historyReprojection", taaOptions.historyReprojection);
setConstantParameter(ma, "filterHistory", taaOptions.filterHistory);
setConstantParameter(ma, "filterInput", taaOptions.filterInput);
setConstantParameter(ma, "useYCoCg", taaOptions.useYCoCg);
setConstantParameter(ma, "preventFlickering", taaOptions.preventFlickering);
setConstantParameter(ma, "boxType", (int32_t)taaOptions.boxType);
setConstantParameter(ma, "boxClipping", (int32_t)taaOptions.boxClipping);
setConstantParameter(ma, "varianceGamma", taaOptions.varianceGamma);
if (dirty) {
ma->invalidate();
// TODO: call Material::compile(), we can't si that now because it works only
// with surface materials
}
}
FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input,
FrameGraphId<FrameGraphTexture> depth,
@@ -2665,10 +2554,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
auto& taaPass = fg.addPass<TAAData>("TAA",
[&](FrameGraph::Builder& builder, auto& data) {
auto desc = fg.getDescriptor(input);
if (taaOptions.upscaling) {
desc.width *= 2;
desc.height *= 2;
}
data.color = builder.sample(input);
data.depth = builder.sample(depth);
data.history = builder.sample(colorHistory);
@@ -2703,25 +2588,18 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
{ -1.0f, 1.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f },
};
constexpr float2 subSampleOffsets[4] = {
{ -0.25f, 0.25f }, { 0.25f, 0.25f }, { 0.25f, -0.25f }, { -0.25f, -0.25f }
};
float4 sum = 0.0;
float4 weights[9];
float sum = 0.0;
float weights[9];
// this doesn't get vectorized (probably because of exp()), so don't bother
// unrolling it.
#pragma nounroll
for (size_t i = 0; i < 9; i++) {
float2 const o = sampleOffsets[i];
for (size_t j = 0; j < 4; j++) {
float2 const s = taaOptions.upscaling ? subSampleOffsets[j] : float2{ 0 };
float2 const d = (o - current.jitter - s) / taaOptions.filterWidth;
// This is a gaussian fit of a 3.3-wide Blackman-Harris window
// see: "High Quality Temporal Supersampling" by Brian Karis
weights[i][j] = std::exp(-2.29f * (d.x * d.x + d.y * d.y));
}
float2 d = sampleOffsets[i] - current.jitter;
d *= 1.0f / taaOptions.filterWidth;
// this is a gaussian fit of a 3.3 Blackman Harris window
// see: "High Quality Temporal Supersampling" by Brian Karis
weights[i] = std::exp2(-3.3f * (d.x * d.x + d.y * d.y));
sum += weights[i];
}
for (auto& w : weights) {
@@ -2732,8 +2610,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
auto color = resources.getTexture(data.color);
auto depth = resources.getTexture(data.depth);
auto history = resources.getTexture(data.history);
auto const& material = getPostProcessMaterial("taa");
auto const& material = getPostProcessMaterial("taa");
FMaterialInstance* mi = material.getMaterialInstance(mEngine);
mi->setParameter("color", color, {}); // nearest
mi->setParameter("depth", depth, {}); // nearest
@@ -2743,7 +2621,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
.filterMin = SamplerMinFilter::LINEAR
});
mi->setParameter("filterWeights", weights, 9);
mi->setParameter("jitter", current.jitter);
mi->setParameter("reprojection",
mat4f{ historyProjection * inverse(current.projection) } *
normalizedToClip);
@@ -2787,11 +2664,61 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
return exportHistoryPass->color;
}
FrameGraphId<FrameGraphTexture> PostProcessManager::opaqueBlit(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input, filament::Viewport const& vp,
FrameGraphTexture::Descriptor const& outDesc,
SamplerMagFilter filter) noexcept {
struct PostProcessScaling {
FrameGraphId<FrameGraphTexture> input;
FrameGraphId<FrameGraphTexture> output;
};
auto& ppBlit = fg.addPass<PostProcessScaling>("opaque blit",
[&](FrameGraph::Builder& builder, auto& data) {
// we currently have no use for this case, so we just assert. This is better for now to trap
// cases that we might not intend.
assert_invariant(fg.getDescriptor(input).samples <= 1);
data.output = builder.declareRenderPass(
builder.createTexture("opaque blit output", outDesc));
data.input = builder.read(input);
// We use a RenderPass for the source here, instead of just creating a render
// target from data.input in the execute closure, because data.input may refer to
// an imported render target and in this case data.input won't resolve to an actual
// HwTexture handle. Using a RenderPass works because data.input will resolve
// to the actual imported render target and will have the correct viewport.
builder.declareRenderPass("opaque blit input", {
.attachments = { .color = { data.input }},
.viewport = vp
});
},
[=](FrameGraphResources const& resources, auto const&, DriverApi& driver) {
auto out = resources.getRenderPassInfo(0);
auto in = resources.getRenderPassInfo(1);
driver.blit(TargetBufferFlags::COLOR,
out.target, out.params.viewport,
in.target, in.params.viewport,
filter);
});
// we rely on automatic culling of unused render passes
return ppBlit->output;
}
FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool translucent,
DynamicResolutionOptions dsrOptions, FrameGraphId<FrameGraphTexture> input,
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filter) noexcept {
if (UTILS_LIKELY(!translucent && dsrOptions.quality == QualityLevel::LOW &&
mEngine.getDriverApi().getFeatureLevel() >= FeatureLevel::FEATURE_LEVEL_1)) {
return opaqueBlit(fg, input, vp, outDesc, filter);
}
// The code below cannot handle sub-resources
assert_invariant(fg.getSubResourceDescriptor(input).layer == 0);
assert_invariant(fg.getSubResourceDescriptor(input).level == 0);
@@ -2989,164 +2916,83 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
}
FrameGraphId<FrameGraphTexture> PostProcessManager::blit(FrameGraph& fg, bool translucent,
FrameGraphId<FrameGraphTexture> input,
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
SamplerMagFilter filterMag,
SamplerMinFilter filterMin) noexcept {
// TODO: add support for sub-resources
assert_invariant(fg.getSubResourceDescriptor(input).layer == 0);
assert_invariant(fg.getSubResourceDescriptor(input).level == 0);
struct QuadBlitData {
FrameGraphId<FrameGraphTexture> input;
FrameGraphId<FrameGraphTexture> output;
};
auto& ppQuadBlit = fg.addPass<QuadBlitData>("blitting",
[&](FrameGraph::Builder& builder, auto& data) {
data.input = builder.sample(input);
data.output = builder.createTexture("upscaled output", outDesc);
data.output = builder.write(data.output,
FrameGraphTexture::Usage::COLOR_ATTACHMENT);
builder.declareRenderPass(builder.getName(data.output), {
.attachments = { .color = { data.output }},
.clearFlags = TargetBufferFlags::DEPTH });
},
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
auto color = resources.getTexture(data.input);
auto const& inputDesc = resources.getDescriptor(data.input);
auto const& outputDesc = resources.getDescriptor(data.output);
auto out = resources.getRenderPassInfo();
// --------------------------------------------------------------------------------
// set uniforms
PostProcessMaterial const& material = getPostProcessMaterial("blitLow");
auto* mi = material.getMaterialInstance(mEngine);
mi->setParameter("color", color, {
.filterMag = filterMag,
.filterMin = filterMin
});
mi->setParameter("resolution",
float4{ outputDesc.width, outputDesc.height,
1.0f / outputDesc.width, 1.0f / outputDesc.height });
mi->setParameter("viewport", float4{
float(vp.left) / inputDesc.width,
float(vp.bottom) / inputDesc.height,
float(vp.width) / inputDesc.width,
float(vp.height) / inputDesc.height
});
mi->commit(driver);
mi->use(driver);
PipelineState pipeline(material.getPipelineState(mEngine));
if (translucent) {
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
pipeline.rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA;
pipeline.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
}
render(out, pipeline, driver);
});
return ppQuadBlit->output;
FrameGraphId<FrameGraphTexture> input, filament::Viewport const& vp,
FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filter) noexcept {
// for now, we implement this by calling upscale() with the low-quality setting.
return upscale(fg, translucent, { .quality = QualityLevel::LOW }, input, vp, outDesc, filter);
}
FrameGraphId<FrameGraphTexture> PostProcessManager::resolve(FrameGraph& fg,
const char* outputBufferName, FrameGraphId<FrameGraphTexture> input,
FrameGraphTexture::Descriptor outDesc) noexcept {
FrameGraphId<FrameGraphTexture> PostProcessManager::resolveBaseLevel(FrameGraph& fg,
const char* outputBufferName, FrameGraphId<FrameGraphTexture> input) noexcept {
// Don't do anything if we're not a MSAA buffer
auto const& inDesc = fg.getDescriptor(input);
if (inDesc.samples <= 1) {
auto desc = fg.getDescriptor(input);
if (desc.samples <= 1) {
return input;
}
desc.samples = 0;
desc.levels = 1;
return resolveBaseLevelNoCheck(fg, outputBufferName, input, desc);
}
// we currently don't support stencil resolve
assert_invariant(!isStencilFormat(inDesc.format));
// The Metal / Vulkan backends currently don't support depth/stencil resolve.
if (isDepthFormat(inDesc.format) && (!mEngine.getDriverApi().isDepthStencilResolveSupported())) {
return resolveDepth(fg, outputBufferName, input, outDesc);
}
outDesc.width = inDesc.width;
outDesc.height = inDesc.height;
outDesc.format = inDesc.format;
outDesc.samples = 0;
FrameGraphId<FrameGraphTexture> PostProcessManager::resolveBaseLevelNoCheck(FrameGraph& fg,
const char* outputBufferName, FrameGraphId<FrameGraphTexture> input,
FrameGraphTexture::Descriptor const& desc) noexcept {
struct ResolveData {
FrameGraphId<FrameGraphTexture> input;
FrameGraphId<FrameGraphTexture> output;
backend::TargetBufferFlags inFlags;
FrameGraphTexture::Usage usage;
};
auto& ppResolve = fg.addPass<ResolveData>("resolve",
[&](FrameGraph::Builder& builder, auto& data) {
data.input = builder.read(input, FrameGraphTexture::Usage::BLIT_SRC);
data.output = builder.createTexture(outputBufferName, outDesc);
data.output = builder.write(data.output, FrameGraphTexture::Usage::BLIT_DST);
FrameGraphRenderPass::Descriptor rpDesc;
auto& rpDescAttachment = isDepthFormat(desc.format) ?
rpDesc.attachments.depth :
rpDesc.attachments.color[0];
data.usage = isDepthFormat(desc.format) ?
FrameGraphTexture::Usage::DEPTH_ATTACHMENT :
FrameGraphTexture::Usage::COLOR_ATTACHMENT;
data.inFlags = isDepthFormat(desc.format) ?
backend::TargetBufferFlags::DEPTH :
backend::TargetBufferFlags::COLOR0;
data.input = builder.read(input, data.usage);
rpDescAttachment = builder.createTexture(outputBufferName, desc);
rpDescAttachment = builder.write(rpDescAttachment, data.usage);
data.output = rpDescAttachment;
builder.declareRenderPass("Resolve Pass", rpDesc);
},
[](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
auto const& src = resources.getTexture(data.input);
auto const& dst = resources.getTexture(data.output);
auto const& srcSubDesc = resources.getSubResourceDescriptor(data.input);
auto const& dstSubDesc = resources.getSubResourceDescriptor(data.output);
UTILS_UNUSED_IN_RELEASE auto const& srcDesc = resources.getDescriptor(data.input);
UTILS_UNUSED_IN_RELEASE auto const& dstDesc = resources.getDescriptor(data.output);
assert_invariant(src);
assert_invariant(dst);
assert_invariant(srcDesc.format == dstDesc.format);
assert_invariant(srcDesc.width == dstDesc.width && srcDesc.height == dstDesc.height);
driver.resolve(
dst, dstSubDesc.level, dstSubDesc.layer,
src, srcSubDesc.level, srcSubDesc.layer);
});
auto inDesc = resources.getDescriptor(data.input);
auto in = resources.getTexture(data.input);
auto out = resources.getRenderPassInfo();
return ppResolve->output;
}
assert_invariant(in);
FrameGraphId<FrameGraphTexture> PostProcessManager::resolveDepth(FrameGraph& fg,
const char* outputBufferName, FrameGraphId<FrameGraphTexture> input,
FrameGraphTexture::Descriptor outDesc) noexcept {
Handle<HwRenderTarget> inRt;
if (data.usage == FrameGraphTexture::Usage::COLOR_ATTACHMENT) {
inRt = driver.createRenderTarget(data.inFlags,
out.params.viewport.width, out.params.viewport.height,
inDesc.samples, {{ in }}, {}, {});
}
if (data.usage == FrameGraphTexture::Usage::DEPTH_ATTACHMENT) {
inRt = driver.createRenderTarget(data.inFlags,
out.params.viewport.width, out.params.viewport.height,
inDesc.samples, {}, { in }, {});
}
// Don't do anything if we're not a MSAA buffer
auto const& inDesc = fg.getDescriptor(input);
if (inDesc.samples <= 1) {
return input;
}
driver.blit(data.inFlags,
out.target, out.params.viewport, inRt, out.params.viewport,
SamplerMagFilter::NEAREST);
UTILS_UNUSED_IN_RELEASE auto const& inSubDesc = fg.getSubResourceDescriptor(input);
assert_invariant(isDepthFormat(inDesc.format));
assert_invariant(inSubDesc.layer == 0);
assert_invariant(inSubDesc.level == 0);
outDesc.width = inDesc.width;
outDesc.height = inDesc.height;
outDesc.format = inDesc.format;
outDesc.samples = 0;
struct ResolveData {
FrameGraphId<FrameGraphTexture> input;
FrameGraphId<FrameGraphTexture> output;
};
auto& ppResolve = fg.addPass<ResolveData>("resolveDepth",
[&](FrameGraph::Builder& builder, auto& data) {
data.input = builder.sample(input);
data.output = builder.createTexture(outputBufferName, outDesc);
data.output = builder.write(data.output, FrameGraphTexture::Usage::DEPTH_ATTACHMENT);
builder.declareRenderPass(builder.getName(data.output), {
.attachments = { .depth = { data.output }},
.clearFlags = TargetBufferFlags::DEPTH });
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
auto const& input = resources.getTexture(data.input);
auto const& material = getPostProcessMaterial("resolveDepth");
auto* mi = material.getMaterialInstance(mEngine);
mi->setParameter("depth", input, {}); // NEAREST
commitAndRender(resources.getRenderPassInfo(), material, driver);
driver.destroyRenderTarget(inRt);
});
return ppResolve->output;
@@ -3191,7 +3037,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg
auto& material = getPostProcessMaterial("vsmMipmap");
// When generating shadow map mip levels, we want to preserve the 1 texel border.
// (note clearing never respects the scissor in Filament)
// (note clearing never respects the scissor in filament)
PipelineState pipeline(material.getPipelineState(mEngine));
pipeline.scissor = { 1u, 1u, dim - 2u, dim - 2u };
+67 -78
View File
@@ -86,10 +86,6 @@ public:
void init() noexcept;
void terminate(backend::DriverApi& driver) noexcept;
void configureTemporalAntiAliasingMaterial(
TemporalAntiAliasingOptions const& taaOptions) noexcept;
// methods below are ordered relative to their position in the pipeline (as much as possible)
// structure (depth) pass
@@ -162,7 +158,7 @@ public:
FrameGraphId<FrameGraphTexture> depth,
const CameraInfo& cameraInfo,
bool translucent,
math::float2 bokehScale,
float bokehAspectRatio,
const DepthOfFieldOptions& dofOptions) noexcept;
// Bloom
@@ -171,9 +167,7 @@ public:
FrameGraphId<FrameGraphTexture> flare;
};
BloomPassOutput bloom(FrameGraph& fg, FrameGraphId<FrameGraphTexture> input,
backend::TextureFormat outFormat,
BloomOptions& inoutBloomOptions,
TemporalAntiAliasingOptions const& taaOptions,
BloomOptions& inoutBloomOptions, backend::TextureFormat outFormat,
math::float2 scale) noexcept;
FrameGraphId<FrameGraphTexture> flarePass(FrameGraph& fg,
@@ -213,9 +207,7 @@ public:
backend::TextureFormat outFormat, bool translucent) noexcept;
// Temporal Anti-aliasing
void prepareTaa(FrameGraph& fg,
filament::Viewport const& svp,
TemporalAntiAliasingOptions const& taaOptions,
void prepareTaa(FrameGraph& fg, filament::Viewport const& svp,
FrameHistory& frameHistory,
FrameHistoryEntry::TemporalAA FrameHistoryEntry::*pTaa,
CameraInfo* inoutCameraInfo,
@@ -229,36 +221,32 @@ public:
TemporalAntiAliasingOptions const& taaOptions,
ColorGradingConfig const& colorGradingConfig) noexcept;
/*
* Blit/rescaling/resolves
*/
// Blit/rescaling/resolves
FrameGraphId<FrameGraphTexture> opaqueBlit(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input, filament::Viewport const& vp,
FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filter = backend::SamplerMagFilter::LINEAR) noexcept;
// high quality upscaler
// - when translucent, reverts to LINEAR
// - doens't handle sub-resouces
FrameGraphId<FrameGraphTexture> upscale(FrameGraph& fg, bool translucent,
DynamicResolutionOptions dsrOptions, FrameGraphId<FrameGraphTexture> input,
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filter) noexcept;
backend::SamplerMagFilter filter = backend::SamplerMagFilter::LINEAR) noexcept;
// upscale/downscale blitter using shaders
FrameGraphId<FrameGraphTexture> blit(FrameGraph& fg, bool translucent,
FrameGraphId<FrameGraphTexture> input,
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filterMag,
backend::SamplerMinFilter filterMin) noexcept;
FrameGraphId<FrameGraphTexture> input, filament::Viewport const& vp,
FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filter = backend::SamplerMagFilter::LINEAR) noexcept;
// Resolves base level of input and outputs a texture from outDesc.
// outDesc with, height, format and samples will be overridden.
FrameGraphId<FrameGraphTexture> resolve(FrameGraph& fg,
const char* outputBufferName, FrameGraphId<FrameGraphTexture> input,
FrameGraphTexture::Descriptor outDesc) noexcept;
// resolve base level of input and outputs a 1-level texture
FrameGraphId<FrameGraphTexture> resolveBaseLevel(FrameGraph& fg,
const char* outputBufferName, FrameGraphId<FrameGraphTexture> input) noexcept;
// Resolves base level of input and outputs a texture from outDesc.
// outDesc with, height, format and samples will be overridden.
FrameGraphId<FrameGraphTexture> resolveDepth(FrameGraph& fg,
// resolves base level of input and outputs a texture from outDesc. outDesc must
// have the same dimensions and format as input, or this will fail.
// outDesc can have mipmaps.
FrameGraphId<FrameGraphTexture> resolveBaseLevelNoCheck(FrameGraph& fg,
const char* outputBufferName, FrameGraphId<FrameGraphTexture> input,
FrameGraphTexture::Descriptor outDesc) noexcept;
FrameGraphTexture::Descriptor const& outDesc) noexcept;
// VSM shadow mipmap pass
FrameGraphId<FrameGraphTexture> vsmMipmapPass(FrameGraph& fg,
@@ -279,6 +267,48 @@ public:
backend::Handle<backend::HwTexture> getOneTextureArray() const;
backend::Handle<backend::HwTexture> getZeroTextureArray() const;
math::float2 halton(size_t index) const noexcept {
return mHaltonSamples[index & 0xFu];
}
private:
FEngine& mEngine;
class PostProcessMaterial;
struct BilateralPassConfig {
uint8_t kernelSize = 11;
bool bentNormals = false;
float standardDeviation = 1.0f;
float bilateralThreshold = 0.0625f;
float scale = 1.0f;
};
FrameGraphId<FrameGraphTexture> bilateralBlurPass(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input, FrameGraphId<FrameGraphTexture> depth,
math::int2 axis, float zf, backend::TextureFormat format,
BilateralPassConfig const& config) noexcept;
BloomPassOutput bloomPass(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input, backend::TextureFormat outFormat,
BloomOptions& inoutBloomOptions, math::float2 scale) noexcept;
FrameGraphId<FrameGraphTexture> downscalePass(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input,
FrameGraphTexture::Descriptor const& outDesc,
bool threshold, float highlight, bool fireflies) noexcept;
void commitAndRender(FrameGraphResources::RenderPassInfo const& out,
PostProcessMaterial const& material, uint8_t variant,
backend::DriverApi& driver) const noexcept;
void commitAndRender(FrameGraphResources::RenderPassInfo const& out,
PostProcessMaterial const& material,
backend::DriverApi& driver) const noexcept;
void render(FrameGraphResources::RenderPassInfo const& out,
backend::PipelineState const& pipeline,
backend::DriverApi& driver) const noexcept;
class PostProcessMaterial {
public:
PostProcessMaterial() noexcept;
@@ -312,62 +342,21 @@ public:
utils::FixedCapacityVector<ConstantInfo> mConstants{};
};
void registerPostProcessMaterial(std::string_view name, MaterialInfo const& info);
PostProcessMaterial& getPostProcessMaterial(std::string_view name) noexcept;
void commitAndRender(FrameGraphResources::RenderPassInfo const& out,
PostProcessMaterial const& material, uint8_t variant,
backend::DriverApi& driver) const noexcept;
void commitAndRender(FrameGraphResources::RenderPassInfo const& out,
PostProcessMaterial const& material,
backend::DriverApi& driver) const noexcept;
void render(FrameGraphResources::RenderPassInfo const& out,
backend::PipelineState const& pipeline,
backend::DriverApi& driver) const noexcept;
private:
FEngine& mEngine;
struct BilateralPassConfig {
uint8_t kernelSize = 11;
bool bentNormals = false;
float standardDeviation = 1.0f;
float bilateralThreshold = 0.0625f;
float scale = 1.0f;
};
FrameGraphId<FrameGraphTexture> bilateralBlurPass(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input, FrameGraphId<FrameGraphTexture> depth,
math::int2 axis, float zf, backend::TextureFormat format,
BilateralPassConfig const& config) noexcept;
FrameGraphId<FrameGraphTexture> downscalePass(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input,
FrameGraphTexture::Descriptor const& outDesc,
bool threshold, float highlight, bool fireflies) noexcept;
using MaterialRegistryMap = tsl::robin_map<
std::string_view,
PostProcessMaterial>;
MaterialRegistryMap mMaterialRegistry;
void registerPostProcessMaterial(std::string_view name, MaterialInfo const& info);
PostProcessMaterial& getPostProcessMaterial(std::string_view name) noexcept;
backend::Handle<backend::HwTexture> mStarburstTexture;
std::uniform_real_distribution<float> mUniformDistribution{0.0f, 1.0f};
template<size_t SIZE>
struct JitterSequence {
auto operator()(size_t i) const noexcept { return positions[i % SIZE] - 0.5f; }
const math::float2 positions[SIZE];
};
static const JitterSequence<4> sRGSS4;
static const JitterSequence<4> sUniformHelix4;
static const JitterSequence<16> sHaltonSamples;
static const math::float2 sHaltonSamples[16];
math::float2 const* mHaltonSamples = sHaltonSamples;
bool mWorkaroundSplitEasu : 1;
bool mWorkaroundAllowReadOnlyAncillaryFeedbackLoop : 1;
+14 -18
View File
@@ -89,7 +89,7 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
data.color = builder.createTexture("Color Buffer", colorBufferDesc);
}
const bool canAutoResolveDepth = engine.getDriverApi().isAutoDepthResolveSupported();
const bool canResolveDepth = engine.getDriverApi().isAutoDepthResolveSupported();
if (!data.depth) {
// clear newly allocated depth/stencil buffers, regardless of given clear flags
@@ -114,17 +114,13 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
data.depth = builder.createTexture(name, {
.width = colorBufferDesc.width,
.height = colorBufferDesc.height,
// If the color attachment requested MS, we assume this means the MS
// buffer must be kept, and for that reason we allocate the depth
// buffer with MS as well.
// On the other hand, if the color attachment was allocated without
// MS, no need to allocate the depth buffer with MS; Either it's not
// multi-sampled or it is auto-resolved.
// One complication above is that some backends don't support
// depth auto-resolve, in which case we must allocate the depth
// buffer with MS and manually resolve it (see "Resolved Depth Buffer"
// pass).
.samples = canAutoResolveDepth ? colorBufferDesc.samples : uint8_t(config.msaa),
// If the color attachment requested MS, we assume this means the MS buffer
// must be kept, and for that reason we allocate the depth buffer with MS
// as well. On the other hand, if the color attachment was allocated without
// MS, no need to allocate the depth buffer with MS, if the RT is MS,
// the tile depth buffer will be MS, but it'll be resolved to single
// sample automatically -- which is what we want.
.samples = canResolveDepth ? colorBufferDesc.samples : uint8_t(config.msaa),
.format = format,
});
if (config.enabledStencilBuffer) {
@@ -286,7 +282,7 @@ std::pair<FrameGraphId<FrameGraphTexture>, bool> RendererUtils::refractionPass(
input = RendererUtils::colorPass(fg, "Color Pass (opaque)", engine, view, {
// When rendering the opaques, we need to conserve the sample buffer,
// so create a config that specifies the sample count.
// so create config that specifies the sample count.
.width = config.physicalViewport.width,
.height = config.physicalViewport.height,
.samples = config.msaa,
@@ -316,11 +312,11 @@ std::pair<FrameGraphId<FrameGraphTexture>, bool> RendererUtils::refractionPass(
config, colorGradingConfig, pass.getExecutor(refraction, pass.end()));
if (config.msaa > 1 && !colorGradingConfig.asSubpass) {
// We need to do a resolve here because later passes (such as color grading or DoF) will
// need to sample from 'output'. However, because we have MSAA, we know we're not
// sampleable. And this is because in the SSR case, we had to use a renderbuffer to
// conserve the multi-sample buffer.
output = ppm.resolve(fg, "Resolved Color Buffer", output, { .levels = 1 });
// We need to do a resolve here because later passes (such as color grading or DoF) will need
// to sample from 'output'. However, because we have MSAA, we know we're not sampleable.
// And this is because in the SSR case, we had to use a renderbuffer to conserve the
// multi-sample buffer.
output = ppm.resolveBaseLevel(fg, "Resolved Color Buffer", output);
}
} else {
output = input;
+3 -3
View File
@@ -247,7 +247,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
// cameraInfo only valid after calling update
const CameraInfo cameraInfo{ shadowMap.getCamera(), mainCameraInfo };
const CameraInfo cameraInfo{ shadowMap.getCamera() };
auto transaction = ShadowMap::open(driver);
ShadowMap::prepareCamera(transaction, engine, cameraInfo);
@@ -844,7 +844,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateSpotShadowMaps(FEngine
FScene::LightSoa const& lightData) noexcept {
// The const_cast here is a little ugly, but conceptually lightData should be const,
// it's just that we're using it to store some temporary data. With SoA we can't have
// it's just that we're using it to store some temporary data. with SoA we can't have
// a `mutable` element, so that's a workaround.
FScene::ShadowInfo* const shadowInfo = const_cast<FScene::ShadowInfo*>(
lightData.data<FScene::SHADOW_INFO>());
@@ -855,7 +855,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateSpotShadowMaps(FEngine
shadowTechnique |= ShadowTechnique::SHADOW_MAP;
for (ShadowMap const& shadowMap : spotShadowMaps) {
const size_t lightIndex = shadowMap.getLightIndex();
// Gather the per-light (not per shadow map) information. For point lights we will
// gather the per-light (not per shadow map) information. For point lights we will
// "see" 6 shadowmaps (one per face), we must use the first face one, the shader
// knows how to find the entry for other faces (they're guaranteed to be sequential).
if (shadowMap.getFace() == 0) {
+16 -14
View File
@@ -265,22 +265,24 @@ uint8_t FCamera::getStereoscopicEyeCount() const noexcept {
// ------------------------------------------------------------------------------------------------
CameraInfo::CameraInfo(FCamera const& camera) noexcept
: CameraInfo(camera, {}, camera.getModelMatrix()) {
CameraInfo::CameraInfo(FCamera const& camera) noexcept {
for (int i = 0; i < camera.getStereoscopicEyeCount(); i++) {
eyeProjection[i] = mat4f{ camera.getProjectionMatrix(i) };
}
cullingProjection = mat4f{ camera.getCullingProjectionMatrix() };
model = mat4f{ camera.getModelMatrix() };
view = mat4f{ camera.getViewMatrix() };
zn = (float)camera.getNear();
zf = (float)camera.getCullingFar();
ev100 = Exposure::ev100(camera);
f = (float)camera.getFocalLength();
A = f / camera.getAperture();
d = std::max(zn, camera.getFocusDistance());
}
CameraInfo::CameraInfo(FCamera const& camera, math::mat4 const& inWorldTransform) noexcept
: CameraInfo(camera, inWorldTransform, inWorldTransform * camera.getModelMatrix()) {
}
CameraInfo::CameraInfo(FCamera const& camera, CameraInfo const& mainCameraInfo) noexcept
: CameraInfo(camera, mainCameraInfo.worldTransform, camera.getModelMatrix()) {
}
CameraInfo::CameraInfo(FCamera const& camera,
math::mat4 const& inWorldTransform,
math::mat4 const& modelMatrix) noexcept {
for (size_t i = 0; i < camera.getStereoscopicEyeCount(); i++) {
CameraInfo::CameraInfo(FCamera const& camera, math::mat4 const& inWorldTransform) noexcept {
const mat4 modelMatrix{ inWorldTransform * camera.getModelMatrix() };
for (int i = 0; i < camera.getStereoscopicEyeCount(); i++) {
eyeProjection[i] = mat4f{ camera.getProjectionMatrix(i) };
eyeFromView[i] = mat4f{ camera.getEyeFromViewMatrix(i) };
}
+1 -16
View File
@@ -220,18 +220,8 @@ private:
struct CameraInfo {
CameraInfo() noexcept {}
// Creates a CameraInfo relative to inWorldTransform (i.e. it's model matrix is
// transformed by inWorldTransform and inWorldTransform is recorded).
// This is typically used for the color pass camera.
CameraInfo(FCamera const& camera, math::mat4 const& inWorldTransform) noexcept;
// Creates a CameraInfo from a camera that is relative to mainCameraInfo.
// This is typically used for the shadow pass cameras.
CameraInfo(FCamera const& camera, CameraInfo const& mainCameraInfo) noexcept;
// Creates a CameraInfo from the FCamera
explicit CameraInfo(FCamera const& camera) noexcept;
CameraInfo(FCamera const& camera, math::mat4 const& inWorldTransform) noexcept;
union {
// projection matrix for drawing (infinite zfar)
@@ -259,11 +249,6 @@ struct CameraInfo {
math::float3 const& getPosition() const noexcept { return model[3].xyz; }
math::float3 getForwardVector() const noexcept { return normalize(-model[2].xyz); }
math::mat4 getUserViewMatrix() const noexcept { return view * worldTransform; }
private:
CameraInfo(FCamera const& camera,
math::mat4 const& inWorldTransform,
math::mat4 const& modelMatrix) noexcept;
};
FILAMENT_DOWNCAST(Camera)
+2 -12
View File
@@ -373,13 +373,8 @@ void FEngine::init() {
mDebugRegistry.registerProperty("d.shadowmap.debug_directional_shadowmap",
&debug.shadowmap.debug_directional_shadowmap, [this]() {
mMaterials.forEach([this](FMaterial* material) {
mMaterials.forEach([](FMaterial* material) {
if (material->getMaterialDomain() == MaterialDomain::SURFACE) {
material->setConstant(
+ReservedSpecializationConstants::CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP,
debug.shadowmap.debug_directional_shadowmap);
material->invalidate(
Variant::DIR | Variant::SRE | Variant::DEP,
Variant::DIR | Variant::SRE);
@@ -389,13 +384,8 @@ void FEngine::init() {
mDebugRegistry.registerProperty("d.lighting.debug_froxel_visualization",
&debug.lighting.debug_froxel_visualization, [this]() {
mMaterials.forEach([this](FMaterial* material) {
mMaterials.forEach([](FMaterial* material) {
if (material->getMaterialDomain() == MaterialDomain::SURFACE) {
material->setConstant(
+ReservedSpecializationConstants::CONFIG_DEBUG_FROXEL_VISUALIZATION,
debug.lighting.debug_froxel_visualization);
material->invalidate(
Variant::DYN | Variant::DEP,
Variant::DYN);
+54 -117
View File
@@ -79,10 +79,7 @@ struct Material::BuilderDetails {
size_t mSize = 0;
MaterialParser* mMaterialParser = nullptr;
bool mDefaultMaterial = false;
std::unordered_map<
utils::CString,
std::variant<int32_t, float, bool>,
CString::Hasher> mConstantSpecializations;
std::unordered_map<std::string, std::variant<int32_t, float, bool>> mConstantSpecializations;
};
FMaterial::DefaultMaterialBuilder::DefaultMaterialBuilder() : Material::Builder() {
@@ -219,14 +216,9 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
mSubpassInfo.isValid = false;
}
utils::FixedCapacityVector<MaterialConstant> constants;
// Older materials won't have a constants chunk, but that's okay.
parser->getConstants(&mMaterialConstants);
for (size_t i = 0, c = mMaterialConstants.size(); i < c; i++) {
auto& item = mMaterialConstants[i];
// the key can be a string_view because mMaterialConstant owns the CString
std::string_view const key{ item.name.data(), item.name.size() };
mSpecializationConstantsNameToIndex[key] = i;
}
parser->getConstants(&constants);
// Verify that all the constant specializations exist in the material and that their types match.
// The first specialization constants are defined internally by Filament.
@@ -246,7 +238,7 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
bool const powerVrShaderWorkarounds =
engine.getDriverApi().isWorkaroundNeeded(Workaround::POWER_VR_SHADER_WORKAROUNDS);
mSpecializationConstants.reserve(mMaterialConstants.size() + CONFIG_MAX_RESERVED_SPEC_CONSTANTS);
mSpecializationConstants.reserve(constants.size() + CONFIG_MAX_RESERVED_SPEC_CONSTANTS);
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::BACKEND_FEATURE_LEVEL,
(int)engine.getSupportedFeatureLevel() });
@@ -258,16 +250,16 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
(int)maxFroxelBufferHeight });
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP,
engine.debug.shadowmap.debug_directional_shadowmap });
(bool)engine.debug.shadowmap.debug_directional_shadowmap });
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_DEBUG_FROXEL_VISUALIZATION,
engine.debug.lighting.debug_froxel_visualization });
(bool)engine.debug.lighting.debug_froxel_visualization });
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_STATIC_TEXTURE_TARGET_WORKAROUND,
staticTextureWorkaround });
(bool)staticTextureWorkaround });
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_POWER_VR_SHADER_WORKAROUNDS,
powerVrShaderWorkarounds });
(bool)powerVrShaderWorkarounds });
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT,
(int)engine.getConfig().stereoscopicEyeCount });
@@ -278,18 +270,19 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
false});
}
for (auto const& [name, value] : builder->mConstantSpecializations) {
std::string_view const key{ name.data(), name.size() };
auto pos = mSpecializationConstantsNameToIndex.find(key);
ASSERT_PRECONDITION(pos != mSpecializationConstantsNameToIndex.end(),
for (const auto& [name, value] : builder->mConstantSpecializations) {
auto found = std::find_if(
constants.begin(), constants.end(), [name = name](const auto& constant) {
return strncmp(constant.name.data(), name.data(), name.length()) == 0;
});
ASSERT_PRECONDITION(found != constants.end(),
"The material %s does not have a constant parameter named %s.",
mName.c_str_safe(), name.c_str());
const char* const types[3] = {"an int", "a float", "a bool"};
const char* const errorMessage =
"The constant parameter %s on material %s is of type %s, but %s was "
"provided.";
auto& constant = mMaterialConstants[pos->second];
switch (constant.type) {
switch (found->type) {
case ConstantType::INT:
ASSERT_PRECONDITION(std::holds_alternative<int32_t>(value), errorMessage,
name.c_str(), mName.c_str_safe(), "int", types[value.index()]);
@@ -303,7 +296,8 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
name.c_str(), mName.c_str_safe(), "bool", types[value.index()]);
break;
}
uint32_t const index = pos->second + CONFIG_MAX_RESERVED_SPEC_CONSTANTS;
uint32_t const index =
std::distance(constants.begin(), found) + CONFIG_MAX_RESERVED_SPEC_CONSTANTS;
mSpecializationConstants.push_back({ index, value });
}
@@ -411,7 +405,6 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
mIsDefaultMaterial = builder->mDefaultMaterial;
if (UTILS_UNLIKELY(mIsDefaultMaterial)) {
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
filaflat::MaterialChunk const& materialChunk{ mMaterialParser->getMaterialChunk() };
auto variants = FixedCapacityVector<Variant>::with_capacity(materialChunk.getShaderCount());
materialChunk.visitShaders([&variants](
@@ -427,14 +420,12 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
std::swap(mDepthVariants, variants);
}
if (mMaterialDomain == MaterialDomain::SURFACE) {
if (UTILS_UNLIKELY(!mIsDefaultMaterial && !mHasCustomDepthShader)) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
auto& cachedPrograms = mCachedPrograms;
for (Variant const variant: pDefaultMaterial->mDepthVariants) {
pDefaultMaterial->prepareProgram(variant);
cachedPrograms[variant.key] = pDefaultMaterial->getProgram(variant);
}
if (UTILS_UNLIKELY(!mIsDefaultMaterial && !mHasCustomDepthShader)) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
auto& cachedPrograms = mCachedPrograms;
for (Variant const variant : pDefaultMaterial->mDepthVariants) {
pDefaultMaterial->prepareProgram(variant);
cachedPrograms[variant.key] = pDefaultMaterial->getProgram(variant);
}
}
@@ -468,47 +459,44 @@ FMaterial::~FMaterial() noexcept {
}
void FMaterial::invalidate(Variant::type_t variantMask, Variant::type_t variantValue) noexcept {
if (mMaterialDomain == MaterialDomain::SURFACE) {
DriverApi& driverApi = mEngine.getDriverApi();
auto& cachedPrograms = mCachedPrograms;
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
Variant const variant(k);
if ((k & variantMask) == variantValue) {
if (UTILS_LIKELY(!mIsDefaultMaterial)) {
// The depth variants may be shared with the default material, in which case
// we should not free it now.
bool const isSharedVariant =
Variant::isValidDepthVariant(variant) && !mHasCustomDepthShader;
if (isSharedVariant) {
// we don't own this variant, skip.
continue;
}
}
driverApi.destroyProgram(cachedPrograms[k]);
cachedPrograms[k].clear();
}
// update the spec constants that can change
// TODO: should we just always update all of them?
for (auto& item : mSpecializationConstants) {
if (item.id == ReservedSpecializationConstants::CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP) {
item.value = mEngine.debug.shadowmap.debug_directional_shadowmap;
} else if (item.id == ReservedSpecializationConstants::CONFIG_DEBUG_FROXEL_VISUALIZATION) {
item.value = mEngine.debug.lighting.debug_froxel_visualization;
}
}
if (UTILS_UNLIKELY(!mIsDefaultMaterial && !mHasCustomDepthShader)) {
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
for (Variant const variant: pDefaultMaterial->mDepthVariants) {
pDefaultMaterial->prepareProgram(variant);
if (!cachedPrograms[variant.key]) {
cachedPrograms[variant.key] = pDefaultMaterial->getProgram(variant);
DriverApi& driverApi = mEngine.getDriverApi();
auto& cachedPrograms = mCachedPrograms;
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
Variant const variant(k);
if ((k & variantMask) == variantValue) {
if (UTILS_LIKELY(!mIsDefaultMaterial)) {
// The depth variants may be shared with the default material, in which case
// we should not free it now.
bool const isSharedVariant =
Variant::isValidDepthVariant(variant) && !mHasCustomDepthShader;
if (isSharedVariant) {
// we don't own this variant, skip.
continue;
}
}
driverApi.destroyProgram(cachedPrograms[k]);
cachedPrograms[k].clear();
}
} else if (mMaterialDomain == MaterialDomain::POST_PROCESS) {
DriverApi& driverApi = mEngine.getDriverApi();
auto& cachedPrograms = mCachedPrograms;
for (size_t k = 0, n = POST_PROCESS_VARIANT_COUNT; k < n; ++k) {
if ((k & variantMask) == variantValue) {
driverApi.destroyProgram(cachedPrograms[k]);
cachedPrograms[k].clear();
}
if (UTILS_UNLIKELY(!mIsDefaultMaterial && !mHasCustomDepthShader)) {
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
for (Variant const variant: pDefaultMaterial->mDepthVariants) {
pDefaultMaterial->prepareProgram(variant);
if (!cachedPrograms[variant.key]) {
cachedPrograms[variant.key] = pDefaultMaterial->getProgram(variant);
}
}
} else if (mMaterialDomain == MaterialDomain::COMPUTE) {
// TODO: handle compute variants if any
}
}
@@ -837,55 +825,4 @@ void FMaterial::destroyPrograms(FEngine& engine) {
}
}
std::optional<uint32_t> FMaterial::getSpecializationConstantId(std::string_view name) const noexcept {
auto pos = mSpecializationConstantsNameToIndex.find(name);
if (pos != mSpecializationConstantsNameToIndex.end()) {
return pos->second + CONFIG_MAX_RESERVED_SPEC_CONSTANTS;
}
return std::nullopt;
}
template<typename T, typename>
bool FMaterial::setConstant(uint32_t id, T value) noexcept {
size_t const maxId = mMaterialConstants.size() + CONFIG_MAX_RESERVED_SPEC_CONSTANTS;
if (UTILS_LIKELY(id < maxId)) {
if (id >= CONFIG_MAX_RESERVED_SPEC_CONSTANTS) {
// Constant from the material itself (as opposed to the reserved ones)
auto& constant = mMaterialConstants[id - CONFIG_MAX_RESERVED_SPEC_CONSTANTS];
using ConstantType = backend::ConstantType;
switch (constant.type) {
case ConstantType::INT:
if (!std::is_same_v<T, int32_t>) return false;
break;
case ConstantType::FLOAT:
if (!std::is_same_v<T, float>) return false;
break;
case ConstantType::BOOL:
if (!std::is_same_v<T, bool>) return false;
break;
}
}
auto pos = std::find_if(
mSpecializationConstants.begin(), mSpecializationConstants.end(),
[id](backend::Program::SpecializationConstant const& specializationConstant) {
return specializationConstant.id == id;
});
if (pos != mSpecializationConstants.end()) {
if (std::get<T>(pos->value) != value) {
pos->value = value;
return true;
}
} else {
mSpecializationConstants.push_back({ id, value });
return true;
}
}
return false;
}
template bool FMaterial::setConstant<int32_t>(uint32_t id, int32_t value) noexcept;
template bool FMaterial::setConstant<float>(uint32_t id, float value) noexcept;
template bool FMaterial::setConstant<bool>(uint32_t id, bool value) noexcept;
} // namespace filament
-13
View File
@@ -165,14 +165,6 @@ public:
void destroyPrograms(FEngine& engine);
// return the id of a specialization constant specified by name for this material
std::optional<uint32_t> getSpecializationConstantId(std::string_view name) const noexcept ;
// Sets a specialization constant by id. call is no-op if the id is invalid.
// Return true is the value was changed.
template<typename T, typename = Builder::is_supported_constant_parameter_t<T>>
bool setConstant(uint32_t id, T value) noexcept;
#if FILAMENT_ENABLE_MATDBG
void applyPendingEdits() noexcept;
@@ -269,11 +261,6 @@ private:
SamplerGroupBindingInfoList mSamplerGroupBindingInfoList;
SamplerBindingToNameMap mSamplerBindingToNameMap;
// Constants defined by this Material
utils::FixedCapacityVector<MaterialConstant> mMaterialConstants;
// A map from the Constant name to the mMaterialConstant index
std::unordered_map<std::string_view, uint32_t> mSpecializationConstantsNameToIndex;
// current specialization constants for the HwProgram
utils::FixedCapacityVector<backend::Program::SpecializationConstant> mSpecializationConstants;
#if FILAMENT_ENABLE_MATDBG
+1 -1
View File
@@ -117,7 +117,7 @@ void FMaterialInstance::initDefaultInstance(FEngine& engine, FMaterial const* ma
if (!material->getSamplerInterfaceBlock().isEmpty()) {
mSamplers = SamplerGroup(material->getSamplerInterfaceBlock().getSize());
mSbHandle = driver.createSamplerGroup(
mSamplers.getSize(), utils::FixedSizeString<32>(mMaterial->getName().c_str_safe()));
mSamplers.getSize(), utils::FixedSizeString<32>("Default material"));
}
const RasterState& rasterState = material->getRasterState();
+21 -52
View File
@@ -365,19 +365,19 @@ void FRenderer::copyFrame(FSwapChain* dstSwapChain, filament::Viewport const& ds
params.viewport.bottom = 0;
params.viewport.width = std::numeric_limits<uint32_t>::max();
params.viewport.height = std::numeric_limits<uint32_t>::max();
driver.beginRenderPass(mRenderTargetHandle, params);
driver.endRenderPass();
}
driver.beginRenderPass(mRenderTargetHandle, params);
// Verify that the source swap chain is readable.
assert_invariant(mSwapChain->isReadable());
driver.blitDEPRECATED(TargetBufferFlags::COLOR, mRenderTargetHandle,
dstViewport, mRenderTargetHandle, srcViewport, SamplerMagFilter::LINEAR);
driver.blit(TargetBufferFlags::COLOR,
mRenderTargetHandle, dstViewport, mRenderTargetHandle, srcViewport, SamplerMagFilter::LINEAR);
if (flags & SET_PRESENTATION_TIME) {
// TODO: Implement this properly, see https://github.com/google/filament/issues/633
}
driver.endRenderPass();
if (flags & COMMIT) {
dstSwapChain->commit(driver);
}
@@ -491,19 +491,6 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
hasDithering = false;
hasFXAA = false;
scale = 1.0f;
} else {
// This configures post-process materials by setting constant parameters
if (taaOptions.enabled) {
ppm.configureTemporalAntiAliasingMaterial(taaOptions);
if (taaOptions.upscaling) {
// for now TAA upscaling is incompatible with regular dsr
dsrOptions.enabled = false;
// also, upscaling doesn't work well with quater-resolution SSAO
aoOptions.resolution = 1.0;
// Currently we only support a fixed TAA upscaling ratio
scale = 0.5f;
}
}
}
const bool blendModeTranslucent = view.getBlendMode() == BlendMode::TRANSLUCENT;
@@ -533,7 +520,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
};
// whether we're scaled at all
bool scaled = any(notEqual(scale, float2(1.0f)));
const bool scaled = any(notEqual(scale, float2(1.0f)));
// vp is the user defined viewport within the View
filament::Viewport const& vp = view.getViewport();
@@ -622,7 +609,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
view.prepare(engine, driver, arena, svp, cameraInfo, getShaderUserTime(), needsAlphaChannel);
view.prepareUpscaler(scale, taaOptions, dsrOptions);
view.prepareUpscaler(scale);
/*
* Allocate command buffer
@@ -826,14 +813,14 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
[=, &view](FrameGraphResources const& resources,
auto const&, DriverApi& driver) mutable {
auto out = resources.getRenderPassInfo();
view.executePickingQueries(driver, out.target, scale * aoOptions.resolution);
view.executePickingQueries(driver, out.target, aoOptions.resolution);
});
}
// Store this frame's camera projection in the frame history.
if (UTILS_UNLIKELY(taaOptions.enabled)) {
// Apply the TAA jitter to everything after the structure pass, starting with the color pass.
ppm.prepareTaa(fg, svp, taaOptions, view.getFrameHistory(), &FrameHistoryEntry::taa,
ppm.prepareTaa(fg, svp, view.getFrameHistory(), &FrameHistoryEntry::taa,
&cameraInfo, view.getPerViewUniforms());
}
@@ -997,12 +984,10 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
view.commitUniforms(driver);
});
// Resolve depth -- which might be needed because of TAA or DoF. This pass will be culled
// if the depth is not used below or if the depth is not MS (e.g. it could have been
// auto-resolved).
// In practice, this is used on Vulkan and older Metal devices.
auto depth = blackboard.get<FrameGraphTexture>("depth");
depth = ppm.resolve(fg, "Resolved Depth Buffer", depth, { .levels = 1 });
// resolve depth -- which might be needed because of TAA or DoF. This pass will be culled
// if the depth is not used below.
auto const depth = ppm.resolveBaseLevel(fg, "Resolved Depth Buffer",
blackboard.get<FrameGraphTexture>("depth"));
// Debug: CSM visualisation
if (UTILS_UNLIKELY(engine.debug.shadowmap.visualize_cascades &&
@@ -1019,15 +1004,6 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
if (taaOptions.enabled) {
input = ppm.taa(fg, input, depth, view.getFrameHistory(), &FrameHistoryEntry::taa,
taaOptions, colorGradingConfig);
if (taaOptions.upscaling) {
scale = 1.0f;
scaled = false;
UTILS_UNUSED_IN_RELEASE auto const& inputDesc = fg.getDescriptor(input);
svp.width = inputDesc.width;
svp.height = inputDesc.height;
xvp.width *= 2;
xvp.height *= 2;
}
}
// --------------------------------------------------------------------------------------------
@@ -1043,21 +1019,16 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
// The bokeh height is always correct regardless of the dynamic resolution scaling.
// (because the CoC is calculated w.r.t. the height), so we only need to adjust
// the width.
float const aspect = (scale.x / scale.y) * dofOptions.cocAspectRatio;
float2 const bokehScale{
aspect < 1.0f ? aspect : 1.0f,
aspect > 1.0f ? 1.0f / aspect : 1.0f
};
float const bokehAspectRatio = scale.x / scale.y;
input = ppm.dof(fg, input, depth, cameraInfo, needsAlphaChannel,
bokehScale, dofOptions);
bokehAspectRatio, dofOptions);
}
FrameGraphId<FrameGraphTexture> bloom, flare;
if (bloomOptions.enabled) {
// Generate the bloom buffer, which is stored in the blackboard as "bloom". This is
// generate the bloom buffer, which is stored in the blackboard as "bloom". This is
// consumed by the colorGrading pass and will be culled if colorGrading is disabled.
auto [bloom_, flare_] = ppm.bloom(fg, input, TextureFormat::R11F_G11F_B10F,
bloomOptions, taaOptions, scale);
auto [bloom_, flare_] = ppm.bloom(fg, input, bloomOptions, TextureFormat::R11F_G11F_B10F, scale);
bloom = bloom_;
flare = flare_;
}
@@ -1086,7 +1057,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
auto viewport = DEBUG_DYNAMIC_SCALING ? xvp : vp;
input = ppm.upscale(fg, needsAlphaChannel, dsrOptions, input, xvp, {
.width = viewport.width, .height = viewport.height,
.format = colorGradingConfig.ldrFormat }, SamplerMagFilter::LINEAR);
.format = colorGradingConfig.ldrFormat });
xvp.left = xvp.bottom = 0;
svp = xvp;
}
@@ -1109,8 +1080,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
// TODO: in that specific scenario it would be better to just not use xvp
// The intermediate buffer is accomplished with a "fake" opaqueBlit (i.e. blit) operation.
const bool outputIsSwapChain =
(input == colorPassOutput) && (viewRenderTarget == mRenderTargetHandle);
const bool outputIsSwapChain = (input == colorPassOutput) && (viewRenderTarget == mRenderTargetHandle);
if (mightNeedFinalBlit) {
if (blendModeTranslucent ||
xvp != svp ||
@@ -1121,9 +1091,8 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
ssReflectionsOptions.enabled))) {
assert_invariant(!scaled);
input = ppm.blit(fg, blendModeTranslucent, input, xvp, {
.width = vp.width, .height = vp.height,
.format = colorGradingConfig.ldrFormat },
SamplerMagFilter::NEAREST, SamplerMinFilter::NEAREST);
.width = vp.width, .height = vp.height,
.format = colorGradingConfig.ldrFormat }, SamplerMagFilter::NEAREST);
}
}
+86 -37
View File
@@ -58,7 +58,7 @@ struct Texture::BuilderDetails {
uint8_t mLevels = 1;
Sampler mTarget = Sampler::SAMPLER_2D;
InternalFormat mFormat = InternalFormat::RGBA8;
Usage mUsage = Usage::NONE;
Usage mUsage = Usage::DEFAULT;
bool mTextureIsSwizzled = false;
std::array<Swizzle, 4> mSwizzle = {
Swizzle::CHANNEL_0, Swizzle::CHANNEL_1,
@@ -125,36 +125,6 @@ Texture* Texture::Builder::build(Engine& engine) {
ASSERT_PRECONDITION(Texture::isTextureFormatSupported(engine, mImpl->mFormat),
"Texture format %u not supported on this platform", mImpl->mFormat);
uint8_t maxLevelCount;
switch (mImpl->mTarget) {
case SamplerType::SAMPLER_2D:
case SamplerType::SAMPLER_2D_ARRAY:
case SamplerType::SAMPLER_CUBEMAP:
case SamplerType::SAMPLER_EXTERNAL:
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
maxLevelCount = FTexture::maxLevelCount(mImpl->mWidth, mImpl->mHeight);
break;
case SamplerType::SAMPLER_3D:
maxLevelCount = FTexture::maxLevelCount(std::max(
{ mImpl->mWidth, mImpl->mHeight, mImpl->mDepth }));
break;
}
mImpl->mLevels = std::min(mImpl->mLevels, maxLevelCount);
if (mImpl->mUsage == TextureUsage::NONE) {
mImpl->mUsage = TextureUsage::DEFAULT;
if (mImpl->mLevels > 1 &&
(mImpl->mWidth > 1 || mImpl->mHeight > 1) &&
mImpl->mTarget != SamplerType::SAMPLER_EXTERNAL) {
const bool formatMipmappable =
downcast(engine).getDriverApi().isTextureFormatMipmappable(mImpl->mFormat);
if (formatMipmappable) {
// by default mipmappable textures have the BLIT usage bits set
mImpl->mUsage |= TextureUsage::BLIT_SRC | TextureUsage::BLIT_DST;
}
}
}
const bool sampleable = bool(mImpl->mUsage & TextureUsage::SAMPLEABLE);
const bool swizzled = mImpl->mTextureIsSwizzled;
const bool imported = mImpl->mImportedId;
@@ -193,15 +163,30 @@ Texture* Texture::Builder::build(Engine& engine) {
// ------------------------------------------------------------------------------------------------
FTexture::FTexture(FEngine& engine, const Builder& builder) {
FEngine::DriverApi& driver = engine.getDriverApi();
mWidth = static_cast<uint32_t>(builder->mWidth);
mHeight = static_cast<uint32_t>(builder->mHeight);
mDepth = static_cast<uint32_t>(builder->mDepth);
mFormat = builder->mFormat;
mUsage = builder->mUsage;
mTarget = builder->mTarget;
mLevelCount = builder->mLevels;
uint8_t maxLevelCount;
switch (builder->mTarget) {
case SamplerType::SAMPLER_2D:
case SamplerType::SAMPLER_2D_ARRAY:
case SamplerType::SAMPLER_CUBEMAP:
case SamplerType::SAMPLER_EXTERNAL:
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
maxLevelCount = FTexture::maxLevelCount(mWidth, mHeight);
break;
case SamplerType::SAMPLER_3D:
maxLevelCount = FTexture::maxLevelCount(std::max(mWidth, std::max(mHeight, mDepth)));
break;
}
mLevelCount = std::min(builder->mLevels, maxLevelCount);
FEngine::DriverApi& driver = engine.getDriverApi();
if (UTILS_LIKELY(builder->mImportedId == 0)) {
if (UTILS_LIKELY(!builder->mTextureIsSwizzled)) {
mHandle = driver.createTexture(
@@ -406,9 +391,6 @@ void FTexture::generateMipmaps(FEngine& engine) const noexcept {
ASSERT_PRECONDITION(mTarget != SamplerType::SAMPLER_EXTERNAL,
"External Textures are not mipmappable.");
ASSERT_PRECONDITION(mTarget != SamplerType::SAMPLER_3D,
"3D Textures are not mipmappable.");
const bool formatMipmappable = engine.getDriverApi().isTextureFormatMipmappable(mFormat);
ASSERT_PRECONDITION(formatMipmappable,
"Texture format %u is not mipmappable.", (unsigned)mFormat);
@@ -417,7 +399,74 @@ void FTexture::generateMipmaps(FEngine& engine) const noexcept {
return;
}
engine.getDriverApi().generateMipmaps(mHandle);
if (engine.getDriverApi().canGenerateMipmaps()) {
engine.getDriverApi().generateMipmaps(mHandle);
return;
}
auto generateMipsForLayer = [this, &engine](TargetBufferInfo proto) {
FEngine::DriverApi& driver = engine.getDriverApi();
// Wrap miplevel 0 in a render target so that we can use it as a blit source.
uint8_t level = 0;
uint32_t srcw = mWidth;
uint32_t srch = mHeight;
proto.handle = mHandle;
proto.level = level++;
backend::Handle<backend::HwRenderTarget> srcrth = driver.createRenderTarget(
TargetBufferFlags::COLOR, srcw, srch, mSampleCount, proto, {}, {});
// Perform a blit for all miplevels down to 1x1.
backend::Handle<backend::HwRenderTarget> dstrth;
do {
uint32_t const dstw = std::max(srcw >> 1u, 1u);
uint32_t const dsth = std::max(srch >> 1u, 1u);
proto.level = level++;
dstrth = driver.createRenderTarget(
TargetBufferFlags::COLOR, dstw, dsth, mSampleCount, proto, {}, {});
driver.blit(TargetBufferFlags::COLOR,
dstrth, { 0, 0, dstw, dsth },
srcrth, { 0, 0, srcw, srch },
SamplerMagFilter::LINEAR);
driver.destroyRenderTarget(srcrth);
srcrth = dstrth;
srcw = dstw;
srch = dsth;
} while ((srcw > 1 || srch > 1) && level < mLevelCount);
driver.destroyRenderTarget(dstrth);
};
switch (mTarget) {
case SamplerType::SAMPLER_2D:
generateMipsForLayer({});
break;
case SamplerType::SAMPLER_2D_ARRAY:
UTILS_NOUNROLL
for (uint16_t layer = 0, c = mDepth; layer < c; ++layer) {
generateMipsForLayer({ .layer = layer });
}
break;
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
UTILS_NOUNROLL
for (uint16_t layer = 0, c = mDepth * 6; layer < c; ++layer) {
generateMipsForLayer({ .layer = layer });
}
break;
case SamplerType::SAMPLER_CUBEMAP:
UTILS_NOUNROLL
for (uint8_t face = 0; face < 6; ++face) {
generateMipsForLayer({ .layer = face });
}
break;
case SamplerType::SAMPLER_EXTERNAL:
// not mipmapable
break;
case SamplerType::SAMPLER_3D:
// TODO: handle SAMPLER_3D -- this can't be done with a 2D blit, this would require
// a fragment shader
slog.w << "Texture::generateMipmap does not support SAMPLER_3D yet on this h/w." << io::endl;
break;
}
}
bool FTexture::isTextureFormatSupported(FEngine& engine, InternalFormat format) noexcept {
+7 -22
View File
@@ -313,10 +313,6 @@ void FView::prepareShadowing(FEngine& engine, FScene::RenderableSoa& renderableD
}
if (UTILS_LIKELY(!lcm.isShadowCaster(li))) {
// Because we early exit here, we need to make sure we mark the light as non-casting.
// See `ShadowMapManager::updateSpotShadowMaps` for const_cast<> justification.
const_cast<FScene::ShadowInfo&>(
lightData.elementAt<FScene::SHADOW_INFO>(l)).castsShadows = false;
continue; // doesn't cast shadows
}
@@ -725,22 +721,11 @@ UTILS_NOINLINE
});
}
void FView::prepareUpscaler(float2 scale,
TemporalAntiAliasingOptions const& taaOptions,
DynamicResolutionOptions const& dsrOptions) const noexcept {
void FView::prepareUpscaler(float2 scale) const noexcept {
SYSTRACE_CALL();
float bias = 0.0f;
float2 derivativesScale{ 1.0f };
if (dsrOptions.enabled && dsrOptions.quality >= QualityLevel::HIGH) {
bias = std::log2(std::min(scale.x, scale.y));
}
if (taaOptions.enabled) {
bias += taaOptions.lodBias;
if (taaOptions.upscaling) {
derivativesScale = 0.5f;
}
}
mPerViewUniforms.prepareLodBias(bias, derivativesScale);
const float bias = (mDynamicResolution.quality >= QualityLevel::HIGH) ?
std::log2(std::min(scale.x, scale.y)) : 0.0f;
mPerViewUniforms.prepareLodBias(bias);
}
void FView::prepareCamera(FEngine& engine, const CameraInfo& cameraInfo) const noexcept {
@@ -996,15 +981,15 @@ void FView::drainFrameHistory(FEngine& engine) noexcept {
}
void FView::executePickingQueries(backend::DriverApi& driver,
backend::RenderTargetHandle handle, float2 scale) noexcept {
backend::RenderTargetHandle handle, float scale) noexcept {
while (mActivePickingQueriesList) {
FPickingQuery* const pQuery = mActivePickingQueriesList;
mActivePickingQueriesList = pQuery->next;
// adjust for dynamic resolution and structure buffer scale
const uint32_t x = uint32_t(float(pQuery->x) * scale.x);
const uint32_t y = uint32_t(float(pQuery->y) * scale.y);
const uint32_t x = uint32_t(float(pQuery->x) * (scale * mScale.x));
const uint32_t y = uint32_t(float(pQuery->y) * (scale * mScale.y));
if (UTILS_UNLIKELY(driver.getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0)) {
driver.readPixels(handle, x, y, 1, 1, {
+2 -4
View File
@@ -133,9 +133,7 @@ public:
return mName.c_str_safe();
}
void prepareUpscaler(math::float2 scale,
TemporalAntiAliasingOptions const& taaOptions,
DynamicResolutionOptions const& dsrOptions) const noexcept;
void prepareUpscaler(math::float2 scale) const noexcept;
void prepareCamera(FEngine& engine, const CameraInfo& cameraInfo) const noexcept;
void prepareViewport(
@@ -419,7 +417,7 @@ public:
View::PickingQueryResultCallback callback) noexcept;
void executePickingQueries(backend::DriverApi& driver,
backend::RenderTargetHandle handle, math::float2 scale) noexcept;
backend::RenderTargetHandle handle, float scale) noexcept;
void setMaterialGlobal(uint32_t index, math::float4 const& value);
+1 -1
View File
@@ -204,7 +204,7 @@ void FrameGraph::execute(backend::DriverApi& driver) noexcept {
}
// call execute
FrameGraphResources const resources(*this, *node);
FrameGraphResources resources(*this, *node);
node->execute(resources, driver);
// destroy concrete resources
-5
View File
@@ -229,11 +229,6 @@ void RenderPassNode::resolve() noexcept {
rt.descriptor.samples = pImportedRenderTarget->importedDesc.samples;
rt.backend.target = pImportedRenderTarget->target;
// We could end-up here more than once, for instance if the rendertarget is used
// by multiple passes (this would imply a read-back, btw). In this case, we don't want
// to clear it the 2nd time, so we clear the imported pass's clear flags.
pImportedRenderTarget->importedDesc.clearFlags = TargetBufferFlags::NONE;
// but don't discard attachments the imported target tells us to keep
rt.backend.params.flags.discardStart &= ~pImportedRenderTarget->importedDesc.keepOverrideStart;
rt.backend.params.flags.discardEnd &= ~pImportedRenderTarget->importedDesc.keepOverrideEnd;
+132 -170
View File
@@ -24,57 +24,10 @@ material {
precision: high
},
{
type : float2,
name : jitter,
precision: high
},
{
type : float4[9],
type : float[9],
name : filterWeights
}
],
constants : [
{
type : bool,
name : historyReprojection,
default : true
},
{
type : bool,
name : filterHistory,
default : true
},
{
type : bool,
name : filterInput,
default : true
},
{
type : int,
name : boxClipping,
default : 0
},
{
type : int,
name : boxType,
default : 1
},
{
type : bool,
name : useYCoCg,
default : false
},
{
type : bool,
name : preventFlickering,
default : false
},
{
type : float,
name : varianceGamma,
default : 1.0
}
],
variables : [
vertex
],
@@ -91,6 +44,14 @@ vertex {
fragment {
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
#define TEXTURE_SPACE_UP -1
#define TEXTURE_SPACE_DN 1
#else
#define TEXTURE_SPACE_UP 1
#define TEXTURE_SPACE_DN -1
#endif
/* Clipping box type */
// min/max neighborhood
@@ -100,6 +61,9 @@ fragment {
// uses both min/max and variance
#define BOX_TYPE_AABB_VARIANCE 2
// High VARIANCE_GAMMA [0.75, 1.25] increases ghosting artefact, lower values increases jittering
#define VARIANCE_GAMMA 1.0
/* Clipping algorithm */
// accurate box clipping
@@ -109,12 +73,34 @@ fragment {
// no clipping (for debugging only)
#define BOX_CLIPPING_NONE 2
/* Configuration mobile/desktop */
#if FILAMENT_QUALITY < FILAMENT_QUALITY_HIGH
#define BOX_CLIPPING BOX_CLIPPING_ACCURATE
#define BOX_TYPE BOX_TYPE_VARIANCE
#define USE_YCoCg 0
#define FILTER_INPUT 1
#define FILTER_HISTORY 0
#else
#define BOX_CLIPPING BOX_CLIPPING_ACCURATE
#define BOX_TYPE BOX_TYPE_AABB_VARIANCE
#define USE_YCoCg 1
#define FILTER_INPUT 1
#define FILTER_HISTORY 1
#endif
/* debugging helper */
#define HISTORY_REPROJECTION 1
#define PREVENT_FLICKERING 0 // FIXME: thin lines disapear
float luma(const vec3 color) {
if (materialConstants_useYCoCg) {
return color.x;
} else {
return luminance(color);
}
#if USE_YCoCg
return color.x;
#else
return luminance(color);
#endif
}
vec3 RGB_YCoCg(const vec3 c) {
@@ -208,136 +194,108 @@ vec4 sampleTextureCatmullRom(const sampler2D tex, const highp vec2 uv, const hig
result *= 1.0 / (k0 + k1 + k2 + k3 + k4);
// we could end-up with negative values
result = max(vec4(0), result);
return result;
}
void postProcess(inout PostProcessInputs postProcess) {
highp vec4 uv = variable_vertex.xyxy; // interpolated to pixel center
if (materialConstants_historyReprojection) {
// read the depth buffer center sample for reprojection
highp float depth = textureLod(materialParams_depth, uv.xy, 0.0).r;
// reproject history to current frame
uv.zw = uvToRenderTargetUV(uv.zw);
highp vec4 q = materialParams.reprojection * vec4(uv.zw, depth, 1.0);
uv.zw = (q.xy * (1.0 / q.w)) * 0.5 + 0.5;
uv.zw = uvToRenderTargetUV(uv.zw);
}
// read the depth buffer center sample for reprojection
float depth = textureLod(materialParams_depth, uv.xy, 0.0).r;
#if HISTORY_REPROJECTION
uv.zw = uvToRenderTargetUV(uv.zw);
// reproject history to current frame
highp vec4 q = materialParams.reprojection * vec4(uv.zw, depth, 1.0);
uv.zw = (q.xy * (1.0 / q.w)) * 0.5 + 0.5;
uv.zw = uvToRenderTargetUV(uv.zw);
#endif
// read center color and history samples
vec4 history;
if (materialConstants_filterHistory) {
history = sampleTextureCatmullRom(materialParams_history, uv.zw,
vec2(textureSize(materialParams_history, 0)));
} else {
history = textureLod(materialParams_history, uv.zw, 0.0);
}
vec4 color = textureLod(materialParams_color, uv.xy, 0.0);
#if FILTER_HISTORY
vec4 history = sampleTextureCatmullRom(materialParams_history, uv.zw,
vec2(textureSize(materialParams_history, 0)));
#else
vec4 history = textureLod(materialParams_history, uv.zw, 0.0);
#endif
if (materialConstants_useYCoCg) {
history.rgb = RGB_YCoCg(history.rgb);
}
highp vec2 size = vec2(textureSize(materialParams_color, 0));
highp vec2 p = (floor(uv.xy * size) + 0.5) / size;
vec4 color = textureLod(materialParams_color, p, 0.0);
vec3 s[9];
if (materialConstants_filterInput || materialConstants_boxClipping != BOX_CLIPPING_NONE) {
s[0] = textureLodOffset(materialParams_color, p, 0.0, ivec2(-1, -1)).rgb;
s[1] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 0, -1)).rgb;
s[2] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 1, -1)).rgb;
s[3] = textureLodOffset(materialParams_color, p, 0.0, ivec2(-1, 0)).rgb;
s[4] = color.rgb;
s[5] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 1, 0)).rgb;
s[6] = textureLodOffset(materialParams_color, p, 0.0, ivec2(-1, 1)).rgb;
s[7] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 0, 1)).rgb;
s[8] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 1, 1)).rgb;
}
if (materialConstants_useYCoCg) {
color.rgb = RGB_YCoCg(color.rgb);
if (materialConstants_filterInput || materialConstants_boxClipping != BOX_CLIPPING_NONE) {
for (int i = 0; i < 9; i++) {
s[i] = RGB_YCoCg(s[i]);
}
}
}
vec2 subPixelOffset = p - uv.xy; // +/- [0.25, 0.25]
float confidence = 0.0;
vec4 filtered = color;
if (materialConstants_filterInput) {
// unjitter/filter input
// figure out which set of coeficients to use
int jxp = subPixelOffset.y > 0.0 ? 3 : 0;
int jxn = subPixelOffset.y > 0.0 ? 2 : 1;
int j = subPixelOffset.x > 0.0 ? jxp : jxn;
filtered = vec4(0, 0, 0, color.a);
for (int i = 0; i < 9; i++) {
float w = materialParams.filterWeights[i][j];
filtered.rgb += s[i] * w;
confidence = max(confidence, w);
}
} else {
confidence = float(materialParams.jitter.x * subPixelOffset.x > 0.0 &&
materialParams.jitter.y * subPixelOffset.y > 0.0);
}
#if USE_YCoCg
history.rgb = RGB_YCoCg(history.rgb);
#endif
// build the history clamping box
if (materialConstants_boxClipping != BOX_CLIPPING_NONE) {
vec3 boxmin;
vec3 boxmax;
if (materialConstants_boxType == BOX_TYPE_AABB ||
materialConstants_boxType == BOX_TYPE_AABB_VARIANCE) {
boxmin = min(s[4], min(min(s[1], s[3]), min(s[5], s[7])));
boxmax = max(s[4], max(max(s[1], s[3]), max(s[5], s[7])));
vec3 box9min = min(boxmin, min(min(s[0], s[2]), min(s[6], s[8])));
vec3 box9max = max(boxmax, max(max(s[0], s[2]), max(s[6], s[8])));
// round the corners of the 3x3 box
boxmin = (boxmin + box9min) * 0.5;
boxmax = (boxmax + box9max) * 0.5;
}
vec3 s[9];
s[0] = textureLodOffset(materialParams_color, uv.xy, 0.0, ivec2(-1, TEXTURE_SPACE_DN)).rgb;
s[1] = textureLodOffset(materialParams_color, uv.xy, 0.0, ivec2( 0, TEXTURE_SPACE_DN)).rgb;
s[2] = textureLodOffset(materialParams_color, uv.xy, 0.0, ivec2( 1, TEXTURE_SPACE_DN)).rgb;
s[3] = textureLodOffset(materialParams_color, uv.xy, 0.0, ivec2(-1, 0)).rgb;
s[4] = color.rgb;
s[5] = textureLodOffset(materialParams_color, uv.xy, 0.0, ivec2( 1, 0)).rgb;
s[6] = textureLodOffset(materialParams_color, uv.xy, 0.0, ivec2(-1, TEXTURE_SPACE_UP)).rgb;
s[7] = textureLodOffset(materialParams_color, uv.xy, 0.0, ivec2( 0, TEXTURE_SPACE_UP)).rgb;
s[8] = textureLodOffset(materialParams_color, uv.xy, 0.0, ivec2( 1, TEXTURE_SPACE_UP)).rgb;
if (materialConstants_boxType == BOX_TYPE_VARIANCE ||
materialConstants_boxType == BOX_TYPE_AABB_VARIANCE) {
// "An Excursion in Temporal Supersampling" by Marco Salvi
highp vec3 m0 = s[4];// conversion to highp
highp vec3 m1 = m0 * m0;
// we use only 5 samples instead of all 9
for (int i = 1; i < 9; i+=2) {
highp vec3 c = s[i];// conversion to highp
m0 += c;
m1 += c * c;
}
highp vec3 a0 = m0 * (1.0 / 5.0);
highp vec3 a1 = m1 * (1.0 / 5.0);
highp vec3 sigma = sqrt(a1 - a0 * a0);
if (materialConstants_boxType == BOX_TYPE_VARIANCE) {
boxmin = a0 - materialConstants_varianceGamma * sigma;
boxmax = a0 + materialConstants_varianceGamma * sigma;
} else {
// intersect both bounding boxes
boxmin = max(boxmin, a0 - materialConstants_varianceGamma * sigma);
boxmax = min(boxmax, a0 + materialConstants_varianceGamma * sigma);
}
}
// history clamping
history = clipToBox(materialConstants_boxClipping, boxmin, boxmax, filtered, history);
#if USE_YCoCg
for (int i = 0 ; i < 9 ; i++) {
s[i] = RGB_YCoCg(s[i]);
}
color.rgb = s[4].rgb;
#endif
#if FILTER_INPUT
// unjitter/filter input
vec4 filtered = vec4(0, 0, 0, color.a);
for (int i = 0 ; i < 9 ; i++) {
filtered.rgb += s[i] * materialParams.filterWeights[i];
}
#else
vec4 filtered = color;
#endif
#if BOX_TYPE == BOX_TYPE_AABB || BOX_TYPE == BOX_TYPE_AABB_VARIANCE
vec3 boxmin = min(s[4], min(min(s[1], s[3]), min(s[5], s[7])));
vec3 boxmax = max(s[4], max(max(s[1], s[3]), max(s[5], s[7])));
vec3 box9min = min(boxmin, min(min(s[0], s[2]), min(s[6], s[8])));
vec3 box9max = max(boxmax, max(max(s[0], s[2]), max(s[6], s[8])));
// round the corners of the 3x3 box
boxmin = (boxmin + box9min) * 0.5;
boxmax = (boxmax + box9max) * 0.5;
#endif
#if BOX_TYPE == BOX_TYPE_VARIANCE || BOX_TYPE == BOX_TYPE_AABB_VARIANCE
// "An Excursion in Temporal Supersampling" by Marco Salvi
vec3 m0 = s[4];
vec3 m1 = s[4] * s[4];
// we use only 5 samples instead of all 9
for (int i = 1 ; i < 9 ; i+=2) {
m0 += s[i];
m1 += s[i] * s[i];
}
vec3 a0 = m0 * (1.0 / 5.0);
vec3 a1 = m1 * (1.0 / 5.0);
vec3 sigma = sqrt(a1 - a0 * a0);
#if BOX_TYPE == BOX_TYPE_VARIANCE
vec3 boxmin = a0 - VARIANCE_GAMMA * sigma;
vec3 boxmax = a0 + VARIANCE_GAMMA * sigma;
#else
boxmin = min(boxmin, a0 - VARIANCE_GAMMA * sigma);
boxmax = max(boxmax, a0 + VARIANCE_GAMMA * sigma);
#endif
#endif
// history clamping
history = clipToBox(BOX_CLIPPING, boxmin, boxmax, filtered, history);
float lumaColor = luma(filtered.rgb);
float lumaHistory = luma(history.rgb);
float alpha = materialParams.alpha * confidence;
if (materialConstants_preventFlickering) {
// [Lottes] prevents flickering by modulating the blend weight by the difference in luma
float diff = 1.0 - abs(lumaColor - lumaHistory) / (0.001 + max(lumaColor, lumaHistory));
alpha *= diff * diff;
}
float alpha = materialParams.alpha;
#if PREVENT_FLICKERING
// [Lottes] prevents flickering by modulating the blend weight by the difference in luma
float diff = 1.0 - abs(lumaColor - lumaHistory) / (0.001 + max(lumaColor, lumaHistory));
alpha *= diff * diff;
#endif
// tonemapping for handling HDR
filtered.rgb *= 1.0 / (1.0 + lumaColor);
@@ -349,16 +307,20 @@ void postProcess(inout PostProcessInputs postProcess) {
// untonemap result
result.rgb *= 1.0 / (1.0 - luma(result.rgb));
if (materialConstants_useYCoCg) {
result.rgb = YCoCg_RGB(result.rgb);
}
#if USE_YCoCg
result.rgb = YCoCg_RGB(result.rgb);
#endif
// store result (which will becomes new history)
// we could end-up with negative values due to the bicubic filter, which never recover on
// their own.
result = max(vec4(0), result);
#if POST_PROCESS_OPAQUE
// kill the work performed above
result.a = 1.0;
#endif
// store result (which will becomes new history)
postProcess.color = result;
}
-33
View File
@@ -1,33 +0,0 @@
material {
name : resolveDepth,
parameters : [
{
type : sampler2d,
name : depth,
precision: high,
multisample : true
}
],
outputs : [
{
name : depth,
target : depth,
type : float
}
],
domain : postprocess,
depthWrite : true,
depthCulling : false,
culling: none
}
fragment {
// resolve depth by keeping the first sample. This is similar to what glBlitFramebuffer() does
// this material is currently only used on Metal and Vulkan.
// Technically it should be feature-level 2 material, but that would restrict when we can use
// it because Vulkan can return feature-level 1 currently (we should fix that).
void postProcess(inout PostProcessInputs postProcess) {
highp ivec2 icoord = ivec2(gl_FragCoord.xy);
postProcess.depth = texelFetch(materialParams_depth, icoord, 0).r;
}
}
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.49.3"
spec.version = "1.49.0"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.49.3/filament-v1.49.3-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.49.0/filament-v1.49.0-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
@@ -16,8 +16,6 @@
#import <UIKit/UIKit.h>
#include <utils/Entity.h>
namespace filament {
class Engine;
class Scene;
@@ -78,17 +76,6 @@ typedef NSData* _Nonnull (^ResourceCallback)(NSString* _Nonnull);
- (void)destroyModel;
/**
* Issues a pick query at the given view coordinates.
* The coordinates should be in UIKit's coordinate system, with the origin at
* the top-left.
* The callback is triggered with entity of the picked object.
*/
typedef void (^PickCallback)(utils::Entity);
- (void)issuePickQuery:(CGPoint)point callback:(PickCallback)callback;
- (NSString* _Nullable)getEntityName:(utils::Entity)entity;
/**
* Sets up a root transform on the current model to make it fit into a unit cube.
*/
@@ -127,12 +127,13 @@ const float kSensitivity = 100.0f;
_swapChain = _engine->createSwapChain((__bridge void*)self.layer);
_materialProvider =
createUbershaderProvider(_engine, UBERARCHIVE_DEFAULT_DATA, UBERARCHIVE_DEFAULT_SIZE);
_materialProvider = createUbershaderProvider(_engine,
UBERARCHIVE_DEFAULT_DATA, UBERARCHIVE_DEFAULT_SIZE);
EntityManager& em = EntityManager::get();
NameComponentManager* ncm = new NameComponentManager(em);
_assetLoader = AssetLoader::create({_engine, _materialProvider, ncm, &em});
_resourceLoader = new ResourceLoader({.engine = _engine, .normalizeSkinningWeights = true});
_resourceLoader = new ResourceLoader(
{.engine = _engine, .normalizeSkinningWeights = true});
_stbDecoder = createStbProvider(_engine);
_ktxDecoder = createKtx2Provider(_engine);
_resourceLoader->addTextureProvider("image/png", _stbDecoder);
@@ -181,26 +182,6 @@ const float kSensitivity = 100.0f;
_animator = nullptr;
}
- (void)issuePickQuery:(CGPoint)point callback:(PickCallback)callback {
CGPoint pointOriginBottomLeft = CGPointMake(point.x, self.bounds.size.height - point.y);
CGPoint pointScaled = CGPointMake(pointOriginBottomLeft.x * self.contentScaleFactor,
pointOriginBottomLeft.y * self.contentScaleFactor);
_view->pick(pointScaled.x, pointScaled.y,
[callback](View::PickingQueryResult const& result) { callback(result.renderable); });
}
- (NSString* _Nullable)getEntityName:(utils::Entity)entity {
if (!_asset) {
return nil;
}
NameComponentManager* ncm = _assetLoader->getNames();
NameComponentManager::Instance instance = ncm->getInstance(entity);
if (instance) {
return [NSString stringWithUTF8String:ncm->getName(ncm->getInstance(entity))];
}
return nil;
}
- (void)transformToUnitCube {
if (!_asset) {
return;
@@ -15,7 +15,6 @@
*/
#import "FILViewController.h"
#include <UIKit/UIKit.h>
#import "FILModelView.h"
@@ -36,9 +35,6 @@ using namespace filament;
using namespace utils;
using namespace ktxreader;
const float kToastAnimationDuration = 0.25f;
const float kToastDelayDuration = 2.0f;
@interface FILViewController ()
- (void)startDisplayLink;
@@ -47,9 +43,6 @@ const float kToastDelayDuration = 2.0f;
- (void)createRenderables;
- (void)createLights;
- (void)appWillResignActive:(NSNotification*)notification;
- (void)appDidBecomeActive:(NSNotification*)notification;
@end
@implementation FILViewController {
@@ -57,7 +50,6 @@ const float kToastDelayDuration = 2.0f;
CFTimeInterval _startTime;
viewer::RemoteServer* _server;
viewer::AutomationEngine* _automation;
UILabel* _toastLabel;
Texture* _skyboxTexture;
Skybox* _skybox;
@@ -65,7 +57,6 @@ const float kToastDelayDuration = 2.0f;
IndirectLight* _indirectLight;
Entity _sun;
UITapGestureRecognizer* _singleTapRecognizer;
UITapGestureRecognizer* _doubleTapRecognizer;
}
@@ -76,16 +67,6 @@ const float kToastDelayDuration = 2.0f;
self.title = @"https://google.github.io/filament/remote";
// Observe lifecycle notifications to prevent us from rendering in the background.
[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(appWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:nil];
[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(appDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
// Arguments:
// --model <path>
// path to glb or gltf file to load from documents directory
@@ -113,37 +94,9 @@ const float kToastDelayDuration = 2.0f;
_server = new viewer::RemoteServer();
_automation = viewer::AutomationEngine::createDefault();
_doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(reloadModel)];
_doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reloadModel)];
_doubleTapRecognizer.numberOfTapsRequired = 2;
[self.modelView addGestureRecognizer:_doubleTapRecognizer];
_singleTapRecognizer =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(issuePickingQuery)];
_singleTapRecognizer.numberOfTapsRequired = 1;
[self.modelView addGestureRecognizer:_singleTapRecognizer];
// Create a label at the top of the screen to toast messages to the user.
CGRect labelRect = self.view.bounds;
labelRect.size.height = 50;
_toastLabel = [[UILabel alloc] initWithFrame:labelRect];
_toastLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_toastLabel.textAlignment = NSTextAlignmentCenter;
_toastLabel.textColor = [UIColor whiteColor];
_toastLabel.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5f];
_toastLabel.numberOfLines = 0;
_toastLabel.lineBreakMode = NSLineBreakByWordWrapping;
_toastLabel.text = @"";
_toastLabel.alpha = 0.0f;
[self.view addSubview:_toastLabel];
}
- (void)appWillResignActive:(NSNotification*)notification {
[self stopDisplayLink];
}
- (void)appDidBecomeActive:(NSNotification*)notification {
[self startDisplayLink];
}
- (void)viewWillAppear:(BOOL)animated {
@@ -270,8 +223,7 @@ const float kToastDelayDuration = 2.0f;
.indirectLight = _indirectLight,
.sunlight = _sun,
};
_automation->applySettings(
self.modelView.engine, message->buffer, message->bufferByteCount, content);
_automation->applySettings(self.modelView.engine, message->buffer, message->bufferByteCount, content);
ColorGrading* const colorGrading = _automation->getColorGrading(self.modelView.engine);
self.modelView.view->setColorGrading(colorGrading);
self.modelView.cameraFocalLength = _automation->getViewerOptions().cameraFocalLength;
@@ -316,42 +268,7 @@ const float kToastDelayDuration = 2.0f;
[self createDefaultRenderables];
}
- (void)issuePickingQuery {
CGPoint tapLocation = [_singleTapRecognizer locationInView:self.modelView];
__weak typeof(self) weakSelf = self;
[self.modelView issuePickQuery:tapLocation
callback:^(utils::Entity entity) {
NSString* name = [self.modelView getEntityName:entity];
if (!name) {
name = @"<unnamed>";
}
NSString* message = [NSString
stringWithFormat:@"Picked entity %d (%@) at (%d,%d)",
entity.getId(), name, int(tapLocation.x), int(tapLocation.y)];
[weakSelf toastMessage:message];
}];
}
- (void)toastMessage:(NSString*)message {
_toastLabel.text = message;
_toastLabel.alpha = 0.0f;
[UIView animateWithDuration:kToastAnimationDuration
animations:^{
_toastLabel.alpha = 1.0f;
}
completion:^(BOOL finished) {
[UIView animateWithDuration:kToastAnimationDuration
delay:kToastDelayDuration
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
_toastLabel.alpha = 0.0f;
}
completion:nil];
}];
}
- (void)dealloc {
[NSNotificationCenter.defaultCenter removeObserver:self];
delete _server;
delete _automation;
self.modelView.engine->destroy(_indirectLight);
@@ -26,9 +26,7 @@
namespace filament {
static constexpr size_t POST_PROCESS_VARIANT_BITS = 1;
static constexpr size_t POST_PROCESS_VARIANT_COUNT = (1u << POST_PROCESS_VARIANT_BITS);
static constexpr size_t POST_PROCESS_VARIANT_MASK = POST_PROCESS_VARIANT_COUNT - 1;
static constexpr size_t POST_PROCESS_VARIANT_COUNT = 2;
enum class PostProcessVariant : uint8_t {
OPAQUE,
TRANSLUCENT
@@ -137,15 +135,11 @@ template<>
struct utils::EnableIntegerOperators<filament::SamplerBindingPoints> : public std::true_type {};
template<>
struct utils::EnableIntegerOperators<filament::ReservedSpecializationConstants> : public std::true_type {};
template<>
struct utils::EnableIntegerOperators<filament::PostProcessVariant> : public std::true_type {};
template<>
inline constexpr size_t utils::Enum::count<filament::UniformBindingPoints>() { return 9; }
template<>
inline constexpr size_t utils::Enum::count<filament::SamplerBindingPoints>() { return 4; }
template<>
inline constexpr size_t utils::Enum::count<filament::PostProcessVariant>() { return filament::POST_PROCESS_VARIANT_COUNT; }
static_assert(utils::Enum::count<filament::UniformBindingPoints>() <= filament::backend::CONFIG_UNIFORM_BINDING_COUNT);
static_assert(utils::Enum::count<filament::SamplerBindingPoints>() <= filament::backend::CONFIG_SAMPLER_BINDING_COUNT);
@@ -99,7 +99,6 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
float lodBias; // load bias to apply to user materials
float refractionLodOffset;
math::float2 derivativesScale;
// camera position in view space (when camera_at_origin is enabled), i.e. it's (0,0,0).
float oneOverFarMinusNear; // 1 / (f-n), always positive
@@ -112,6 +111,8 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
// AO
float aoSamplingQualityAndEdgeDistance; // <0: no AO, 0: bilinear, !0: bilateral edge distance
float aoBentNormals; // 0: no AO bent normal, >0.0 AO bent normals
float aoReserved0;
float aoReserved1;
// --------------------------------------------------------------------------------------------
// Dynamic Lighting [variant: DYN]
@@ -311,8 +311,12 @@ public:
*/
MaterialBuilder& parameter(const char* name, SamplerType samplerType,
SamplerFormat format = SamplerFormat::FLOAT,
ParameterPrecision precision = ParameterPrecision::DEFAULT,
bool multisample = false) noexcept;
ParameterPrecision precision = ParameterPrecision::DEFAULT) noexcept;
/// @copydoc parameter(SamplerType, SamplerFormat, ParameterPrecision, const char*)
MaterialBuilder& parameter(const char* name, SamplerType samplerType,
ParameterPrecision precision) noexcept;
MaterialBuilder& buffer(filament::BufferInterfaceBlock bib) noexcept;
@@ -618,8 +622,8 @@ public:
Parameter() noexcept: parameterType(INVALID) {}
// Sampler
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p, bool ms)
: name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER), multisample(ms) { }
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p)
: name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER) { }
// Uniform
Parameter(const char* paramName, UniformType t, size_t typeSize, ParameterPrecision p)
@@ -636,7 +640,6 @@ public:
SamplerType samplerType;
SubpassType subpassType;
SamplerFormat format;
bool multisample;
enum {
INVALID,
UNIFORM,
+1 -1
View File
@@ -234,7 +234,7 @@ void GLSLPostProcessor::spirvToMsl(const SpirvBlob *spirv, std::string *outMsl,
for (const auto& info: infoList) {
const std::string name = info.uniformName.c_str();
argBufferBuilder
.texture(info.offset * 2, name, info.type, info.format, info.multisample)
.texture(info.offset * 2, name, info.type, info.format)
.sampler(info.offset * 2 + 1, name + "Smplr");
}
+9 -11
View File
@@ -250,20 +250,17 @@ MaterialBuilder& MaterialBuilder::parameter(const char* name, UniformType type,
MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType samplerType,
SamplerFormat format, ParameterPrecision precision, bool multisample) noexcept {
ASSERT_PRECONDITION(
!multisample || (format != SamplerFormat::SHADOW && (
samplerType == SamplerType::SAMPLER_2D
|| samplerType == SamplerType::SAMPLER_2D_ARRAY)),
"multisample samplers only possible with SAMPLER_2D or SAMPLER_2D_ARRAY,"
" as long as type is not SHADOW");
SamplerFormat format, ParameterPrecision precision) noexcept {
ASSERT_POSTCONDITION(mParameterCount < MAX_PARAMETERS_COUNT, "Too many parameters");
mParameters[mParameterCount++] = { name, samplerType, format, precision, multisample };
mParameters[mParameterCount++] = { name, samplerType, format, precision };
return *this;
}
MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType samplerType,
ParameterPrecision precision) noexcept {
return parameter(name, samplerType, SamplerFormat::FLOAT, precision);
}
template<typename T, typename>
MaterialBuilder& MaterialBuilder::constant(const char* name, ConstantType type, T defaultValue) {
auto result = std::find_if(mConstants.begin(), mConstants.end(), [name](const Constant& c) {
@@ -559,7 +556,7 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
assert_invariant(!param.isSubpass());
if (param.isSampler()) {
sbb.add({ param.name.data(), param.name.size() },
param.samplerType, param.format, param.precision, param.multisample);
param.samplerType, param.format, param.precision);
} else if (param.isUniform()) {
ibb.add({{{ param.name.data(), param.name.size() },
uint32_t(param.size == 1u ? 0u : param.size), param.uniformType,
@@ -1168,6 +1165,7 @@ error:
mVariantFilter |= uint32_t(UserVariantFilterBit::SHADOW_RECEIVER);
mVariantFilter |= uint32_t(UserVariantFilterBit::VSM);
mVariantFilter |= uint32_t(UserVariantFilterBit::SSR);
mVariantFilter |= uint32_t(UserVariantFilterBit::STE);
}
// Create chunk tree.
+4 -17
View File
@@ -29,20 +29,11 @@ MetalArgumentBuffer::Builder& filamat::MetalArgumentBuffer::Builder::name(
MetalArgumentBuffer::Builder& MetalArgumentBuffer::Builder::texture(size_t index,
const std::string& name, filament::backend::SamplerType type,
filament::backend::SamplerFormat format,
bool multisample) noexcept {
using namespace filament::backend;
filament::backend::SamplerFormat format) noexcept {
// All combinations of SamplerType and SamplerFormat are valid except for SAMPLER_3D / SHADOW.
assert_invariant(type != SamplerType::SAMPLER_3D || format != SamplerFormat::SHADOW);
// multisample textures have restrictions too
assert_invariant(!multisample || (
format != SamplerFormat::SHADOW && (
type == SamplerType::SAMPLER_2D || type == SamplerType::SAMPLER_2D_ARRAY)));
mArguments.emplace_back(TextureArgument { name, index, type, format, multisample });
assert_invariant(type != filament::backend::SamplerType::SAMPLER_3D ||
format != filament::backend::SamplerFormat::SHADOW);
mArguments.emplace_back(TextureArgument { name, index, type, format });
return *this;
}
@@ -88,10 +79,6 @@ std::ostream& MetalArgumentBuffer::Builder::TextureArgument::write(std::ostream&
break;
}
if (multisample) {
os << "_ms";
}
switch (format) {
case filament::backend::SamplerFormat::INT:
os << "<int>";
+1 -3
View File
@@ -48,8 +48,7 @@ public:
*/
Builder& texture(size_t index, const std::string& name,
filament::backend::SamplerType type,
filament::backend::SamplerFormat format,
bool multisample) noexcept;
filament::backend::SamplerFormat format) noexcept;
/**
* Add a sampler argument to the argument buffer structure.
@@ -70,7 +69,6 @@ public:
size_t index;
filament::backend::SamplerType type;
filament::backend::SamplerFormat format;
bool multisample;
std::ostream& write(std::ostream& os) const;
};
+3 -3
View File
@@ -176,7 +176,7 @@ bool GLSLTools::analyzeComputeShader(const std::string& shaderCode,
bool const ok = tShader.parse(&DefaultTBuiltInResource, version, false, msg);
if (!ok) {
utils::slog.e << "ERROR: Unable to parse compute shader:" << utils::io::endl;
utils::slog.e << tShader.getInfoLog() << utils::io::endl;
utils::slog.e << tShader.getInfoLog() << utils::io::flush;
return false;
}
@@ -214,7 +214,7 @@ std::optional<GLSLTools::FragmentShaderInfo> GLSLTools::analyzeFragmentShader(
bool const ok = tShader.parse(&DefaultTBuiltInResource, version, false, msg);
if (!ok) {
utils::slog.e << "ERROR: Unable to parse fragment shader:" << utils::io::endl;
utils::slog.e << tShader.getInfoLog() << utils::io::endl;
utils::slog.e << tShader.getInfoLog() << utils::io::flush;
return std::nullopt;
}
@@ -294,7 +294,7 @@ bool GLSLTools::analyzeVertexShader(const std::string& shaderCode,
bool const ok = tShader.parse(&DefaultTBuiltInResource, version, false, msg);
if (!ok) {
utils::slog.e << "ERROR: Unable to parse vertex shader" << utils::io::endl;
utils::slog.e << tShader.getInfoLog() << utils::io::endl;
utils::slog.e << tShader.getInfoLog() << utils::io::flush;
return false;
}
+7 -6
View File
@@ -1150,12 +1150,13 @@ char const* CodeGenerator::getOutputTypeName(MaterialBuilder::OutputType type) n
char const* CodeGenerator::getSamplerTypeName(SamplerType type, SamplerFormat format,
bool multisample) const noexcept {
assert(!multisample); // multisample samplers not yet supported.
switch (type) {
case SamplerType::SAMPLER_2D:
switch (format) {
case SamplerFormat::INT: return multisample ? "isampler2DMS" : "isampler2D";
case SamplerFormat::UINT: return multisample ? "usampler2DMS" : "usampler2D";
case SamplerFormat::FLOAT: return multisample ? "sampler2DMS" : "sampler2D";
case SamplerFormat::INT: return "isampler2D";
case SamplerFormat::UINT: return "usampler2D";
case SamplerFormat::FLOAT: return "sampler2D";
case SamplerFormat::SHADOW: return "sampler2DShadow";
}
case SamplerType::SAMPLER_3D:
@@ -1168,9 +1169,9 @@ char const* CodeGenerator::getSamplerTypeName(SamplerType type, SamplerFormat fo
}
case SamplerType::SAMPLER_2D_ARRAY:
switch (format) {
case SamplerFormat::INT: return multisample ? "isampler2DMSArray": "isampler2DArray";
case SamplerFormat::UINT: return multisample ? "usampler2DMSArray": "usampler2DArray";
case SamplerFormat::FLOAT: return multisample ? "sampler2DMSArray": "sampler2DArray";
case SamplerFormat::INT: return "isampler2DArray";
case SamplerFormat::UINT: return "usampler2DArray";
case SamplerFormat::FLOAT: return "sampler2DArray";
case SamplerFormat::SHADOW: return "sampler2DArrayShadow";
}
case SamplerType::SAMPLER_CUBEMAP:
+1 -9
View File
@@ -52,7 +52,7 @@ void ShaderGenerator::generateSurfaceMaterialVariantDefines(utils::io::sstream&
CodeGenerator::generateDefine(out, "VARIANT_HAS_VSM",
filament::Variant::isVSMVariant(variant));
CodeGenerator::generateDefine(out, "VARIANT_HAS_INSTANCED_STEREO",
hasInstancedStereo(variant, featureLevel));
filament::Variant::isStereoVariant(variant));
switch (stage) {
case ShaderStage::VERTEX:
@@ -758,12 +758,4 @@ bool ShaderGenerator::hasSkinningOrMorphing(
&& featureLevel > MaterialBuilder::FeatureLevel::FEATURE_LEVEL_0;
}
bool ShaderGenerator::hasInstancedStereo(
filament::Variant variant, MaterialBuilder::FeatureLevel featureLevel) noexcept {
return variant.hasInstancedStereo()
// HACK(exv): Ignore stereo variant when targeting ESSL 1.0. We should properly build a
// system in matc which allows the set of included variants to differ per-feature level.
&& featureLevel > MaterialBuilder::FeatureLevel::FEATURE_LEVEL_0;
}
} // namespace filament
@@ -115,10 +115,6 @@ private:
filament::Variant variant,
MaterialBuilder::FeatureLevel featureLevel) noexcept;
static bool hasInstancedStereo(
filament::Variant variant,
MaterialBuilder::FeatureLevel featureLevel) noexcept;
MaterialBuilder::PropertyList mProperties;
MaterialBuilder::VariableList mVariables;
MaterialBuilder::OutputList mOutputs;
+2 -1
View File
@@ -60,7 +60,6 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
{ "lodBias", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 },
{ "refractionLodOffset", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 },
{ "derivativesScale", 0, Type::FLOAT2 },
{ "oneOverFarMinusNear", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 },
{ "nearOverFarMinusNear", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 },
@@ -72,6 +71,8 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
// AO
{ "aoSamplingQualityAndEdgeDistance", 0, Type::FLOAT },
{ "aoBentNormals", 0, Type::FLOAT },
{ "aoReserved0", 0, Type::FLOAT },
{ "aoReserved1", 0, Type::FLOAT },
// ------------------------------------------------------------------------------------
// Dynamic Lighting [variant: DYN]
+10 -30
View File
@@ -72,7 +72,7 @@ TEST(ArgBufferFixup, TextureAndSampler) {
auto argBuffer =
MetalArgumentBuffer::Builder()
.name("myArgumentBuffer")
.texture(0, "textureA", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, false)
.texture(0, "textureA", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT)
.sampler(1, "samplerA")
.build();
auto argBufferStr = argBuffer->getMsl();
@@ -88,33 +88,13 @@ TEST(ArgBufferFixup, TextureAndSampler) {
MetalArgumentBuffer::destroy(&argBuffer);
}
TEST(ArgBufferFixup, TextureAndSamplerMS) {
auto argBuffer =
MetalArgumentBuffer::Builder()
.name("myArgumentBuffer")
.texture(0, "textureA", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, true)
.sampler(1, "samplerA")
.build();
auto argBufferStr = argBuffer->getMsl();
const std::string expected =
"struct myArgumentBuffer {\n"
"texture2d_ms<float> textureA [[id(0)]];\n"
"sampler samplerA [[id(1)]];\n"
"}";
EXPECT_EQ(argBuffer->getMsl(), expected);
MetalArgumentBuffer::destroy(&argBuffer);
}
TEST(ArgBufferFixup, Sorted) {
auto argBuffer =
MetalArgumentBuffer::Builder()
.name("myArgumentBuffer")
.sampler(3, "samplerB")
.texture(0, "textureA", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, false)
.texture(2, "textureB", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, false)
.texture(0, "textureA", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT)
.texture(2, "textureB", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT)
.sampler(1, "samplerA")
.build();
auto argBufferStr = argBuffer->getMsl();
@@ -136,12 +116,12 @@ TEST(ArgBufferFixup, TextureTypes) {
auto argBuffer =
MetalArgumentBuffer::Builder()
.name("myArgumentBuffer")
.texture(0, "textureA", SamplerType::SAMPLER_2D, SamplerFormat::INT, false)
.texture(1, "textureB", SamplerType::SAMPLER_2D_ARRAY, SamplerFormat::UINT, false)
.texture(2, "textureC", SamplerType::SAMPLER_CUBEMAP, SamplerFormat::FLOAT, false)
.texture(3, "textureD", SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT, false)
.texture(4, "textureE", SamplerType::SAMPLER_3D, SamplerFormat::FLOAT, false)
.texture(5, "textureF", SamplerType::SAMPLER_CUBEMAP_ARRAY, SamplerFormat::SHADOW, false)
.texture(0, "textureA", SamplerType::SAMPLER_2D, SamplerFormat::INT)
.texture(1, "textureB", SamplerType::SAMPLER_2D_ARRAY, SamplerFormat::UINT)
.texture(2, "textureC", SamplerType::SAMPLER_CUBEMAP, SamplerFormat::FLOAT)
.texture(3, "textureD", SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT)
.texture(4, "textureE", SamplerType::SAMPLER_3D, SamplerFormat::FLOAT)
.texture(5, "textureF", SamplerType::SAMPLER_CUBEMAP_ARRAY, SamplerFormat::SHADOW)
.build();
auto argBufferStr = argBuffer->getMsl();
@@ -167,7 +147,7 @@ TEST(ArgBufferFixup, InvalidType) {
auto argBuffer =
MetalArgumentBuffer::Builder()
.name("myArgumentBuffer")
.texture(0, "textureA", SamplerType::SAMPLER_3D, SamplerFormat::SHADOW, false)
.texture(0, "textureA", SamplerType::SAMPLER_3D, SamplerFormat::SHADOW)
.build();
MetalArgumentBuffer::destroy(&argBuffer);
}, "failed assertion");
+8 -8
View File
@@ -215,7 +215,7 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn,
}
void ApiHandler::addMaterial(MaterialRecord const* material) {
std::unique_lock const lock(mStatusMutex);
std::unique_lock<utils::Mutex> lock(mStatusMutex);
snprintf(statusMaterialId, sizeof(statusMaterialId), "%8.8x", material->key);
mStatusCondition.notify_all();
}
@@ -229,7 +229,7 @@ bool ApiHandler::handleGetStatus(struct mg_connection* conn,
return true;
}
std::unique_lock<std::mutex> lock(mStatusMutex);
std::unique_lock<utils::Mutex> lock(mStatusMutex);
uint64_t const currentStatusCount = mCurrentStatus;
if (mStatusCondition.wait_for(lock, 10s,
[this, currentStatusCount] { return currentStatusCount < mCurrentStatus; })) {
@@ -258,13 +258,13 @@ bool ApiHandler::handlePost(CivetServer* server, struct mg_connection* conn) {
// [material id] [api index] [shader index] [shader source....]
if (uri == "/api/edit") {
struct mg_request_info const* req_info = mg_get_request_info(conn);
size_t const msgLen = req_info->content_length;
size_t msgLen = req_info->content_length;
char buf[1024];
size_t readLen = 0;
std::stringstream sstream;
while (readLen < msgLen) {
int const res = mg_read(conn, buf, sizeof(buf));
int res = mg_read(conn, buf, sizeof(buf));
if (res < 0) {
utils::slog.e << "civet error parsing /api/edit body: " << res << utils::io::endl;
break;
@@ -279,7 +279,7 @@ bool ApiHandler::handlePost(CivetServer* server, struct mg_connection* conn) {
int api;
int shaderIndex;
sstream >> std::hex >> matid >> std::dec >> api >> shaderIndex;
std::string const shader = sstream.str().substr(sstream.tellg());
std::string shader = sstream.str().substr(sstream.tellg());
mServer->handleEditCommand(matid, backend::Backend(api), shaderIndex, shader.c_str(),
shader.size());
@@ -298,7 +298,7 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) {
mServer->updateActiveVariants();
// Careful not to lock the above line.
std::unique_lock const lock(mServer->mMaterialRecordsMutex);
std::unique_lock<utils::Mutex> lock(mServer->mMaterialRecordsMutex);
mg_printf(conn, kSuccessHeader.data(), "application/json");
mg_printf(conn, "{");
@@ -329,7 +329,7 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) {
}
if (uri == "/api/matids") {
std::unique_lock const lock(mServer->mMaterialRecordsMutex);
std::unique_lock<utils::Mutex> lock(mServer->mMaterialRecordsMutex);
mg_printf(conn, kSuccessHeader.data(), "application/json");
mg_printf(conn, "[");
int index = 0;
@@ -342,7 +342,7 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) {
}
if (uri == "/api/materials") {
std::unique_lock const lock(mServer->mMaterialRecordsMutex);
std::unique_lock<utils::Mutex> lock(mServer->mMaterialRecordsMutex);
mg_printf(conn, kSuccessHeader.data(), "application/json");
mg_printf(conn, "[");
int index = 0;
+2 -3
View File
@@ -17,8 +17,7 @@
#ifndef MATDBG_APIHANDLER_H
#define MATDBG_APIHANDLER_H
#include <mutex>
#include <condition_variable>
#include <utils/Mutex.h>
#include <CivetServer.h>
@@ -54,7 +53,7 @@ private:
DebugServer* mServer;
std::mutex mStatusMutex;
utils::Mutex mStatusMutex;
std::condition_variable mStatusCondition;
char statusMaterialId[9] = {};
-5
View File
@@ -12,11 +12,6 @@
margin: 0;
font-family: "Open Sans";
}
@font-face {
font-family: codicon;
src: url(https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.25.2/min/vs/base/browser/ui/codicons/codicon/codicon.ttf);
}
</style>
<script src="api.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.25.2/min/vs/loader.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@ struct hashCStrings {
typedef size_t result_type;
result_type operator()(argument_type cstr) const noexcept {
size_t hash = 5381;
while (int const c = *cstr++) {
while (int c = *cstr++) {
hash = (hash * 33u) ^ size_t(c);
}
return hash;
+4 -10
View File
@@ -29,7 +29,7 @@ namespace utils::io {
struct ostream_;
class UTILS_PUBLIC ostream : protected utils::PrivateImplementation<ostream_> {
class UTILS_PUBLIC ostream : protected utils::PrivateImplementation<ostream_> {
friend struct ostream_;
public:
@@ -69,13 +69,6 @@ public:
ostream& dec() noexcept;
ostream& hex() noexcept;
/*! @cond PRIVATE */
// Sets a consumer of the log. The consumer is invoked on flush() and replaces the default.
// Thread safe and reentrant.
using ConsumerCallback = void(*)(void*, char const*);
void setConsumer(ConsumerCallback consumer, void* user) noexcept;
/*! @endcond */
protected:
ostream& print(const char* format, ...) noexcept;
@@ -111,7 +104,7 @@ private:
friend ostream& hex(ostream& s) noexcept;
friend ostream& dec(ostream& s) noexcept;
friend ostream& endl(ostream& s) noexcept;
UTILS_PUBLIC friend ostream& flush(ostream& s) noexcept;
friend ostream& flush(ostream& s) noexcept;
enum type {
SHORT, USHORT, CHAR, UCHAR, INT, UINT, LONG, ULONG, LONG_LONG, ULONG_LONG, FLOAT, DOUBLE,
@@ -139,7 +132,8 @@ inline ostream& operator<<(ostream& stream, const VECTOR<T>& v) {
inline ostream& hex(ostream& s) noexcept { return s.hex(); }
inline ostream& dec(ostream& s) noexcept { return s.dec(); }
inline ostream& endl(ostream& s) noexcept { return flush(s << '\n'); }
inline ostream& endl(ostream& s) noexcept { s << '\n'; return s.flush(); }
inline ostream& flush(ostream& s) noexcept { return s.flush(); }
} // namespace utils::io
+23 -23
View File
@@ -31,8 +31,6 @@
#include <emscripten/console.h>
#endif
#include <mutex>
namespace utils {
namespace io {
@@ -48,41 +46,43 @@ public:
ostream& flush() noexcept override;
private:
const Priority mPriority;
Priority mPriority;
};
ostream& LogStream::flush() noexcept {
std::lock_guard const lock(mImpl->mLock);
std::lock_guard lock(mImpl->mLock);
Buffer& buf = getBuffer();
char const* const str = buf.get();
if (UTILS_UNLIKELY(!str)) {
// this can happen if the log hasn't been written ever
return *this;
}
#ifdef __ANDROID__
int prio = ANDROID_LOG_UNKNOWN;
switch (mPriority) {
case LOG_DEBUG: prio = ANDROID_LOG_DEBUG; break;
case LOG_ERROR: prio = ANDROID_LOG_ERROR; break;
case LOG_WARNING: prio = ANDROID_LOG_WARN; break;
case LOG_INFO: prio = ANDROID_LOG_INFO; break;
case LOG_VERBOSE: prio = ANDROID_LOG_VERBOSE; break;
case LOG_DEBUG:
__android_log_write(ANDROID_LOG_DEBUG, UTILS_LOG_TAG, buf.get());
break;
case LOG_ERROR:
__android_log_write(ANDROID_LOG_ERROR, UTILS_LOG_TAG, buf.get());
break;
case LOG_WARNING:
__android_log_write(ANDROID_LOG_WARN, UTILS_LOG_TAG, buf.get());
break;
case LOG_INFO:
__android_log_write(ANDROID_LOG_INFO, UTILS_LOG_TAG, buf.get());
break;
case LOG_VERBOSE:
__android_log_write(ANDROID_LOG_VERBOSE, UTILS_LOG_TAG, buf.get());
break;
}
__android_log_write(prio, UTILS_LOG_TAG, str);
#elif defined(__EMSCRIPTEN__)
switch (mPriority) {
case LOG_DEBUG:
case LOG_WARNING:
case LOG_INFO:
_emscripten_out(str);
_emscripten_out(buf.get());
break;
case LOG_ERROR:
_emscripten_err(str);
_emscripten_err(buf.get());
break;
case LOG_VERBOSE:
#ifndef NFIL_DEBUG
_emscripten_out(str);
_emscripten_out(buf.get());
#endif
break;
}
@@ -91,14 +91,14 @@ ostream& LogStream::flush() noexcept {
case LOG_DEBUG:
case LOG_WARNING:
case LOG_INFO:
fprintf(stdout, "%s", str);
fprintf(stdout, "%s", buf.get());
break;
case LOG_ERROR:
fprintf(stderr, "%s", str);
fprintf(stderr, "%s", buf.get());
break;
case LOG_VERBOSE:
#ifndef NDEBUG
fprintf(stdout, "%s", str);
fprintf(stdout, "%s", buf.get());
#endif
break;
}
+6 -38
View File
@@ -24,14 +24,10 @@
#include <utils/PrivateImplementation-impl.h>
#include <algorithm>
#include <mutex>
#include <string>
#include <string_view>
#include <utility>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
template class utils::PrivateImplementation<utils::io::ostream_>;
@@ -39,34 +35,6 @@ namespace utils::io {
ostream::~ostream() = default;
void ostream::setConsumer(ConsumerCallback consumer, void* user) noexcept {
auto* const pImpl = mImpl;
std::lock_guard const lock(pImpl->mLock);
pImpl->mConsumer = { consumer, user };
}
ostream& flush(ostream& s) noexcept {
auto* const pImpl = s.mImpl;
pImpl->mLock.lock();
auto const callback = pImpl->mConsumer;
if (UTILS_UNLIKELY(callback.first)) {
auto& buf = s.getBuffer();
char const* const data = buf.get();
if (UTILS_LIKELY(data)) {
char* const str = strdup(data);
buf.reset();
pImpl->mLock.unlock();
// call ConsumerCallback without lock held
callback.first(callback.second, str);
::free(str);
return s;
}
}
pImpl->mLock.unlock();
return s.flush();
}
ostream::Buffer& ostream::getBuffer() noexcept {
return mImpl->mData;
}
@@ -101,12 +69,12 @@ ostream& ostream::print(const char* format, ...) noexcept {
// figure out how much size to we need
va_start(args0, format);
va_copy(args1, args0);
ssize_t const s = vsnprintf(nullptr, 0, format, args0);
ssize_t s = vsnprintf(nullptr, 0, format, args0);
va_end(args0);
{ // scope for the lock
std::lock_guard const lock(mImpl->mLock);
std::lock_guard lock(mImpl->mLock);
Buffer& buf = getBuffer();
@@ -237,14 +205,14 @@ ostream::Buffer::~Buffer() noexcept {
void ostream::Buffer::advance(ssize_t n) noexcept {
if (n > 0) {
size_t const written = n < size ? size_t(n) : size;
size_t written = n < size ? size_t(n) : size;
curr += written;
size -= written;
}
}
void ostream::Buffer::reserve(size_t newSize) noexcept {
size_t const offset = curr - buffer;
size_t offset = curr - buffer;
if (buffer == nullptr) {
buffer = (char*)malloc(newSize);
} else {
@@ -269,8 +237,8 @@ void ostream::Buffer::reset() noexcept {
std::pair<char*, size_t> ostream::Buffer::grow(size_t s) noexcept {
if (UTILS_UNLIKELY(size < s)) {
size_t const used = curr - buffer;
size_t const newCapacity = std::max(size_t(32), used + (s * 3 + 1) / 2); // 32 bytes minimum
size_t used = curr - buffer;
size_t newCapacity = std::max(size_t(32), used + (s * 3 + 1) / 2); // 32 bytes minimum
reserve(newCapacity);
assert(size >= s);
}
-1
View File
@@ -25,7 +25,6 @@ namespace utils::io {
struct ostream_ {
std::mutex mLock;
ostream::Buffer mData;
std::pair<ostream::ConsumerCallback, void*> mConsumer{};
bool mShowHex = false;
};
-25
View File
@@ -18,33 +18,8 @@
#include <utils/sstream.h>
#include <utils/Log.h>
using namespace utils;
using namespace utils::io;
TEST(ostream, setConsumer) {
slog.d.setConsumer(+[](void*, char const*) {
GTEST_FAIL();
}, nullptr);
// we test that we don't crash if the log is empty and that we don't call the consumer.
flush(slog.d);
slog.d.setConsumer(nullptr, nullptr);
slog.d << "hello world";
// we test that after resetting the consumer, it's not called on flush.
flush(slog.d);
const char* str = "hello world!";
slog.d.setConsumer(+[](void* user, char const* str) {
ASSERT_STREQ(str, (const char*)user);
}, (void*)str);
slog.d << str;
// we test that the comsumer is called with the right string
flush(slog.d);
slog.d.setConsumer(nullptr, nullptr);
}
TEST(sstream, EmptyString) {
sstream ss;
EXPECT_STREQ("", ss.c_str());
-1
View File
@@ -234,7 +234,6 @@ struct ViewerOptions {
float cameraNear = 0.1f;
float cameraFar = 100.0f;
float cameraEyeOcularDistance = 0.0f;
float cameraEyeToeIn = 0.0f;
float groundShadowStrength = 0.75f;
bool groundPlaneEnabled = false;
bool skyboxEnabled = true;
+2 -7
View File
@@ -504,8 +504,6 @@ static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, ViewerOp
i = parse(tokens, i + 1, jsonChunk, &out->cameraFar);
} else if (compare(tok, jsonChunk, "cameraEyeOcularDistance") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->cameraEyeOcularDistance);
} else if (compare(tok, jsonChunk, "cameraEyeToeIn") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->cameraEyeToeIn);
} else if (compare(tok, jsonChunk, "groundShadowStrength") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->groundShadowStrength);
} else if (compare(tok, jsonChunk, "groundPlaneEnabled") == 0) {
@@ -660,11 +658,9 @@ void applySettings(Engine* engine, const ViewerOptions& settings, Camera* camera
// "cross-eyed" stereo.
// For cross-eyed stereo, Eye 0 is really the RIGHT eye, while Eye 1 is the LEFT eye.
const auto od = settings.cameraEyeOcularDistance;
const auto toeIn = settings.cameraEyeToeIn;
const auto eyeCount = engine->getConfig().stereoscopicEyeCount;
const double3 up = double3(0.0, 1.0, 0.0);
const mat4 rightEye = mat4::translation(double3{ od, 0.0, 0.0}) * mat4::rotation( toeIn, up);
const mat4 leftEye = mat4::translation(double3{-od, 0.0, 0.0}) * mat4::rotation(-toeIn, up);
const mat4 rightEye = mat4::translation(double3{ od, 0.0, 0.0}); // right eye
const mat4 leftEye = mat4::translation(double3{-od, 0.0, 0.0}); // left eye
const mat4 modelMatrices[2] = { rightEye, leftEye };
for (int i = 0; i < eyeCount; i++) {
camera->setEyeModelMatrix(i, modelMatrices[i % 2]);
@@ -881,7 +877,6 @@ static std::ostream& operator<<(std::ostream& out, const ViewerOptions& in) {
<< "\"cameraNear\": " << (in.cameraNear) << ",\n"
<< "\"cameraFar\": " << (in.cameraFar) << ",\n"
<< "\"cameraEyeOcularDistance\": " << (in.cameraEyeOcularDistance) << ",\n"
<< "\"cameraEyeToeIn\": " << (in.cameraEyeToeIn) << ",\n"
<< "\"groundShadowStrength\": " << (in.groundShadowStrength) << ",\n"
<< "\"groundPlaneEnabled\": " << to_string(in.groundPlaneEnabled) << ",\n"
<< "\"skyboxEnabled\": " << to_string(in.skyboxEnabled) << ",\n"
+1 -96
View File
@@ -391,8 +391,6 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, DepthOfFieldOpt
CHECK_KEY(tok);
if (compare(tok, jsonChunk, "cocScale") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->cocScale);
} else if (compare(tok, jsonChunk, "cocAspectRatio") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->cocAspectRatio);
} else if (compare(tok, jsonChunk, "maxApertureDiameter") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->maxApertureDiameter);
} else if (compare(tok, jsonChunk, "enabled") == 0) {
@@ -426,7 +424,6 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, DepthOfFieldOpt
std::ostream& operator<<(std::ostream& out, const DepthOfFieldOptions& in) {
return out << "{\n"
<< "\"cocScale\": " << (in.cocScale) << ",\n"
<< "\"cocAspectRatio\": " << (in.cocAspectRatio) << ",\n"
<< "\"maxApertureDiameter\": " << (in.maxApertureDiameter) << ",\n"
<< "\"enabled\": " << to_string(in.enabled) << ",\n"
<< "\"filter\": " << (in.filter) << ",\n"
@@ -650,65 +647,6 @@ std::ostream& operator<<(std::ostream& out, const MultiSampleAntiAliasingOptions
<< "}";
}
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAliasingOptions::BoxType* out) {
if (0 == compare(tokens[i], jsonChunk, "AABB")) { *out = TemporalAntiAliasingOptions::BoxType::AABB; }
else if (0 == compare(tokens[i], jsonChunk, "VARIANCE")) { *out = TemporalAntiAliasingOptions::BoxType::VARIANCE; }
else if (0 == compare(tokens[i], jsonChunk, "AABB_VARIANCE")) { *out = TemporalAntiAliasingOptions::BoxType::AABB_VARIANCE; }
else {
slog.w << "Invalid TemporalAntiAliasingOptions::BoxType: '" << STR(tokens[i], jsonChunk) << "'" << io::endl;
}
return i + 1;
}
std::ostream& operator<<(std::ostream& out, TemporalAntiAliasingOptions::BoxType in) {
switch (in) {
case TemporalAntiAliasingOptions::BoxType::AABB: return out << "\"AABB\"";
case TemporalAntiAliasingOptions::BoxType::VARIANCE: return out << "\"VARIANCE\"";
case TemporalAntiAliasingOptions::BoxType::AABB_VARIANCE: return out << "\"AABB_VARIANCE\"";
}
return out << "\"INVALID\"";
}
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAliasingOptions::BoxClipping* out) {
if (0 == compare(tokens[i], jsonChunk, "ACCURATE")) { *out = TemporalAntiAliasingOptions::BoxClipping::ACCURATE; }
else if (0 == compare(tokens[i], jsonChunk, "CLAMP")) { *out = TemporalAntiAliasingOptions::BoxClipping::CLAMP; }
else if (0 == compare(tokens[i], jsonChunk, "NONE")) { *out = TemporalAntiAliasingOptions::BoxClipping::NONE; }
else {
slog.w << "Invalid TemporalAntiAliasingOptions::BoxClipping: '" << STR(tokens[i], jsonChunk) << "'" << io::endl;
}
return i + 1;
}
std::ostream& operator<<(std::ostream& out, TemporalAntiAliasingOptions::BoxClipping in) {
switch (in) {
case TemporalAntiAliasingOptions::BoxClipping::ACCURATE: return out << "\"ACCURATE\"";
case TemporalAntiAliasingOptions::BoxClipping::CLAMP: return out << "\"CLAMP\"";
case TemporalAntiAliasingOptions::BoxClipping::NONE: return out << "\"NONE\"";
}
return out << "\"INVALID\"";
}
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAliasingOptions::JitterPattern* out) {
if (0 == compare(tokens[i], jsonChunk, "RGSS_X4")) { *out = TemporalAntiAliasingOptions::JitterPattern::RGSS_X4; }
else if (0 == compare(tokens[i], jsonChunk, "UNIFORM_HELIX_X4")) { *out = TemporalAntiAliasingOptions::JitterPattern::UNIFORM_HELIX_X4; }
else if (0 == compare(tokens[i], jsonChunk, "HALTON_23_X8")) { *out = TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X8; }
else if (0 == compare(tokens[i], jsonChunk, "HALTON_23_X16")) { *out = TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X16; }
else {
slog.w << "Invalid TemporalAntiAliasingOptions::JitterPattern: '" << STR(tokens[i], jsonChunk) << "'" << io::endl;
}
return i + 1;
}
std::ostream& operator<<(std::ostream& out, TemporalAntiAliasingOptions::JitterPattern in) {
switch (in) {
case TemporalAntiAliasingOptions::JitterPattern::RGSS_X4: return out << "\"RGSS_X4\"";
case TemporalAntiAliasingOptions::JitterPattern::UNIFORM_HELIX_X4: return out << "\"UNIFORM_HELIX_X4\"";
case TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X8: return out << "\"HALTON_23_X8\"";
case TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X16: return out << "\"HALTON_23_X16\"";
}
return out << "\"INVALID\"";
}
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAliasingOptions* out) {
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
int size = tokens[i++].size;
@@ -719,30 +657,8 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAli
i = parse(tokens, i + 1, jsonChunk, &out->filterWidth);
} else if (compare(tok, jsonChunk, "feedback") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->feedback);
} else if (compare(tok, jsonChunk, "lodBias") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->lodBias);
} else if (compare(tok, jsonChunk, "enabled") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->enabled);
} else if (compare(tok, jsonChunk, "upscaling") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->upscaling);
} else if (compare(tok, jsonChunk, "filterHistory") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->filterHistory);
} else if (compare(tok, jsonChunk, "filterInput") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->filterInput);
} else if (compare(tok, jsonChunk, "useYCoCg") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->useYCoCg);
} else if (compare(tok, jsonChunk, "boxType") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->boxType);
} else if (compare(tok, jsonChunk, "boxClipping") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->boxClipping);
} else if (compare(tok, jsonChunk, "jitterPattern") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->jitterPattern);
} else if (compare(tok, jsonChunk, "varianceGamma") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->varianceGamma);
} else if (compare(tok, jsonChunk, "preventFlickering") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->preventFlickering);
} else if (compare(tok, jsonChunk, "historyReprojection") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->historyReprojection);
} else {
slog.w << "Invalid TemporalAntiAliasingOptions key: '" << STR(tok, jsonChunk) << "'" << io::endl;
i = parse(tokens, i + 1);
@@ -759,18 +675,7 @@ std::ostream& operator<<(std::ostream& out, const TemporalAntiAliasingOptions& i
return out << "{\n"
<< "\"filterWidth\": " << (in.filterWidth) << ",\n"
<< "\"feedback\": " << (in.feedback) << ",\n"
<< "\"lodBias\": " << (in.lodBias) << ",\n"
<< "\"enabled\": " << to_string(in.enabled) << ",\n"
<< "\"upscaling\": " << to_string(in.upscaling) << ",\n"
<< "\"filterHistory\": " << to_string(in.filterHistory) << ",\n"
<< "\"filterInput\": " << to_string(in.filterInput) << ",\n"
<< "\"useYCoCg\": " << to_string(in.useYCoCg) << ",\n"
<< "\"boxType\": " << (in.boxType) << ",\n"
<< "\"boxClipping\": " << (in.boxClipping) << ",\n"
<< "\"jitterPattern\": " << (in.jitterPattern) << ",\n"
<< "\"varianceGamma\": " << (in.varianceGamma) << ",\n"
<< "\"preventFlickering\": " << to_string(in.preventFlickering) << ",\n"
<< "\"historyReprojection\": " << to_string(in.historyReprojection) << "\n"
<< "\"enabled\": " << to_string(in.enabled) << "\n"
<< "}";
}
-9
View File
@@ -69,15 +69,6 @@ std::ostream& operator<<(std::ostream& out, const AmbientOcclusionOptions& in);
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, MultiSampleAntiAliasingOptions* out);
std::ostream& operator<<(std::ostream& out, const MultiSampleAntiAliasingOptions& in);
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAliasingOptions::BoxType* out);
std::ostream& operator<<(std::ostream& out, TemporalAntiAliasingOptions::BoxType in);
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAliasingOptions::BoxClipping* out);
std::ostream& operator<<(std::ostream& out, TemporalAntiAliasingOptions::BoxClipping in);
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAliasingOptions::JitterPattern* out);
std::ostream& operator<<(std::ostream& out, TemporalAntiAliasingOptions::JitterPattern in);
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAliasingOptions* out);
std::ostream& operator<<(std::ostream& out, const TemporalAntiAliasingOptions& in);
-27
View File
@@ -792,28 +792,6 @@ void ViewerGui::updateUserInterface() {
ImGui::Checkbox("Lens Flare", &mSettings.view.bloom.lensFlare);
}
if (ImGui::CollapsingHeader("TAA Options")) {
ImGui::Checkbox("Upscaling", &mSettings.view.taa.upscaling);
ImGui::Checkbox("History Reprojection", &mSettings.view.taa.historyReprojection);
ImGui::SliderFloat("Feedback", &mSettings.view.taa.feedback, 0.0f, 1.0f);
ImGui::Checkbox("Filter History", &mSettings.view.taa.filterHistory);
ImGui::Checkbox("Filter Input", &mSettings.view.taa.filterInput);
ImGui::SliderFloat("FilterWidth", &mSettings.view.taa.filterWidth, 0.2f, 2.0f);
ImGui::SliderFloat("LOD bias", &mSettings.view.taa.lodBias, -8.0f, 0.0f);
ImGui::Checkbox("Use YCoCg", &mSettings.view.taa.useYCoCg);
ImGui::Checkbox("Prevent Flickering", &mSettings.view.taa.preventFlickering);
int jitterSequence = (int)mSettings.view.taa.jitterPattern;
int boxClipping = (int)mSettings.view.taa.boxClipping;
int boxType = (int)mSettings.view.taa.boxType;
ImGui::Combo("Jitter Pattern", &jitterSequence, "RGSS x4\0Uniform Helix x4\0Halton x8\0Halton x16\0\0");
ImGui::Combo("Box Clipping", &boxClipping, "Accurate\0Clamp\0None\0\0");
ImGui::Combo("Box Type", &boxType, "AABB\0Variance\0Both\0\0");
ImGui::SliderFloat("Variance Gamma", &mSettings.view.taa.varianceGamma, 0.75f, 1.25f);
mSettings.view.taa.boxClipping = (TemporalAntiAliasingOptions::BoxClipping)boxClipping;
mSettings.view.taa.boxType = (TemporalAntiAliasingOptions::BoxType)boxType;
mSettings.view.taa.jitterPattern = (TemporalAntiAliasingOptions::JitterPattern)jitterSequence;
}
if (ImGui::CollapsingHeader("SSAO Options")) {
auto& ssao = mSettings.view.ssao;
@@ -1036,7 +1014,6 @@ void ViewerGui::updateUserInterface() {
ImGui::Checkbox("Enabled##dofEnabled", &mSettings.view.dof.enabled);
ImGui::SliderFloat("Focus distance", &mSettings.viewer.cameraFocusDistance, 0.0f, 30.0f);
ImGui::SliderFloat("Blur scale", &mSettings.view.dof.cocScale, 0.1f, 10.0f);
ImGui::SliderFloat("CoC aspect-ratio", &mSettings.view.dof.cocAspectRatio, 0.25f, 4.0f);
ImGui::SliderInt("Ring count", &dofRingCount, 1, 17);
ImGui::SliderInt("Max CoC", &dofMaxCoC, 1, 32);
ImGui::Checkbox("Native Resolution", &mSettings.view.dof.nativeResolution);
@@ -1094,10 +1071,6 @@ void ViewerGui::updateUserInterface() {
ImGui::SliderFloat(
"Ocular distance", &mSettings.viewer.cameraEyeOcularDistance, 0.0f, 1.0f);
float toeInDegrees = mSettings.viewer.cameraEyeToeIn / f::PI * 180.0f;
ImGui::SliderFloat("Toe in", &toeInDegrees, 0.0f, 30.0, "%.3f°");
mSettings.viewer.cameraEyeToeIn = toeInDegrees / 180.0f * f::PI;
ImGui::Unindent();
}
+9 -14
View File
@@ -5,27 +5,22 @@ void main() {
inputs.normalizedUV = position.xy * 0.5 + 0.5;
inputs.position = getPosition();
vec4 position = getPosition();
// Invoke user code
postProcessVertex(inputs);
// (vertex domain) GL convention to inverted DX convention
inputs.position.z = inputs.position.z * -0.5 + 0.5;
#if defined(TARGET_VULKAN_ENVIRONMENT)
// In Vulkan, clip space is Y-down. In OpenGL and Metal, clip space is Y-up.
inputs.position.y = -inputs.position.y;
#endif
// GL convention to inverted DX convention
position.z = position.z * -0.5 + 0.5;
// Adjust clip-space
#if !defined(TARGET_VULKAN_ENVIRONMENT) && !defined(TARGET_METAL_ENVIRONMENT)
// This is not needed in Vulkan or Metal because clipControl is always (1, 0)
// (We don't use a dot() here because it works around a spirv-opt optimization that in turn
// (We don't use a dot() here because it workaround a spirv-opt optimization that in turn
// causes a crash on PowerVR, see #5118)
inputs.position.z = inputs.position.z * frameUniforms.clipControl.x + inputs.position.w * frameUniforms.clipControl.y;
position.z = position.z * frameUniforms.clipControl.x + position.w * frameUniforms.clipControl.y;
#endif
// Invoke user code
postProcessVertex(inputs);
// Handle user-defined interpolated attributes
#if defined(VARIABLE_CUSTOM0)
VARIABLE_CUSTOM_AT0 = inputs.VARIABLE_CUSTOM0;
@@ -41,5 +36,5 @@ void main() {
#endif
// some PowerVR drivers crash when gl_Position is written more than once
gl_Position = inputs.position;
gl_Position = position;
}

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