Compare commits

...
Author SHA1 Message Date
Benjamin Doherty 8ed10d77de Begin to refactor test_LoadImage to use SharedShaders 2025-08-12 17:39:26 -04:00
Ben Doherty e8e99a0de6 Fix: webgpu error regarding mismatched pipeline (#9056) 2025-08-11 17:30:07 -04:00
Ben Doherty 6630aa5f36 matp: Remove accidental switch fallthrough (#9082) 2025-08-11 17:26:46 -04:00
Powei Feng bc83ffdcd1 vk: make default render target independent of call order (#9065) 2025-08-11 20:27:53 +00:00
Powei Feng c21f211a13 Update java for Texture::Usage (#9055)
Also update samples and utils to use proper usage when
generating mipmaps.
2025-08-11 19:47:26 +00:00
Patrik Huber 58d4671c24 Fixes to frame_generator sample (#9050)
* [Fix] frame_generator sample: open ifstream with ios::binary
* [Fix] frame_generator sample: allocate storage for g_materialBuffer
   reserve() merely reserves memory, but does not actually change the size of the vector.
* [Fix] frame_generator sample: destroy materials/renderables during cleanup

Otherwise the sample crashes with a Filament error saying that the material is still associated with a renderable.
2025-08-11 19:21:05 +00:00
Mathias Agopian 93caca7245 fig materialparser assert when shader is not present 2025-08-11 11:11:42 -07:00
Mathias Agopian bf77c023b9 correctly set STENCIL Usage on color pass texture
the framegraph didn't set the Usage::Stencil on textures it created
for the color pass if stencil was requested. On the GL backend it
didn't matter because that bit is unused.
2025-08-11 11:11:22 -07:00
yein 95128d5f55 Follow up of material parser PR (#9029)
- Fix CMakeLists to correctly include src files in matp test
- Replace std::string to std::string_view
- Also update the test_includer.cpp
2025-08-11 18:05:10 +00:00
Powei Feng 6d17d858de vk: Fix bad layouts/formats when doing generateMipmaps (#9058)
- After genMipmap, transition to shader read layout
- Ensure that the staging image format is TRANSFER_SRC.
2025-08-11 17:49:15 +00:00
Sungun Park 05003ea358 mat: Add CRC32 validation for material packages (#9053)
This commit introduces a CRC32 checksum to material packages to ensure
data integrity.

When a material is loaded, this checksum is verified. If the check
fails, an error is logged, and the material fails to load. For older
material packages without a CRC32 checksum, a warning is logged and
proceed.

BUGS=[373396840]
2025-08-09 00:03:56 +00:00
Matthew Hoffman 98847d6509 Simplify backend tests' EXPECT_IMAGE invocation. (#9052) 2025-08-08 21:55:37 +00:00
Mathias Agopian d3828cdd1c fix the 3-parameters fresnel calculation
it would automatically degrade to the 2-parameters version in 
LOW_QUALITY mode, but some other code relied on the proper calculation,
in particular when specularFactor was used.


FIXES=[436866605]
2025-08-08 14:18:15 -07:00
Andy Hovingh 4beda6feee wgpu: fix Android build error 2025-08-08 15:32:18 -05:00
Juan Caldas 7cacef9509 Update GLSL for mip test (#9064) 2025-08-08 15:09:27 -04:00
Juan Caldas 5cd7de7318 Change fogReserved 2025-08-08 10:44:54 -07:00
Sungun Park 9c87e72a81 Correct warning message (#9059)
The subsequent call

`glGetShaderiv(shader, GL_COMPILE_STATUS, &status);`

will ensure the compilation is complete.
2025-08-07 22:35:26 -07:00
Filament Bot 652d973ad8 [automated] Updating /docs due to commit 8466177
Full commit hash is 84661777e7

DOCS_ALLOW_DIRECT_EDITS
2025-08-07 22:52:23 +00:00
Ben Doherty 84661777e7 Materials: add useDefaultDepthVariant flag (#9020) 2025-08-07 22:49:05 +00:00
Powei Feng c8ab2f335e Fix places where generateMipmaps is called without proper usage (#9054) 2025-08-07 22:24:40 +00:00
Mathias Agopian db14efc151 compress the DFG LUT with zstd
- use resgen to package the DFG LUT into filament, instead of using
  a large include of a C array.

- add a zstd compression step, which reduces the size from ~100KB to
  ~75KB.

The overhead of zstd is about 90KB uncompressed, however it will pay
for itself tenfold when we use it to compress material packages.
2025-08-07 14:58:18 -07:00
Mathias Agopian d1ca059dad resgen: add compression options
- with `-z` each resource is compressed individually
- with `-Z` the whole package is compressed
2025-08-07 14:58:18 -07:00
Mathias Agopian c71a22914f small improvements to cmgen
- when generating the DFG LUT as a text file, make sure to faithfully
  reproduce the command used in the comments

- add a "bin" format that will output a headerless raw binary of the
  LUT data.
2025-08-07 14:58:18 -07:00
Mathias Agopian 71d0723026 add zstd to the build 2025-08-07 14:58:18 -07:00
Powei Feng 5c371089f2 Add GEN_MIPMAPPABLE TextureUsage (#9042)
This will allow for more backend-specific usage mapping then before - where BLIT_SRC and BLIT_DST are assumed for textures whose mipmaps will be generated.

These mappings have been introduced in metal, vulkan, webgpu.
2025-08-07 18:14:49 +00:00
Konrad Piascik 2c7064e93d webgpu: skip PushConstants backend test for webgpu
We can revert this once dawn supports push constants
2025-08-07 11:07:02 -04:00
Filament Bot 3961989aca [automated] Updating /docs due to commit b92af35
Full commit hash is b92af357f7

DOCS_ALLOW_DIRECT_EDITS
2025-08-07 08:36:16 +00:00
Mathias Agopian b92af357f7 add a material option to use linear fog calculations (#9030)
The new `linearFog` material property, when set to `true` enables a
simplified fog calculation. The fog equation becomes linear which is
unrealistic, but more efficient to compute. In some situations with
a shallow fog range, it doesn't make a huge difference visually.

In this mode, height falloff and in-scattering are ignored.

The linear equation slope is calculated from the regular parameters to
match the slope of the real equation at a camera height. If 
`heightFalloff` is disabled, set to 0, the `density` parameter 
exactly corresponds to the slope of the equation in [1/m] units.
2025-08-07 01:33:36 -07:00
Mathias Agopian f2a1051df9 add CanonicalizePass optimization
this makes all spirv IDs much more stable which greatly improve the
utilization of the line dictionary.
2025-08-07 01:32:31 -07:00
Mathias Agopian 594ab3e9e3 spirv-tools update to vulkan-sdk-1.4.321.0 2025-08-07 01:32:31 -07:00
Mathias Agopian 7f18c7fd43 fix -d (matdbg) build option
There was two problems:
- tint was needed regardless of webgpu support
- libfilamat wasn't built on the android side
  (I don't know how it ever worked)
2025-08-06 17:29:51 -07:00
Powei Feng 9c1a252ba5 Fix two compilation errors (#9041)
- Include <limits> in bitset.h
- The type could not be inferred for Scene.cpp's `SharedState`
  line.  The failure came from clang version 1:14.0-55~exp2
2025-08-06 22:22:40 +00:00
Juan Caldas bf8e798b60 webgpu: Set Layercount to 1 instead of 0 (#9038)
part of BUGS = [424157731]
2025-08-06 22:00:25 +00:00
Eliza Velasquez b94e90416a Fix build breakage 2025-08-06 14:33:53 -07:00
Andy Hovingh e9fde8346e wgpu: fix test seg fault due to null descriptor set layout label 2025-08-06 16:31:44 -05:00
Andy Hovingh 3ae747b544 wgpu: remove assumption default render target is present in makeCurrent(...) 2025-08-06 16:31:44 -05:00
Eliza 5924633085 gl: amortize shader compilation over N frames (#8964)
* gl: amortize shader compilation over N frames

On platforms which don't support parallel shader compilation (e.g. Firefox), we
can sort of emulate it by queueing up any requests to `Material::compile()` and
compiling each shader over multiple frames.

Compiling over consecutive frames slows things quite noticeably. Instead, space
each compilation over a number of ticks (16 chosen arbitrarily).

If we need a program NOW, we can bump a program queued for much later to the
front. We also avoid compiling any queued programs on this same frame to limit
stuttering.

* gl: add flag to disable amortized shader compile

If this flag is on, the new amortized compile code should theoretically never be
executed.

* gl: add CompilerPriorityQueue docs, Java API

* gl: amortize shaders, z3moon feedback

* gl: update CompilerThreadPool
2025-08-06 21:09:27 +00:00
Juan Caldas a07c19e5b7 Add missing WebGPU checks (#9037)
part of BUGS = [424157731]
2025-08-06 16:18:18 -04:00
Filament Bot 59f4d1ba20 [automated] Updating /docs due to commit ac076e8
Full commit hash is ac076e872e

DOCS_ALLOW_DIRECT_EDITS
2025-08-06 06:03:06 +00:00
Powei Feng ac076e872e Release Filament 1.63.0 2025-08-05 22:59:34 -07:00
Matthew Hoffman 9e55331801 Backend tests using webgpu (#8823)
BUGS = [424157731]
2025-08-06 00:19:13 +00:00
Powei Feng f70a11ced4 Feature flag guard compat check of material instance and desc-set (#9035)
This will allow clients more time to correct their code.
2025-08-05 16:34:53 -07:00
Andy Hovingh 455545f024 wgpu: fix ssao bent normals 2025-08-05 16:35:25 -05:00
Andy Hovingh f35ec42125 bilateral blur & shadow map materials require unfilterable samplers
This fixes the Display Shader Texture with the WebGPU implementation.
2025-08-05 16:05:07 -05:00
Powei Feng 4242bc43fd utils: add precond/postcond macro guarded by feature flags
We link the behavior of certain precondition/postcondition checks to feature flag states.

- If provided *flag* is true, then this macro will assert when the *condition* is false.
- If provided *flag* is fase, then this macro will output a warning when the condition is false.
- If the condition is true, then neither of the above will happen

These two macros will enable us to provide less restrictive behavior for certain correctness assertions, allowing clients to modify their before enabling these assertions by default.
2025-08-05 20:48:13 +00:00
Mathias Agopian bbe6d35bf2 fix typo in gtao material 2025-08-05 12:59:24 -07:00
Andy Hovingh c8894521c8 webgpu: add visibility for debugging bind groups via logging (compile-time flag option) 2025-08-05 12:42:40 -05:00
Ben Doherty a2475b5dcb Use default descriptor set for shared material variants (#9025) 2025-08-04 10:27:05 -07:00
Andy Hovingh b7b89168a7 webgpu: support depth in blit + copy when we can. 2025-08-04 10:02:09 -05:00
1059 changed files with 201069 additions and 9325 deletions
+1
View File
@@ -818,6 +818,7 @@ add_subdirectory(${EXTERNAL}/jsmn/tnt)
add_subdirectory(${EXTERNAL}/stb/tnt)
add_subdirectory(${EXTERNAL}/getopt)
add_subdirectory(${EXTERNAL}/perfetto/tnt)
add_subdirectory(${EXTERNAL}/zstd/tnt)
# Note that this has to be placed after mikktspace in order for combine_static_libs to work.
add_subdirectory(${LIBRARIES}/geometry)
+7
View File
@@ -7,3 +7,10 @@ We are chaning the way Vulkan buffers are handled. We need to switch over to a m
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- engine: add a `linearFog` material parameter. [⚠️ **New Material Version**]
- opengl: When `Material::compile()` is called on a platform which doesn't support parallel compilation, shaders are automatically compiled over a number of frames
- engine: Added `useDefaultDepthVariant` material parameter to force Filament to use its default variant for
depth-only passes. [**Requires recompiling materials**]
- material: fix specularFactor in `LOW_QUALITY` mode. [**Requires recompiling materials**] to take effect.
- material: Add CRC32 validation for material packages [⚠️ **New Material Version**]
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.62.2'
implementation 'com.google.android.filament:filament-android:1.63.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.62.2'
pod 'Filament', '~> 1.63.0'
```
## Documentation
+3
View File
@@ -7,6 +7,9 @@ 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.63.1
## v1.63.0
- Rename `sampler` parameter `unfilterable` to `filterable` [⚠️ **New Material Version**]
+9
View File
@@ -67,6 +67,10 @@ add_library(abseil STATIC IMPORTED)
set_target_properties(abseil PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libabseil.a)
add_library(zstd STATIC IMPORTED)
set_target_properties(zstd PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libzstd.a)
if (FILAMENT_ENABLE_FGVIEWER)
add_library(fgviewer STATIC IMPORTED)
set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION
@@ -74,6 +78,10 @@ if (FILAMENT_ENABLE_FGVIEWER)
endif()
if (FILAMENT_ENABLE_MATDBG)
add_library(filamat STATIC IMPORTED)
set_target_properties(filamat PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilamat.a)
add_library(matdbg STATIC IMPORTED)
set_target_properties(matdbg PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libmatdbg.a)
@@ -138,6 +146,7 @@ target_link_libraries(filament-jni
PRIVATE utils
PRIVATE perfetto
PRIVATE abseil
PRIVATE zstd
# libgeometry is PUBLIC because gltfio uses it.
PUBLIC geometry
@@ -239,8 +239,25 @@ public class Material {
FRONT_AND_BACK
}
/**
* Shader compiler priority queue
*
* On platforms which support parallel shader compilation, compilation requests will be
* processed in order of priority, then insertion order.
*
* See {@link #compile(CompilerPriorityQueue, int, Object, Runnable)}.
*/
public enum CompilerPriorityQueue {
/** We need this program NOW.
*
* When passed as an argument to {@link #compile(CompilerPriorityQueue, int, Object,
* Runnable)}, if the platform doesn't support parallel compilation, but does support
* amortized shader compilation, the given shader program will be synchronously compiled.
*/
CRITICAL,
/** We will need this program soon. */
HIGH,
/** We will need this program eventually. */
LOW
}
@@ -911,6 +911,10 @@ public class Texture {
public static final int BLIT_SRC = 0x40;
/** Texture can be used the destination of a blit() */
public static final int BLIT_DST = 0x80;
/** Texture can be used for protected content */
public static final int PROTECTED = 0x0100;
/** Texture can be used with generateMipmaps() */
public static final int GEN_MIPMAPPABLE = 0x0200;
/** by default textures are <code>UPLOADABLE</code> and <code>SAMPLEABLE</code>*/
public static final int DEFAULT = UPLOADABLE | SAMPLEABLE;
}
@@ -1561,7 +1561,9 @@ public class View {
}
/**
* Options to control large-scale fog in the scene
* Options to control large-scale fog in the scene. Materials can enable the `linearFog` property,
* which uses a simplified, linear equation for fog calculation; in this mode, the heightFalloff
* is ignored as well as the mipmap selection in IBL or skyColor mode.
*/
public static class FogOptions {
/**
@@ -1578,7 +1580,7 @@ public class View {
*/
public float cutOffDistance = Float.POSITIVE_INFINITY;
/**
* fog's maximum opacity between 0 and 1
* fog's maximum opacity between 0 and 1. Ignored in `linearFog` mode.
*/
public float maximumOpacity = 1.0f;
/**
@@ -1586,12 +1588,15 @@ public class View {
*/
public float height = 0.0f;
/**
* How fast the fog dissipates with altitude. heightFalloff has a unit of [1/m].
* How fast the fog dissipates with the altitude. heightFalloff has a unit of [1/m].
* It can be expressed as 1/H, where H is the altitude change in world units [m] that causes a
* factor 2.78 (e) change in fog density.
*
* A falloff of 0 means the fog density is constant everywhere and may result is slightly
* faster computations.
*
* In `linearFog` mode, only use to compute the slope of the linear equation. Completely
* ignored if set to 0.
*/
public float heightFalloff = 1.0f;
/**
@@ -1612,7 +1617,7 @@ public class View {
@NonNull @Size(min = 3)
public float[] color = {1.0f, 1.0f, 1.0f};
/**
* Extinction factor in [1/m] at altitude 'height'. The extinction factor controls how much
* Extinction factor in [1/m] at an altitude 'height'. The extinction factor controls how much
* light is absorbed and out-scattered per unit of distance. Each unit of extinction reduces
* the incoming light to 37% of its original value.
*
@@ -1621,10 +1626,15 @@ public class View {
* the composition of the fog/atmosphere.
*
* For historical reason this parameter is called `density`.
*
* In `linearFog` mode this is the slope of the linear equation if heightFalloff is set to 0.
* Otherwise, heightFalloff affects the slope calculation such that it matches the slope of
* the standard equation at the camera height.
*/
public float density = 0.1f;
/**
* Distance in world units [m] from the camera where the Sun in-scattering starts.
* Ignored in `linearFog` mode.
*/
public float inScatteringStart = 0.0f;
/**
@@ -1632,6 +1642,7 @@ public class View {
* is scattered (by the fog) towards the camera.
* Size of the Sun in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100).
* Smaller values result is a larger scattering size.
* Ignored in `linearFog` mode.
*/
public float inScatteringSize = -1.0f;
/**
@@ -1657,6 +1668,8 @@ public class View {
*
* `fogColorFromIbl` is ignored when skyTexture is specified.
*
* In `linearFog` mode mipmap level 0 is always used.
*
* @see Texture
* @see fogColorFromIbl
*/
@@ -1671,7 +1684,7 @@ public class View {
/**
* Options to control Depth of Field (DoF) effect in the scene.
*
* cocScale can be used to set the depth of field blur independently from the camera
* cocScale can be used to set the depth of field blur independently of the camera
* aperture, e.g. for artistic reasons. This can be achieved by setting:
* cocScale = cameraAperture / desiredDoFAperture
*
@@ -60,6 +60,7 @@ jlong nCreateHDRTexture(JNIEnv* env, jclass,
.height(image->getHeight())
.levels(0xff)
.sampler(Texture::Sampler::SAMPLER_2D)
.usage(Texture::Usage::DEFAULT | Texture::Usage::GEN_MIPMAPPABLE)
.format(textureFormat)
.build(*engine);
@@ -46,8 +46,8 @@ fun loadTexture(engine: Engine, resources: Resources, resourceId: Int, type: Tex
.height(bitmap.height)
.sampler(Texture.Sampler.SAMPLER_2D)
.format(internalFormat(type))
// This tells Filament to figure out the number of mip levels
.levels(0xff)
.levels(0xff) // This tells Filament to figure out the number of mip levels
.usage(Texture.Usage.DEFAULT or Texture.Usage.GEN_MIPMAPPABLE)
.build(engine)
// TextureHelper offers a method that skips the copy of the bitmap into a ByteBuffer
+1 -1
View File
@@ -120,7 +120,7 @@ set(GLTFIO_INCLUDE_DIRS
${FILAMENT_DIR}/include
../../filament/backend/include
../../libs/gltfio/include
../../third_party/basisu/zstd
../../third_party/zstd/lib
../../third_party/cgltf
../../third_party/meshoptimizer/src
../../third_party/robin-map
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.62.2
VERSION_NAME=1.63.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
@@ -276,6 +276,7 @@ public class MainActivity extends Activity
.width(bitmap.getWidth())
.height(bitmap.getHeight())
.sampler(Texture.Sampler.SAMPLER_2D)
.usage(Texture.Usage.DEFAULT | Texture.Usage.GEN_MIPMAPPABLE)
.format(Texture.InternalFormat.SRGB8_A8) // It is crucial to use an SRGB format.
.levels(0xff) // tells Filament to figure out the number of mip levels
.build(engine);
+57
View File
@@ -1199,6 +1199,24 @@ material {
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### General: linearFog
Type
: `boolean`
Value
: `true` or `false`. Defaults to `false`.
Description
: When set to `true`, a simplified fog equation is used for large-scale fog calculations. In this mode,
in-scattering is ignored as well as height falloff.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
linearFog : true
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### General: quality
Type
@@ -1263,6 +1281,45 @@ material {
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### General: useDefaultDepthVariant
Type
: `boolean`
Value
: `true` or `false`. Defaults to `false`.
Description
: This parameter forces Filament to use its default variant for depth passes, such as those used
in shadow rendering. This provides an optimization for materials with expensive custom vertex
shaders. For example, custom vertex shader computations intended to be consumed by the fragment
stage can be skipped during the depth-only pass. This parameter is only meaningful if the
material has a vertex block.
This parameter should not be set to `true` for vertex blocks that modify geometry (i.e.,
modifying `worldPosition`), otherwise shadows may render incorrectly.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
variables : [
customColor
],
useDefaultDepthVariant : true
}
vertex {
void materialVertex(inout MaterialVertexInputs material) {
material.customColor = /* expensive computation that can be skipped for depth-only passes */
}
}
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = variable_customColor;
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Vertex and attributes: requires
Type
+3 -2
View File
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.62.2'
implementation 'com.google.android.filament:filament-android:1.63.0'
}
</code></pre>
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
@@ -196,7 +196,7 @@ dependencies {
</div>
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
<p>iOS projects can use CocoaPods to install the latest release:</p>
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.62.2'
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.63.0'
</code></pre>
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
<ul>
@@ -501,6 +501,7 @@ and tools.</p>
<li><code>filamesh</code>: Mesh converter</li>
<li><code>glslminifier</code>: Minifies GLSL source code</li>
<li><code>matc</code>: Material compiler</li>
<li><code>filament-matp</code>: Material parser</li>
<li><code>matinfo</code> Displays information about materials compiled with <code>matc</code></li>
<li><code>mipgen</code> Generates a series of miplevels from a source image</li>
<li><code>normal-blending</code>: Tool to blend normal maps</li>
+3 -2
View File
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.62.2'
implementation 'com.google.android.filament:filament-android:1.63.0'
}
</code></pre>
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
@@ -196,7 +196,7 @@ dependencies {
</div>
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
<p>iOS projects can use CocoaPods to install the latest release:</p>
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.62.2'
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.63.0'
</code></pre>
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
<ul>
@@ -501,6 +501,7 @@ and tools.</p>
<li><code>filamesh</code>: Mesh converter</li>
<li><code>glslminifier</code>: Minifies GLSL source code</li>
<li><code>matc</code>: Material compiler</li>
<li><code>filament-matp</code>: Material parser</li>
<li><code>matinfo</code> Displays information about materials compiled with <code>matc</code></li>
<li><code>mipgen</code> Generates a series of miplevels from a source image</li>
<li><code>normal-blending</code>: Tool to blend normal maps</li>
+103 -62
View File
@@ -235,36 +235,38 @@ counter-increment: h6;margin-right:10px}
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/general:constants" target="_self" class="level3"><span class="tocNumber">4.2.5&nbsp; </span>General: constants</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/general:variantfilter" target="_self" class="level3"><span class="tocNumber">4.2.6&nbsp; </span>General: variantFilter</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/general:flipuv" target="_self" class="level3"><span class="tocNumber">4.2.7&nbsp; </span>General: flipUV</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/general:quality" target="_self" class="level3"><span class="tocNumber">4.2.8&nbsp; </span>General: quality</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/general:instanced" target="_self" class="level3"><span class="tocNumber">4.2.9&nbsp; </span>General: instanced</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/general:vertexdomaindevicejittered" target="_self" class="level3"><span class="tocNumber">4.2.10&nbsp; </span>General: vertexDomainDeviceJittered</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/vertexandattributes:requires" target="_self" class="level3"><span class="tocNumber">4.2.11&nbsp; </span>Vertex and attributes: requires</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/vertexandattributes:variables" target="_self" class="level3"><span class="tocNumber">4.2.12&nbsp; </span>Vertex and attributes: variables</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/vertexandattributes:vertexdomain" target="_self" class="level3"><span class="tocNumber">4.2.13&nbsp; </span>Vertex and attributes: vertexDomain</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/vertexandattributes:interpolation" target="_self" class="level3"><span class="tocNumber">4.2.14&nbsp; </span>Vertex and attributes: interpolation</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:blending" target="_self" class="level3"><span class="tocNumber">4.2.15&nbsp; </span>Blending and transparency: blending</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:blendfunction" target="_self" class="level3"><span class="tocNumber">4.2.16&nbsp; </span>Blending and transparency: blendFunction</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:postlightingblending" target="_self" class="level3"><span class="tocNumber">4.2.17&nbsp; </span>Blending and transparency: postLightingBlending</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:transparency" target="_self" class="level3"><span class="tocNumber">4.2.18&nbsp; </span>Blending and transparency: transparency</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:maskthreshold" target="_self" class="level3"><span class="tocNumber">4.2.19&nbsp; </span>Blending and transparency: maskThreshold</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:refractionmode" target="_self" class="level3"><span class="tocNumber">4.2.20&nbsp; </span>Blending and transparency: refractionMode</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:refractiontype" target="_self" class="level3"><span class="tocNumber">4.2.21&nbsp; </span>Blending and transparency: refractionType</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/rasterization:culling" target="_self" class="level3"><span class="tocNumber">4.2.22&nbsp; </span>Rasterization: culling</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/rasterization:colorwrite" target="_self" class="level3"><span class="tocNumber">4.2.23&nbsp; </span>Rasterization: colorWrite</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/rasterization:depthwrite" target="_self" class="level3"><span class="tocNumber">4.2.24&nbsp; </span>Rasterization: depthWrite</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/rasterization:depthculling" target="_self" class="level3"><span class="tocNumber">4.2.25&nbsp; </span>Rasterization: depthCulling</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/rasterization:doublesided" target="_self" class="level3"><span class="tocNumber">4.2.26&nbsp; </span>Rasterization: doubleSided</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/rasterization:alphatocoverage" target="_self" class="level3"><span class="tocNumber">4.2.27&nbsp; </span>Rasterization: alphaToCoverage</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/lighting:reflections" target="_self" class="level3"><span class="tocNumber">4.2.28&nbsp; </span>Lighting: reflections</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/lighting:shadowmultiplier" target="_self" class="level3"><span class="tocNumber">4.2.29&nbsp; </span>Lighting: shadowMultiplier</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/lighting:transparentshadow" target="_self" class="level3"><span class="tocNumber">4.2.30&nbsp; </span>Lighting: transparentShadow</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/lighting:clearcoatiorchange" target="_self" class="level3"><span class="tocNumber">4.2.31&nbsp; </span>Lighting: clearCoatIorChange</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/lighting:multibounceambientocclusion" target="_self" class="level3"><span class="tocNumber">4.2.32&nbsp; </span>Lighting: multiBounceAmbientOcclusion</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/lighting:specularambientocclusion" target="_self" class="level3"><span class="tocNumber">4.2.33&nbsp; </span>Lighting: specularAmbientOcclusion</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasing" target="_self" class="level3"><span class="tocNumber">4.2.34&nbsp; </span>Anti-aliasing: specularAntiAliasing</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasingvariance" target="_self" class="level3"><span class="tocNumber">4.2.35&nbsp; </span>Anti-aliasing: specularAntiAliasingVariance</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasingthreshold" target="_self" class="level3"><span class="tocNumber">4.2.36&nbsp; </span>Anti-aliasing: specularAntiAliasingThreshold</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/shading:customsurfaceshading" target="_self" class="level3"><span class="tocNumber">4.2.37&nbsp; </span>Shading: customSurfaceShading</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/general:linearfog" target="_self" class="level3"><span class="tocNumber">4.2.8&nbsp; </span>General: linearFog</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/general:quality" target="_self" class="level3"><span class="tocNumber">4.2.9&nbsp; </span>General: quality</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/general:instanced" target="_self" class="level3"><span class="tocNumber">4.2.10&nbsp; </span>General: instanced</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/general:vertexdomaindevicejittered" target="_self" class="level3"><span class="tocNumber">4.2.11&nbsp; </span>General: vertexDomainDeviceJittered</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/general:usedefaultdepthvariant" target="_self" class="level3"><span class="tocNumber">4.2.12&nbsp; </span>General: useDefaultDepthVariant</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/vertexandattributes:requires" target="_self" class="level3"><span class="tocNumber">4.2.13&nbsp; </span>Vertex and attributes: requires</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/vertexandattributes:variables" target="_self" class="level3"><span class="tocNumber">4.2.14&nbsp; </span>Vertex and attributes: variables</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/vertexandattributes:vertexdomain" target="_self" class="level3"><span class="tocNumber">4.2.15&nbsp; </span>Vertex and attributes: vertexDomain</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/vertexandattributes:interpolation" target="_self" class="level3"><span class="tocNumber">4.2.16&nbsp; </span>Vertex and attributes: interpolation</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:blending" target="_self" class="level3"><span class="tocNumber">4.2.17&nbsp; </span>Blending and transparency: blending</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:blendfunction" target="_self" class="level3"><span class="tocNumber">4.2.18&nbsp; </span>Blending and transparency: blendFunction</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:postlightingblending" target="_self" class="level3"><span class="tocNumber">4.2.19&nbsp; </span>Blending and transparency: postLightingBlending</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:transparency" target="_self" class="level3"><span class="tocNumber">4.2.20&nbsp; </span>Blending and transparency: transparency</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:maskthreshold" target="_self" class="level3"><span class="tocNumber">4.2.21&nbsp; </span>Blending and transparency: maskThreshold</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:refractionmode" target="_self" class="level3"><span class="tocNumber">4.2.22&nbsp; </span>Blending and transparency: refractionMode</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/blendingandtransparency:refractiontype" target="_self" class="level3"><span class="tocNumber">4.2.23&nbsp; </span>Blending and transparency: refractionType</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/rasterization:culling" target="_self" class="level3"><span class="tocNumber">4.2.24&nbsp; </span>Rasterization: culling</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/rasterization:colorwrite" target="_self" class="level3"><span class="tocNumber">4.2.25&nbsp; </span>Rasterization: colorWrite</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/rasterization:depthwrite" target="_self" class="level3"><span class="tocNumber">4.2.26&nbsp; </span>Rasterization: depthWrite</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/rasterization:depthculling" target="_self" class="level3"><span class="tocNumber">4.2.27&nbsp; </span>Rasterization: depthCulling</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/rasterization:doublesided" target="_self" class="level3"><span class="tocNumber">4.2.28&nbsp; </span>Rasterization: doubleSided</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/rasterization:alphatocoverage" target="_self" class="level3"><span class="tocNumber">4.2.29&nbsp; </span>Rasterization: alphaToCoverage</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/lighting:reflections" target="_self" class="level3"><span class="tocNumber">4.2.30&nbsp; </span>Lighting: reflections</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/lighting:shadowmultiplier" target="_self" class="level3"><span class="tocNumber">4.2.31&nbsp; </span>Lighting: shadowMultiplier</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/lighting:transparentshadow" target="_self" class="level3"><span class="tocNumber">4.2.32&nbsp; </span>Lighting: transparentShadow</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/lighting:clearcoatiorchange" target="_self" class="level3"><span class="tocNumber">4.2.33&nbsp; </span>Lighting: clearCoatIorChange</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/lighting:multibounceambientocclusion" target="_self" class="level3"><span class="tocNumber">4.2.34&nbsp; </span>Lighting: multiBounceAmbientOcclusion</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/lighting:specularambientocclusion" target="_self" class="level3"><span class="tocNumber">4.2.35&nbsp; </span>Lighting: specularAmbientOcclusion</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasing" target="_self" class="level3"><span class="tocNumber">4.2.36&nbsp; </span>Anti-aliasing: specularAntiAliasing</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasingvariance" target="_self" class="level3"><span class="tocNumber">4.2.37&nbsp; </span>Anti-aliasing: specularAntiAliasingVariance</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasingthreshold" target="_self" class="level3"><span class="tocNumber">4.2.38&nbsp; </span>Anti-aliasing: specularAntiAliasingThreshold</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/shading:customsurfaceshading" target="_self" class="level3"><span class="tocNumber">4.2.39&nbsp; </span>Shading: customSurfaceShading</a><br/>
&nbsp;&nbsp;<a href="#materialdefinitions/vertexblock" target="_self" class="level2"><span class="tocNumber">4.3&nbsp; </span>Vertex block</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/vertexblock/materialvertexinputs" target="_self" class="level3"><span class="tocNumber">4.3.1&nbsp; </span>Material vertex inputs</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/vertexblock/customvertexattributes" target="_self" class="level3"><span class="tocNumber">4.3.2&nbsp; </span>Custom vertex attributes</a><br/>
@@ -731,7 +733,7 @@ Note that the <code>normal</code> property affects the <em class="underscore">ba
<p>
<p>The <code>bentNormal</code> property defines the average unoccluded direction at a point on the surface. It is
used to improve the accuracy of indirect lighting. Bent normals can also improve the quality of
specular ambient occlusion (see section <a href="#toc4.2.33" target="_self">4.2.33</a> about
specular ambient occlusion (see section <a href="#toc4.2.35" target="_self">4.2.35</a> about
<code>specularAmbientOcclusion</code>).</p>
</p><p>
Bent normals can greatly increase the visual fidelity of an asset with various cavities and concave
@@ -810,7 +812,7 @@ light to bend further away from the initial path.
</table><center><div class="tablecaption"><b style="font-style:normal;">Table&nbsp;6:</b> Index of refraction of common materials</div></center></div>
</p><p>
The appearance of a refractive material will greatly depend on the <code>refractionType</code> and
<code>refractionMode</code> settings of the material. Refer to section <a href="#toc4.2.21" target="_self">4.2.21</a> and section <a href="#toc4.2.20" target="_self">4.2.20</a>
<code>refractionMode</code> settings of the material. Refer to section <a href="#toc4.2.23" target="_self">4.2.23</a> and section <a href="#toc4.2.22" target="_self">4.2.22</a>
for more information.
</p><p>
The effect of <code>ior</code> when <code>refractionMode</code> is set to <code>cubemap</code> and <code>refractionType</code> is set to <code>solid</code>
@@ -1400,7 +1402,16 @@ non-shader data.</p>
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> flipUV <span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="general:quality">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/general:quality">&nbsp;</a><a class="target" name="toc4.2.8">&nbsp;</a><h3 id="general-quality"><a class="header" href="#general-quality">General: quality</a></h3>
<a class="target" name="general:linearfog">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/general:linearfog">&nbsp;</a><a class="target" name="toc4.2.8">&nbsp;</a><h3 id="general-linearfog"><a class="header" href="#general-linearfog">General: linearFog</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>boolean</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code>.
</p></dd><dt>Description</dt><dd><p> When set to <code>true</code>, a simplified fog equation is used for large-scale fog calculations. In this mode,
in-scattering is ignored as well as height falloff.
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> linearFog <span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="general:quality">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/general:quality">&nbsp;</a><a class="target" name="toc4.2.9">&nbsp;</a><h3 id="general-quality"><a class="header" href="#general-quality">General: quality</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>string</code>
</p></dd><dt>Value</dt><dd><p> Any of <code>low</code>, <code>normal</code>, <code>high</code>, <code>default</code>. Defaults to <code>default</code>.
@@ -1411,7 +1422,7 @@ non-shader data.</p>
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> quality <span class="hljs-punctuation">:</span> default
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="general:instanced">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/general:instanced">&nbsp;</a><a class="target" name="toc4.2.9">&nbsp;</a><h3 id="general-instanced"><a class="header" href="#general-instanced">General: instanced</a></h3>
<a class="target" name="general:instanced">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/general:instanced">&nbsp;</a><a class="target" name="toc4.2.10">&nbsp;</a><h3 id="general-instanced"><a class="header" href="#general-instanced">General: instanced</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>boolean</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code>.
@@ -1423,7 +1434,7 @@ non-shader data.</p>
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> instanced <span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="general:vertexdomaindevicejittered">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/general:vertexdomaindevicejittered">&nbsp;</a><a class="target" name="toc4.2.10">&nbsp;</a><h3 id="general-vertexdomaindevicejittered"><a class="header" href="#general-vertexdomaindevicejittered">General: vertexDomainDeviceJittered</a></h3>
<a class="target" name="general:vertexdomaindevicejittered">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/general:vertexdomaindevicejittered">&nbsp;</a><a class="target" name="toc4.2.11">&nbsp;</a><h3 id="general-vertexdomaindevicejittered"><a class="header" href="#general-vertexdomaindevicejittered">General: vertexDomainDeviceJittered</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>boolean</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code>.
@@ -1437,7 +1448,37 @@ non-shader data.</p>
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> vertexDomainDeviceJittered <span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="vertexandattributes:requires">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:requires">&nbsp;</a><a class="target" name="toc4.2.11">&nbsp;</a><h3 id="vertex-and-attributes-requires"><a class="header" href="#vertex-and-attributes-requires">Vertex and attributes: requires</a></h3>
<a class="target" name="general:usedefaultdepthvariant">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/general:usedefaultdepthvariant">&nbsp;</a><a class="target" name="toc4.2.12">&nbsp;</a><h3 id="general-usedefaultdepthvariant"><a class="header" href="#general-usedefaultdepthvariant">General: useDefaultDepthVariant</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>boolean</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code>.
</p></dd><dt>Description</dt><dd><p> This parameter forces Filament to use its default variant for depth passes, such as those used
in shadow rendering. This provides an optimization for materials with expensive custom vertex
shaders. For example, custom vertex shader computations intended to be consumed by the fragment
stage can be skipped during the depth-only pass. This parameter is only meaningful if the
material has a vertex block.
This parameter should not be set to <code>true</code> for vertex blocks that modify geometry (i.e.,
modifying <code>worldPosition</code>), otherwise shadows may render incorrectly.
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> variables <span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
<span class="line"></span> customColor
<span class="line"></span> <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
<span class="line"></span> useDefaultDepthVariant <span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span>
<span class="line"></span><span class="hljs-punctuation">}</span>
<span class="line"></span>
<span class="line"></span>vertex <span class="hljs-punctuation">{</span>
<span class="line"></span> void materialVertex(inout MaterialVertexInputs material) <span class="hljs-punctuation">{</span>
<span class="line"></span> material.customColor = <span class="hljs-comment">/* expensive computation that can be skipped for depth-only passes */</span>
<span class="line"></span> <span class="hljs-punctuation">}</span>
<span class="line"></span><span class="hljs-punctuation">}</span>
<span class="line"></span>
<span class="line"></span>fragment <span class="hljs-punctuation">{</span>
<span class="line"></span> void material(inout MaterialInputs material) <span class="hljs-punctuation">{</span>
<span class="line"></span> prepareMaterial(material);
<span class="line"></span> material.baseColor = variable_customColor;
<span class="line"></span> <span class="hljs-punctuation">}</span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="vertexandattributes:requires">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:requires">&nbsp;</a><a class="target" name="toc4.2.13">&nbsp;</a><h3 id="vertex-and-attributes-requires"><a class="header" href="#vertex-and-attributes-requires">Vertex and attributes: requires</a></h3>
<p>
<dl><dt>Type</dt><dd><p> array of <code>string</code>
</p></dd><dt>Value</dt><dd><p> Each entry must be any of <code>uv0</code>, <code>uv1</code>, <code>color</code>, <code>position</code>, <code>tangents</code>, <code>custom0</code>
@@ -1470,7 +1511,7 @@ non-shader data.</p>
<span class="line"></span> material.baseColor.rgb *= getCustom0().rgb;
<span class="line"></span> <span class="hljs-punctuation">}</span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="vertexandattributes:variables">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:variables">&nbsp;</a><a class="target" name="toc4.2.12">&nbsp;</a><h3 id="vertex-and-attributes-variables"><a class="header" href="#vertex-and-attributes-variables">Vertex and attributes: variables</a></h3>
<a class="target" name="vertexandattributes:variables">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:variables">&nbsp;</a><a class="target" name="toc4.2.14">&nbsp;</a><h3 id="vertex-and-attributes-variables"><a class="header" href="#vertex-and-attributes-variables">Vertex and attributes: variables</a></h3>
<p>
<dl><dt>Type</dt><dd><p> array of <code>string</code>
</p></dd><dt>Value</dt><dd><p> Up to 5 strings, each must be a valid GLSL identifier.
@@ -1525,7 +1566,7 @@ non-shader data.</p>
<span class="line"></span> material.eyeDirection.xyz = mulMat3x3Float3(getWorldFromViewMatrix()<span class="hljs-punctuation">,</span> u);
<span class="line"></span> <span class="hljs-punctuation">}</span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="vertexandattributes:vertexdomain">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:vertexdomain">&nbsp;</a><a class="target" name="toc4.2.13">&nbsp;</a><h3 id="vertex-and-attributes-vertexdomain"><a class="header" href="#vertex-and-attributes-vertexdomain">Vertex and attributes: vertexDomain</a></h3>
<a class="target" name="vertexandattributes:vertexdomain">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:vertexdomain">&nbsp;</a><a class="target" name="toc4.2.15">&nbsp;</a><h3 id="vertex-and-attributes-vertexdomain"><a class="header" href="#vertex-and-attributes-vertexdomain">Vertex and attributes: vertexDomain</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>string</code>
</p></dd><dt>Value</dt><dd><p> Any of <code>object</code>, <code>world</code>, <code>view</code>, <code>device</code>. Defaults to <code>object</code>.
@@ -1547,7 +1588,7 @@ non-shader data.</p>
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> vertexDomain <span class="hljs-punctuation">:</span> device
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="vertexandattributes:interpolation">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:interpolation">&nbsp;</a><a class="target" name="toc4.2.14">&nbsp;</a><h3 id="vertex-and-attributes-interpolation"><a class="header" href="#vertex-and-attributes-interpolation">Vertex and attributes: interpolation</a></h3>
<a class="target" name="vertexandattributes:interpolation">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:interpolation">&nbsp;</a><a class="target" name="toc4.2.16">&nbsp;</a><h3 id="vertex-and-attributes-interpolation"><a class="header" href="#vertex-and-attributes-interpolation">Vertex and attributes: interpolation</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>string</code>
</p></dd><dt>Value</dt><dd><p> Any of <code>smooth</code>, <code>flat</code>. Defaults to <code>smooth</code>.
@@ -1558,7 +1599,7 @@ non-shader data.</p>
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> interpolation <span class="hljs-punctuation">:</span> flat
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="blendingandtransparency:blending">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:blending">&nbsp;</a><a class="target" name="toc4.2.15">&nbsp;</a><h3 id="blending-and-transparency-blending"><a class="header" href="#blending-and-transparency-blending">Blending and transparency: blending</a></h3>
<a class="target" name="blendingandtransparency:blending">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:blending">&nbsp;</a><a class="target" name="toc4.2.17">&nbsp;</a><h3 id="blending-and-transparency-blending"><a class="header" href="#blending-and-transparency-blending">Blending and transparency: blending</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>string</code>
</p></dd><dt>Value</dt><dd><p> Any of <code>opaque</code>, <code>transparent</code>, <code>fade</code>, <code>add</code>, <code>masked</code>, <code>multiply</code>, <code>screen</code>, <code>custom</code>. Defaults to <code>opaque</code>.
@@ -1597,7 +1638,7 @@ non-shader data.</p>
</p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> blending <span class="hljs-punctuation">:</span> transparent
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="blendingandtransparency:blendfunction">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:blendfunction">&nbsp;</a><a class="target" name="toc4.2.16">&nbsp;</a><h3 id="blending-and-transparency-blendfunction"><a class="header" href="#blending-and-transparency-blendfunction">Blending and transparency: blendFunction</a></h3>
<a class="target" name="blendingandtransparency:blendfunction">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:blendfunction">&nbsp;</a><a class="target" name="toc4.2.18">&nbsp;</a><h3 id="blending-and-transparency-blendfunction"><a class="header" href="#blending-and-transparency-blendfunction">Blending and transparency: blendFunction</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>object</code>
</p></dd><dt>Fields</dt><dd><p> <code>srcRGB</code>, <code>srcA</code>, <code>dstRGB</code>, <code>dstA</code>
@@ -1618,7 +1659,7 @@ non-shader data.</p>
<span class="line"></span> dstA<span class="hljs-punctuation">:</span> oneMinusSrcAlpha
<span class="line"></span> <span class="hljs-punctuation">}</span>
<span class="line"></span> <span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="blendingandtransparency:postlightingblending">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:postlightingblending">&nbsp;</a><a class="target" name="toc4.2.17">&nbsp;</a><h3 id="blending-and-transparency-postlightingblending"><a class="header" href="#blending-and-transparency-postlightingblending">Blending and transparency: postLightingBlending</a></h3>
<a class="target" name="blendingandtransparency:postlightingblending">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:postlightingblending">&nbsp;</a><a class="target" name="toc4.2.19">&nbsp;</a><h3 id="blending-and-transparency-postlightingblending"><a class="header" href="#blending-and-transparency-postlightingblending">Blending and transparency: postLightingBlending</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>string</code>
</p></dd><dt>Value</dt><dd><p> Any of <code>opaque</code>, <code>transparent</code>, <code>add</code>. Defaults to <code>transparent</code>.
@@ -1641,7 +1682,7 @@ non-shader data.</p>
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> postLightingBlending <span class="hljs-punctuation">:</span> add
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="blendingandtransparency:transparency">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:transparency">&nbsp;</a><a class="target" name="toc4.2.18">&nbsp;</a><h3 id="blending-and-transparency-transparency"><a class="header" href="#blending-and-transparency-transparency">Blending and transparency: transparency</a></h3>
<a class="target" name="blendingandtransparency:transparency">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:transparency">&nbsp;</a><a class="target" name="toc4.2.20">&nbsp;</a><h3 id="blending-and-transparency-transparency"><a class="header" href="#blending-and-transparency-transparency">Blending and transparency: transparency</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>string</code>
</p></dd><dt>Value</dt><dd><p> Any of <code>default</code>, <code>twoPassesOneSide</code> or <code>twoPassesTwoSides</code>. Defaults to <code>default</code>.
@@ -1674,7 +1715,7 @@ non-shader data.</p>
<center><div class="image" style=""><a class="target" name="figure_transparencytwopassestwosides">&nbsp;</a><a href="../images/screenshot_twopasses_twosides.png" target="_blank"><img class="markdeep" src="../images/screenshot_twopasses_twosides.png" /></a><center><span class="imagecaption"><b style="font-style:normal;">Figure&nbsp;35:</b> In <code>twoPassesTwoSides</code> mode, both set of faces are visible
</span></center></div></center>
</p>
<a class="target" name="blendingandtransparency:maskthreshold">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:maskthreshold">&nbsp;</a><a class="target" name="toc4.2.19">&nbsp;</a><h3 id="blending-and-transparency-maskthreshold"><a class="header" href="#blending-and-transparency-maskthreshold">Blending and transparency: maskThreshold</a></h3>
<a class="target" name="blendingandtransparency:maskthreshold">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:maskthreshold">&nbsp;</a><a class="target" name="toc4.2.21">&nbsp;</a><h3 id="blending-and-transparency-maskthreshold"><a class="header" href="#blending-and-transparency-maskthreshold">Blending and transparency: maskThreshold</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>number</code>
</p></dd><dt>Value</dt><dd><p> A value between <code>0.0</code> and <code>1.0</code>. Defaults to <code>0.4</code>.
@@ -1686,7 +1727,7 @@ non-shader data.</p>
<span class="line"></span> blending <span class="hljs-punctuation">:</span> masked<span class="hljs-punctuation">,</span>
<span class="line"></span> maskThreshold <span class="hljs-punctuation">:</span> <span class="hljs-number">0.5</span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="blendingandtransparency:refractionmode">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:refractionmode">&nbsp;</a><a class="target" name="toc4.2.20">&nbsp;</a><h3 id="blending-and-transparency-refractionmode"><a class="header" href="#blending-and-transparency-refractionmode">Blending and transparency: refractionMode</a></h3>
<a class="target" name="blendingandtransparency:refractionmode">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:refractionmode">&nbsp;</a><a class="target" name="toc4.2.22">&nbsp;</a><h3 id="blending-and-transparency-refractionmode"><a class="header" href="#blending-and-transparency-refractionmode">Blending and transparency: refractionMode</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>string</code>
</p></dd><dt>Value</dt><dd><p> Any of <code>none</code>, <code>cubemap</code>, <code>screenspace</code>. Defaults to <code>none</code>.
@@ -1702,7 +1743,7 @@ non-shader data.</p>
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> refractionMode <span class="hljs-punctuation">:</span> cubemap<span class="hljs-punctuation">,</span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="blendingandtransparency:refractiontype">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:refractiontype">&nbsp;</a><a class="target" name="toc4.2.21">&nbsp;</a><h3 id="blending-and-transparency-refractiontype"><a class="header" href="#blending-and-transparency-refractiontype">Blending and transparency: refractionType</a></h3>
<a class="target" name="blendingandtransparency:refractiontype">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:refractiontype">&nbsp;</a><a class="target" name="toc4.2.23">&nbsp;</a><h3 id="blending-and-transparency-refractiontype"><a class="header" href="#blending-and-transparency-refractiontype">Blending and transparency: refractionType</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>string</code>
</p></dd><dt>Value</dt><dd><p> Any of <code>solid</code>, <code>thin</code>. Defaults to <code>solid</code>.
@@ -1716,7 +1757,7 @@ non-shader data.</p>
<span class="line"></span> refractionMode <span class="hljs-punctuation">:</span> cubemap<span class="hljs-punctuation">,</span>
<span class="line"></span> refractionType <span class="hljs-punctuation">:</span> thin<span class="hljs-punctuation">,</span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="rasterization:culling">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/rasterization:culling">&nbsp;</a><a class="target" name="toc4.2.22">&nbsp;</a><h3 id="rasterization-culling"><a class="header" href="#rasterization-culling">Rasterization: culling</a></h3>
<a class="target" name="rasterization:culling">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/rasterization:culling">&nbsp;</a><a class="target" name="toc4.2.24">&nbsp;</a><h3 id="rasterization-culling"><a class="header" href="#rasterization-culling">Rasterization: culling</a></h3>
<p>
<dl><table><tr valign=top><td><dt>Type</dt></td><td><dd><p> <code>string</code>
</p></dd></td></tr><tr valign=top><td><dt>Value</dt></td><td><dd><p> Any of <code>none</code>, <code>front</code>, <code>back</code>, <code>frontAndBack</code>. Defaults to <code>back</code>.
@@ -1725,7 +1766,7 @@ non-shader data.</p>
</p></dd></td></tr></table></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> culling <span class="hljs-punctuation">:</span> none
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="rasterization:colorwrite">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/rasterization:colorwrite">&nbsp;</a><a class="target" name="toc4.2.23">&nbsp;</a><h3 id="rasterization-colorwrite"><a class="header" href="#rasterization-colorwrite">Rasterization: colorWrite</a></h3>
<a class="target" name="rasterization:colorwrite">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/rasterization:colorwrite">&nbsp;</a><a class="target" name="toc4.2.25">&nbsp;</a><h3 id="rasterization-colorwrite"><a class="header" href="#rasterization-colorwrite">Rasterization: colorWrite</a></h3>
<p>
<dl><table><tr valign=top><td><dt>Type</dt></td><td><dd><p> <code>boolean</code>
</p></dd></td></tr><tr valign=top><td><dt>Value</dt></td><td><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>true</code>.
@@ -1733,7 +1774,7 @@ non-shader data.</p>
</p></dd></td></tr></table></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> colorWrite <span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="rasterization:depthwrite">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/rasterization:depthwrite">&nbsp;</a><a class="target" name="toc4.2.24">&nbsp;</a><h3 id="rasterization-depthwrite"><a class="header" href="#rasterization-depthwrite">Rasterization: depthWrite</a></h3>
<a class="target" name="rasterization:depthwrite">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/rasterization:depthwrite">&nbsp;</a><a class="target" name="toc4.2.26">&nbsp;</a><h3 id="rasterization-depthwrite"><a class="header" href="#rasterization-depthwrite">Rasterization: depthWrite</a></h3>
<p>
<dl><table><tr valign=top><td><dt>Type</dt></td><td><dd><p> <code>boolean</code>
</p></dd></td></tr><tr valign=top><td><dt>Value</dt></td><td><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>true</code> for opaque materials, <code>false</code> for transparent materials.
@@ -1741,7 +1782,7 @@ non-shader data.</p>
</p></dd></td></tr></table></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> depthWrite <span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="rasterization:depthculling">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/rasterization:depthculling">&nbsp;</a><a class="target" name="toc4.2.25">&nbsp;</a><h3 id="rasterization-depthculling"><a class="header" href="#rasterization-depthculling">Rasterization: depthCulling</a></h3>
<a class="target" name="rasterization:depthculling">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/rasterization:depthculling">&nbsp;</a><a class="target" name="toc4.2.27">&nbsp;</a><h3 id="rasterization-depthculling"><a class="header" href="#rasterization-depthculling">Rasterization: depthCulling</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>boolean</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>true</code>.
@@ -1750,7 +1791,7 @@ non-shader data.</p>
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> depthCulling <span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="rasterization:doublesided">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/rasterization:doublesided">&nbsp;</a><a class="target" name="toc4.2.26">&nbsp;</a><h3 id="rasterization-doublesided"><a class="header" href="#rasterization-doublesided">Rasterization: doubleSided</a></h3>
<a class="target" name="rasterization:doublesided">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/rasterization:doublesided">&nbsp;</a><a class="target" name="toc4.2.28">&nbsp;</a><h3 id="rasterization-doublesided"><a class="header" href="#rasterization-doublesided">Rasterization: doubleSided</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>boolean</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code>.
@@ -1770,7 +1811,7 @@ non-shader data.</p>
<span class="line"></span> material.baseColor = materialParams.albedo;
<span class="line"></span> <span class="hljs-punctuation">}</span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="rasterization:alphatocoverage">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/rasterization:alphatocoverage">&nbsp;</a><a class="target" name="toc4.2.27">&nbsp;</a><h3 id="rasterization-alphatocoverage"><a class="header" href="#rasterization-alphatocoverage">Rasterization: alphaToCoverage</a></h3>
<a class="target" name="rasterization:alphatocoverage">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/rasterization:alphatocoverage">&nbsp;</a><a class="target" name="toc4.2.29">&nbsp;</a><h3 id="rasterization-alphatocoverage"><a class="header" href="#rasterization-alphatocoverage">Rasterization: alphaToCoverage</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>boolean</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code>.
@@ -1792,7 +1833,7 @@ non-shader data.</p>
<span class="line"></span> material.baseColor = materialParams.albedo;
<span class="line"></span> <span class="hljs-punctuation">}</span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="lighting:reflections">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:reflections">&nbsp;</a><a class="target" name="toc4.2.28">&nbsp;</a><h3 id="lighting-reflections"><a class="header" href="#lighting-reflections">Lighting: reflections</a></h3>
<a class="target" name="lighting:reflections">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:reflections">&nbsp;</a><a class="target" name="toc4.2.30">&nbsp;</a><h3 id="lighting-reflections"><a class="header" href="#lighting-reflections">Lighting: reflections</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>string</code>
</p></dd><dt>Value</dt><dd><p> <code>default</code> or <code>screenspace</code>. Defaults to <code>default</code>.
@@ -1804,7 +1845,7 @@ non-shader data.</p>
<span class="line"></span> name <span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Glossy metal&quot;</span><span class="hljs-punctuation">,</span>
<span class="line"></span> reflections <span class="hljs-punctuation">:</span> screenspace
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="lighting:shadowmultiplier">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:shadowmultiplier">&nbsp;</a><a class="target" name="toc4.2.29">&nbsp;</a><h3 id="lighting-shadowmultiplier"><a class="header" href="#lighting-shadowmultiplier">Lighting: shadowMultiplier</a></h3>
<a class="target" name="lighting:shadowmultiplier">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:shadowmultiplier">&nbsp;</a><a class="target" name="toc4.2.31">&nbsp;</a><h3 id="lighting-shadowmultiplier"><a class="header" href="#lighting-shadowmultiplier">Lighting: shadowMultiplier</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>boolean</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code>.
@@ -1826,7 +1867,7 @@ non-shader data.</p>
<span class="line"></span> material.baseColor = vec4(<span class="hljs-number">0.0</span><span class="hljs-punctuation">,</span> <span class="hljs-number">0.0</span><span class="hljs-punctuation">,</span> <span class="hljs-number">0.0</span><span class="hljs-punctuation">,</span> <span class="hljs-number">0.7</span>);
<span class="line"></span> <span class="hljs-punctuation">}</span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="lighting:transparentshadow">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:transparentshadow">&nbsp;</a><a class="target" name="toc4.2.30">&nbsp;</a><h3 id="lighting-transparentshadow"><a class="header" href="#lighting-transparentshadow">Lighting: transparentShadow</a></h3>
<a class="target" name="lighting:transparentshadow">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:transparentshadow">&nbsp;</a><a class="target" name="toc4.2.32">&nbsp;</a><h3 id="lighting-transparentshadow"><a class="header" href="#lighting-transparentshadow">Lighting: transparentShadow</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>boolean</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code>.
@@ -1852,7 +1893,7 @@ non-shader data.</p>
<center><div class="image" style=""><a class="target" name="figure_transparentshadow">&nbsp;</a><a href="../images/screenshot_transparent_shadows.jpg" target="_blank"><img class="markdeep" src="../images/screenshot_transparent_shadows.jpg" /></a><center><span class="imagecaption"><b style="font-style:normal;">Figure&nbsp;36:</b> Objects rendered with transparent shadows and blurry VSM with a
</span></center></div></center>
</p>
<a class="target" name="lighting:clearcoatiorchange">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:clearcoatiorchange">&nbsp;</a><a class="target" name="toc4.2.31">&nbsp;</a><h3 id="lighting-clearcoatiorchange"><a class="header" href="#lighting-clearcoatiorchange">Lighting: clearCoatIorChange</a></h3>
<a class="target" name="lighting:clearcoatiorchange">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:clearcoatiorchange">&nbsp;</a><a class="target" name="toc4.2.33">&nbsp;</a><h3 id="lighting-clearcoatiorchange"><a class="header" href="#lighting-clearcoatiorchange">Lighting: clearCoatIorChange</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>boolean</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>true</code>.
@@ -1866,7 +1907,7 @@ non-shader data.</p>
<center><div class="image" style=""><a class="target" name="figure_clearcoatiorchange">&nbsp;</a><a href="../images/screenshot_clear_coat_ior_change.jpg" target="_blank"><img class="markdeep" src="../images/screenshot_clear_coat_ior_change.jpg" /></a><center><span class="imagecaption"><b style="font-style:normal;">Figure&nbsp;37:</b> The same rough metallic ball with a clear coat layer rendered
</span></center></div></center>
</p>
<a class="target" name="lighting:multibounceambientocclusion">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:multibounceambientocclusion">&nbsp;</a><a class="target" name="toc4.2.32">&nbsp;</a><h3 id="lighting-multibounceambientocclusion"><a class="header" href="#lighting-multibounceambientocclusion">Lighting: multiBounceAmbientOcclusion</a></h3>
<a class="target" name="lighting:multibounceambientocclusion">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:multibounceambientocclusion">&nbsp;</a><a class="target" name="toc4.2.34">&nbsp;</a><h3 id="lighting-multibounceambientocclusion"><a class="header" href="#lighting-multibounceambientocclusion">Lighting: multiBounceAmbientOcclusion</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>boolean</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code> on mobile, <code>true</code> on desktop.
@@ -1886,7 +1927,7 @@ non-shader data.</p>
<center><div class="image" style=""><a class="target" name="figure_multibounceaoanimated">&nbsp;</a><a href="../images/screenshot_multi_bounce_ao.gif" target="_blank"><img class="markdeep" src="../images/screenshot_multi_bounce_ao.gif" /></a><center><span class="imagecaption"><b style="font-style:normal;">Figure&nbsp;39:</b> Brick texture rendered with multi-bounce ambient
</span></center></div></center>
</p>
<a class="target" name="lighting:specularambientocclusion">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:specularambientocclusion">&nbsp;</a><a class="target" name="toc4.2.33">&nbsp;</a><h3 id="lighting-specularambientocclusion"><a class="header" href="#lighting-specularambientocclusion">Lighting: specularAmbientOcclusion</a></h3>
<a class="target" name="lighting:specularambientocclusion">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:specularambientocclusion">&nbsp;</a><a class="target" name="toc4.2.35">&nbsp;</a><h3 id="lighting-specularambientocclusion"><a class="header" href="#lighting-specularambientocclusion">Lighting: specularAmbientOcclusion</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>string</code>
</p></dd><dt>Value</dt><dd><p> <code>none</code>, <code>simple</code> or <code>bentNormals</code>. Defaults to <code>none</code> on mobile, <code>simple</code> on desktop. For
@@ -1905,7 +1946,7 @@ non-shader data.</p>
<center><div class="image" style=""><a class="target" name="figure_specularao">&nbsp;</a><a href="../images/screenshot_specular_ao.gif" target="_blank"><img class="markdeep" src="../images/screenshot_specular_ao.gif" /></a><center><span class="imagecaption"><b style="font-style:normal;">Figure&nbsp;40:</b> Comparison of specular ambient occlusion on and off. The effect is
</span></center></div></center>
</p>
<a class="target" name="anti-aliasing:specularantialiasing">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/anti-aliasing:specularantialiasing">&nbsp;</a><a class="target" name="toc4.2.34">&nbsp;</a><h3 id="anti-aliasing-specularantialiasing"><a class="header" href="#anti-aliasing-specularantialiasing">Anti-aliasing: specularAntiAliasing</a></h3>
<a class="target" name="anti-aliasing:specularantialiasing">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/anti-aliasing:specularantialiasing">&nbsp;</a><a class="target" name="toc4.2.36">&nbsp;</a><h3 id="anti-aliasing-specularantialiasing"><a class="header" href="#anti-aliasing-specularantialiasing">Anti-aliasing: specularAntiAliasing</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>boolean</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code>.
@@ -1917,7 +1958,7 @@ non-shader data.</p>
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> specularAntiAliasing <span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="anti-aliasing:specularantialiasingvariance">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/anti-aliasing:specularantialiasingvariance">&nbsp;</a><a class="target" name="toc4.2.35">&nbsp;</a><h3 id="anti-aliasing-specularantialiasingvariance"><a class="header" href="#anti-aliasing-specularantialiasingvariance">Anti-aliasing: specularAntiAliasingVariance</a></h3>
<a class="target" name="anti-aliasing:specularantialiasingvariance">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/anti-aliasing:specularantialiasingvariance">&nbsp;</a><a class="target" name="toc4.2.37">&nbsp;</a><h3 id="anti-aliasing-specularantialiasingvariance"><a class="header" href="#anti-aliasing-specularantialiasingvariance">Anti-aliasing: specularAntiAliasingVariance</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>float</code>
</p></dd><dt>Value</dt><dd><p> A value between 0 and 1, set to 0.15 by default.
@@ -1927,7 +1968,7 @@ non-shader data.</p>
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> specularAntiAliasingVariance <span class="hljs-punctuation">:</span> <span class="hljs-number">0.2</span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="anti-aliasing:specularantialiasingthreshold">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/anti-aliasing:specularantialiasingthreshold">&nbsp;</a><a class="target" name="toc4.2.36">&nbsp;</a><h3 id="anti-aliasing-specularantialiasingthreshold"><a class="header" href="#anti-aliasing-specularantialiasingthreshold">Anti-aliasing: specularAntiAliasingThreshold</a></h3>
<a class="target" name="anti-aliasing:specularantialiasingthreshold">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/anti-aliasing:specularantialiasingthreshold">&nbsp;</a><a class="target" name="toc4.2.38">&nbsp;</a><h3 id="anti-aliasing-specularantialiasingthreshold"><a class="header" href="#anti-aliasing-specularantialiasingthreshold">Anti-aliasing: specularAntiAliasingThreshold</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>float</code>
</p></dd><dt>Value</dt><dd><p> A value between 0 and 1, set to 0.2 by default.
@@ -1936,7 +1977,7 @@ non-shader data.</p>
</p></dd></dl></p><pre class="listing tilde"><code><span class="line"></span>material <span class="hljs-punctuation">{</span>
<span class="line"></span> specularAntiAliasingThreshold <span class="hljs-punctuation">:</span> <span class="hljs-number">0.1</span>
<span class="line"></span><span class="hljs-punctuation">}</span></code></pre>
<a class="target" name="shading:customsurfaceshading">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/shading:customsurfaceshading">&nbsp;</a><a class="target" name="toc4.2.37">&nbsp;</a><h3 id="shading-customsurfaceshading"><a class="header" href="#shading-customsurfaceshading">Shading: customSurfaceShading</a></h3>
<a class="target" name="shading:customsurfaceshading">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/shading:customsurfaceshading">&nbsp;</a><a class="target" name="toc4.2.39">&nbsp;</a><h3 id="shading-customsurfaceshading"><a class="header" href="#shading-customsurfaceshading">Shading: customSurfaceShading</a></h3>
<p>
<dl><dt>Type</dt><dd><p> <code>bool</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code>.
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+57
View File
@@ -1199,6 +1199,24 @@ material {
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### General: linearFog
Type
: `boolean`
Value
: `true` or `false`. Defaults to `false`.
Description
: When set to `true`, a simplified fog equation is used for large-scale fog calculations. In this mode,
in-scattering is ignored as well as height falloff.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
linearFog : true
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### General: quality
Type
@@ -1263,6 +1281,45 @@ material {
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### General: useDefaultDepthVariant
Type
: `boolean`
Value
: `true` or `false`. Defaults to `false`.
Description
: This parameter forces Filament to use its default variant for depth passes, such as those used
in shadow rendering. This provides an optimization for materials with expensive custom vertex
shaders. For example, custom vertex shader computations intended to be consumed by the fragment
stage can be skipped during the depth-only pass. This parameter is only meaningful if the
material has a vertex block.
This parameter should not be set to `true` for vertex blocks that modify geometry (i.e.,
modifying `worldPosition`), otherwise shadows may render incorrectly.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
variables : [
customColor
],
useDefaultDepthVariant : true
}
vertex {
void materialVertex(inout MaterialVertexInputs material) {
material.customColor = /* expensive computation that can be skipped for depth-only passes */
}
}
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = variable_customColor;
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Vertex and attributes: requires
Type
+26 -11
View File
@@ -152,6 +152,7 @@ set(SRCS
src/fg/PassNode.cpp
src/fg/ResourceNode.cpp
src/fsr.cpp
src/ZstdHelper.cpp
)
set(PRIVATE_HDRS
@@ -235,6 +236,7 @@ set(PRIVATE_HDRS
src/materials/fsr/ffx_a.h
src/materials/fsr/ffx_fsr1.h
src/materials/fsr/ffx_fsr1_mobile.fs
src/ZstdHelper.h
)
set(MATERIAL_SRCS
@@ -605,6 +607,28 @@ add_custom_command(
APPEND
)
file(MAKE_DIRECTORY "${GENERATION_ROOT}/generated/data/")
set(output_path_dfg_bin "${GENERATION_ROOT}/generated/data/dfg.bin")
add_custom_command(
OUTPUT ${output_path_dfg_bin}
COMMAND cmgen --quiet --size=${DFG_LUT_SIZE} --ibl-dfg-multiscatter --ibl-dfg-cloth --ibl-dfg=${output_path_dfg_bin}
DEPENDS cmgen
COMMENT "Generating DFG LUT to ${output_path_dfg_bin}"
)
set(dfg_package_name "dfg")
get_resgen_vars(${RESOURCE_DIR} ${dfg_package_name})
add_custom_command(
OUTPUT ${RESGEN_OUTPUTS}
COMMAND resgen ${RESGEN_FLAGS} -Z ${output_path_dfg_bin}
DEPENDS resgen
DEPENDS ${output_path_dfg_bin}
COMMENT "Generating DFG resource package for ${dfg_package_name}"
)
list(APPEND GENERATED_RESOURCE_HDRS ${RESGEN_HEADER})
list(APPEND GENERATED_RESOURCE_SRCS ${RESGEN_SOURCE})
# Add the generated resource files to the source and header lists.
list(APPEND PRIVATE_HDRS ${GENERATED_RESOURCE_HDRS})
list(APPEND SRCS ${GENERATED_RESOURCE_SRCS})
@@ -613,16 +637,6 @@ if (DEFINED RESGEN_SOURCE_FLAGS)
set_source_files_properties(${GENERATED_RESOURCE_SRCS} PROPERTIES COMPILE_FLAGS ${RESGEN_SOURCE_FLAGS})
endif()
file(MAKE_DIRECTORY "${GENERATION_ROOT}/generated/data/")
set(output_path "${GENERATION_ROOT}/generated/data/dfg.inc")
add_custom_command(
OUTPUT ${output_path}
COMMAND cmgen --quiet --size=${DFG_LUT_SIZE} --ibl-dfg-multiscatter --ibl-dfg-cloth --ibl-dfg=${output_path}
DEPENDS cmgen
COMMENT "Generating DFG LUT ${output_path}"
)
list(APPEND DATA_BINS ${output_path})
# ==================================================================================================
# Includes & target definition
@@ -633,7 +647,7 @@ include_directories(${GENERATION_ROOT})
include_directories(src)
# we're building a library
add_library(${TARGET} STATIC ${PRIVATE_HDRS} ${PUBLIC_HDRS} ${SRCS} ${DATA_BINS})
add_library(${TARGET} STATIC ${PRIVATE_HDRS} ${PUBLIC_HDRS} ${SRCS})
# specify where the public headers of this library are
target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
@@ -650,6 +664,7 @@ target_link_libraries(${TARGET} PUBLIC math)
target_link_libraries(${TARGET} PUBLIC utils)
target_link_libraries(${TARGET} PUBLIC filaflat)
target_link_libraries(${TARGET} PUBLIC filabridge)
target_link_libraries(${TARGET} PRIVATE zstd)
if (FILAMENT_USE_ABSEIL_LOGGING)
target_link_libraries(${TARGET} PUBLIC absl::log)
@@ -672,9 +672,21 @@ enum class Precision : uint8_t {
/**
* Shader compiler priority queue
*
* On platforms which support parallel shader compilation, compilation requests will be processed in
* order of priority, then insertion order. See Material::compile().
*/
enum class CompilerPriorityQueue : uint8_t {
/** We need this program NOW.
*
* When passed as an argument to Material::compile(), if the platform doesn't support parallel
* compilation, but does support amortized shader compilation, the given shader program will be
* synchronously compiled.
*/
CRITICAL,
/** We will need this program soon. */
HIGH,
/** We will need this program eventually. */
LOW
};
@@ -1056,6 +1068,7 @@ enum class TextureUsage : uint16_t {
BLIT_SRC = 0x0040, //!< Texture can be used the source of a blit()
BLIT_DST = 0x0080, //!< Texture can be used the destination of a blit()
PROTECTED = 0x0100, //!< Texture can be used for protected content
GEN_MIPMAPPABLE = 0x0200, //!< Texture can be used with generateMipmaps()
DEFAULT = UPLOADABLE | SAMPLEABLE, //!< Default texture usage
ALL_ATTACHMENTS = COLOR_ATTACHMENT | DEPTH_ATTACHMENT | STENCIL_ATTACHMENT | SUBPASS_INPUT, //!< Mask of all attachments
};
+7 -1
View File
@@ -152,6 +152,12 @@ public:
*/
bool disableParallelShaderCompile = false;
/**
* Set to `true` to forcibly disable amortized shader compilation in the backend.
* Currently only honored by the GL backend.
*/
bool disableAmortizedShaderCompile = false;
/**
* Disable backend handles use-after-free checks.
*/
@@ -220,7 +226,7 @@ public:
* @param sharedContext an optional shared context. This is not meaningful with all graphic
* APIs and platforms.
* For EGL platforms, this is an EGLContext.
*
*
* @param driverConfig specifies driver initialization parameters
*
* @return nullptr on failure, or a pointer to the newly created driver.
+1 -1
View File
@@ -80,7 +80,7 @@ public:
Program& operator=(const Program& rhs) = delete;
Program(Program&& rhs) noexcept;
Program& operator=(Program&& rhs) noexcept = delete;
Program& operator=(Program&& rhs) noexcept;
~Program() noexcept;
+2 -1
View File
@@ -32,6 +32,7 @@ CompilerThreadPool::~CompilerThreadPool() noexcept {
assert_invariant(mCompilerThreads.empty());
assert_invariant(mQueues[0].empty());
assert_invariant(mQueues[1].empty());
assert_invariant(mQueues[2].empty());
}
void CompilerThreadPool::init(uint32_t threadCount,
@@ -55,7 +56,7 @@ void CompilerThreadPool::init(uint32_t threadCount,
});
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "CompilerThreadPool Jobs",
mQueues[0].size() + mQueues[1].size());
mQueues[0].size() + mQueues[1].size() + mQueues[2].size());
if (UTILS_LIKELY(!mExitRequested)) {
Job job;
+1 -2
View File
@@ -59,7 +59,7 @@ private:
bool mExitRequested{ false };
utils::Mutex mQueueLock;
utils::Condition mQueueCondition;
std::array<Queue, 2> mQueues;
std::array<Queue, 3> mQueues;
// lock must be held for methods below
std::pair<Queue&, Queue::iterator> find(program_token_t const& token);
};
@@ -67,4 +67,3 @@ private:
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_COMPILERTHREADPOOL_H
+2
View File
@@ -37,6 +37,8 @@ Program::Program() noexcept { // NOLINT(modernize-use-equals-default)
Program::Program(Program&& rhs) noexcept = default;
Program& Program::operator=(Program&& rhs) noexcept = default;
Program::~Program() noexcept = default;
Program& Program::priorityQueue(CompilerPriorityQueue priorityQueue) noexcept {
@@ -102,6 +102,9 @@ static inline MTLTextureUsage getMetalTextureUsage(TextureUsage usage) {
if (any(usage & TextureUsage::BLIT_SRC)) {
u |= MTLTextureUsageShaderRead;
}
if (any(usage & TextureUsage::GEN_MIPMAPPABLE)) {
u |= (MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead);
}
return MTLTextureUsage(u);
}
+11 -1
View File
@@ -2421,7 +2421,17 @@ bool OpenGLDriver::isStereoSupported() {
}
bool OpenGLDriver::isParallelShaderCompileSupported() {
return mShaderCompilerService.isParallelShaderCompileSupported();
// We emulate parallel compilation even on platforms that don't support it by amortizing the
// cost of shader compilation over N frames. It would be nice to move this behavior out of the
// OpenGL into a generic system usable by all backends. However, the behavior of async shader
// compilation is closely coupled to the internals of ShaderCompilerService, which is
// GL-specific. It would also be nice to inform the engine that they're working with this fake
// amortized system, but this fact will become implicit when we generalize this feature for all
// backends.
if (mDriverConfig.disableAmortizedShaderCompile) {
return mShaderCompilerService.isParallelShaderCompileSupported();
}
return true;
}
bool OpenGLDriver::isDepthStencilResolveSupported() {
@@ -60,6 +60,11 @@ namespace filament::backend {
using namespace utils;
// How many ticks do we wait in between compiling non-IMMEDIATE programs synchronously?
constexpr uint32_t NUM_TICKS_BETWEEN_PROGRAMS = 16;
// How many non-IMMEDIATE synchronous programs are we allowed to compile on the same tick?
constexpr uint32_t MAX_NUM_SYNCHRONOUS_PROGRAMS_PER_FRAME = 1;
// ------------------------------------------------------------------------------------------------
static std::string to_string(bool const b) { return b ? "true" : "false"; }
@@ -265,6 +270,7 @@ void ShaderCompilerService::terminate() noexcept {
mCompilerThreadPool.terminate();
mRunAtNextTickOps.clear();
mPendingSynchronousPrograms.clear();
// We could have some pending callbacks here, we need to execute them.
// This is equivalent to calling cancelTickOp() on all active tokens.
@@ -274,6 +280,7 @@ void ShaderCompilerService::terminate() noexcept {
ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
CString const& name, Program&& program) {
auto& gl = mDriver.getContext();
CompilerPriorityQueue const priorityQueue = program.getPriorityQueue();
// Create a token. A callback condition (handle) is internally created upon token creation.
auto token = std::make_shared<OpenGLProgramToken>(*this, name);
@@ -281,7 +288,33 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
token->attributes = std::move(program.getAttributes());
}
// Initiate program compilation.
if (mMode == Mode::SYNCHRONOUS) {
if (priorityQueue == CompilerPriorityQueue::CRITICAL ||
shouldCompileSynchronousProgramThisTick()) {
// We should immediately compile this program this frame.
compileProgram(token, std::move(program));
} else {
// We already exceeded the number of non-IMMEDIATE synchronous programs we're allowed to
// create this frame. Queue it for a future frame, sorted by priority.
auto const pos = std::lower_bound(mPendingSynchronousPrograms.begin(),
mPendingSynchronousPrograms.end(), priorityQueue,
[](PendingSynchronousProgram const& lhs,
CompilerPriorityQueue const priorityQueue) {
return std::get<1>(lhs).getPriorityQueue() < priorityQueue;
});
mPendingSynchronousPrograms.emplace(pos, token, std::move(program));
}
} else {
// Truly asynchronous platforms can always begin compiling immediately.
compileProgram(token, std::move(program));
}
return token;
}
void ShaderCompilerService::compileProgram(
program_token_t const& token, Program&& program) noexcept {
auto& gl = mDriver.getContext();
CompilerPriorityQueue const priorityQueue = program.getPriorityQueue();
switch (mMode) {
case Mode::THREAD_POOL: {
@@ -330,6 +363,8 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
}
case Mode::SYNCHRONOUS:
mNumProgramsCreatedSynchronouslyThisTick++;
UTILS_FALLTHROUGH;
case Mode::ASYNCHRONOUS: {
// Try retrieving the program from the cache first. If no program found,
// a normal compilation/linking process is performed.
@@ -365,8 +400,6 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
assert_invariant(false);
}
}
return token;
}
GLuint ShaderCompilerService::getProgram(program_token_t& token) {
@@ -400,6 +433,7 @@ GLuint ShaderCompilerService::getProgram(program_token_t& token) {
}
} else {
token->compiler.cancelTickOp(token);
token->compiler.cancelPendingSynchronousProgram(token);
}
token = nullptr; // This will try submitting a callback handle to the callback manager.
@@ -411,6 +445,9 @@ void ShaderCompilerService::tick() {
} else {
executeTickOps();
}
if (UTILS_UNLIKELY(mMode == Mode::SYNCHRONOUS)) {
compilePendingSynchronousPrograms();
}
}
CallbackManager::Handle ShaderCompilerService::issueCallbackHandle() const noexcept {
@@ -487,9 +524,9 @@ void ShaderCompilerService::ensureTokenIsReady(program_token_t const& token) {
// just log warnings here instead of repeatedly checking compile status. If this turns
// out to be a real issue later, we would need to consider doing the canonical way.
if (!isCompileCompleted(token)) {
LOG(WARNING)
LOG(INFO)
<< "Shader compilation for OpenGL program " << token->name.c_str_safe()
<< " is not completed yet. The following program link may not succeed.";
<< " is not completed yet. The following program link may be slow.";
}
linkProgram(mDriver.getContext(), token);
@@ -497,9 +534,12 @@ void ShaderCompilerService::ensureTokenIsReady(program_token_t const& token) {
}
case Mode::SYNCHRONOUS: {
// We must not have called the TickOp yet until now. Call now to have
// `token->gl.program` ready to use.
tick();
// This program might still be in the queue, so try to compile it now.
compilePendingSynchronousProgramNow(token);
// If the program was just compiled on the above line, or the program was compiled but
// the tick ops weren't yet executed, we must execute them to populate
// `token->gl.program`.
executeTickOps();
break;
}
@@ -591,6 +631,65 @@ void ShaderCompilerService::executeTickOps() noexcept {
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "ShaderCompilerService Jobs", ops.size());
}
bool ShaderCompilerService::shouldCompileSynchronousProgramThisTick() const noexcept {
return mDriver.getDriverConfig().disableAmortizedShaderCompile ||
(mNumProgramsCreatedSynchronouslyThisTick < MAX_NUM_SYNCHRONOUS_PROGRAMS_PER_FRAME &&
mNumTicksUntilNextSynchronousProgram == 0);
}
void ShaderCompilerService::compilePendingSynchronousPrograms() noexcept {
if (mDriver.getDriverConfig().disableAmortizedShaderCompile) {
return;
}
auto it = mPendingSynchronousPrograms.begin();
while (it != mPendingSynchronousPrograms.end() && shouldCompileSynchronousProgramThisTick()) {
compileProgram(std::get<0>(*it), std::move(std::get<1>(*it)));
it = mPendingSynchronousPrograms.erase(it);
}
if (mNumProgramsCreatedSynchronouslyThisTick) {
mNumTicksUntilNextSynchronousProgram = NUM_TICKS_BETWEEN_PROGRAMS;
mNumProgramsCreatedSynchronouslyThisTick = 0u;
} else if (mNumTicksUntilNextSynchronousProgram) {
mNumTicksUntilNextSynchronousProgram--;
}
}
void ShaderCompilerService::compilePendingSynchronousProgramNow(
program_token_t const& token) noexcept {
if (mDriver.getDriverConfig().disableAmortizedShaderCompile) {
return;
}
auto pos = std::find_if(mPendingSynchronousPrograms.begin(),
mPendingSynchronousPrograms.end(), [&](PendingSynchronousProgram const& item) {
return std::get<0>(item) == token;
});
if (pos != mPendingSynchronousPrograms.end()) {
compileProgram(std::get<0>(*pos), std::move(std::get<1>(*pos)));
mPendingSynchronousPrograms.erase(pos);
}
}
void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t const& token) noexcept {
if (mDriver.getDriverConfig().disableAmortizedShaderCompile) {
return;
}
// We do a linear search here, but this is rare, and we know the list is pretty small.
auto const pos = std::find_if(mPendingSynchronousPrograms.begin(),
mPendingSynchronousPrograms.end(), [&](const auto& item) {
return std::get<0>(item) == token;
});
if (pos != mPendingSynchronousPrograms.end()) {
mPendingSynchronousPrograms.erase(pos);
return;
}
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT,
"ShaderCompilerService Pending Programs", mPendingSynchronousPrograms.size());
}
/* static */ void ShaderCompilerService::compileShaders(OpenGLContext& context,
Program::ShaderSource shadersSource,
FixedCapacityVector<Program::SpecializationConstant> const& specializationConstants,
@@ -17,8 +17,6 @@
#ifndef TNT_FILAMENT_BACKEND_OPENGL_SHADERCOMPILERSERVICE_H
#define TNT_FILAMENT_BACKEND_OPENGL_SHADERCOMPILERSERVICE_H
#include "gl_headers.h"
#include "CallbackManager.h"
#include "CompilerThreadPool.h"
#include "OpenGLBlobCache.h"
@@ -35,7 +33,6 @@
#include <functional>
#include <list>
#include <memory>
#include <mutex>
#include <tuple>
#include <utility>
#include <vector>
@@ -136,6 +133,12 @@ private:
std::vector<ContainerType> mRunAtNextTickOps;
std::list<program_token_t> mCanceledTokens;
// These members are only ever accessed on the main thread and are completely unused when mMode
// is not SYNCHRONOUS.
uint32_t mNumProgramsCreatedSynchronouslyThisTick = 0u;
uint32_t mNumTicksUntilNextSynchronousProgram = 0u;
using PendingSynchronousProgram = std::tuple<program_token_t, Program>;
std::vector<PendingSynchronousProgram> mPendingSynchronousPrograms;
GLuint initialize(program_token_t& token);
void ensureTokenIsReady(program_token_t const& token);
@@ -149,6 +152,13 @@ private:
void executeTickOps() noexcept;
bool cancelTickOp(program_token_t const& token) noexcept;
bool shouldCompileSynchronousProgramThisTick() const noexcept;
void compilePendingSynchronousPrograms() noexcept;
void compilePendingSynchronousProgramNow(program_token_t const& token) noexcept;
void cancelPendingSynchronousProgram(program_token_t const& token) noexcept;
void compileProgram(program_token_t const& token, Program&& program) noexcept;
// Compile shaders with the given `shaderSource`. `gl.shaders` is always populated with valid
// shader IDs after this method. But this doesn't necessarily mean the shaders are successfully
// compiled. Errors can be checked by calling `checkCompileStatus` later.
+1
View File
@@ -499,6 +499,7 @@ io::ostream& operator<<(io::ostream& out, ShaderStage shaderStage) {
io::ostream& operator<<(io::ostream& out, CompilerPriorityQueue compilerPriorityQueue) {
switch (compilerPriorityQueue) {
CASE(CompilerPriorityQueue, CRITICAL)
CASE(CompilerPriorityQueue, HIGH)
CASE(CompilerPriorityQueue, LOW)
}
+11 -4
View File
@@ -37,10 +37,16 @@ inline void blitFast(VulkanCommandBuffer* commands, VkImageAspectFlags aspect, V
const VkOffset3D srcRect[2], const VkOffset3D dstRect[2]) {
VkCommandBuffer const cmdbuf = commands->buffer();
if constexpr (FVK_ENABLED(FVK_DEBUG_BLITTER)) {
FVK_LOGD << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
<< " layout=" << src.getLayout()
<< " to=" << dst.texture->getVkImage() << ",level=" << (int) dst.level
<< " layout=" << dst.getLayout();
FVK_LOGE << "Fast blit from=" << src.texture->getVkImage() << ", level=" << (int) src.level
<< ", layer=" << (int) src.layer
<< ", layout=" << src.getLayout()
<< ", src-rect=(" << srcRect[0].x << "," << srcRect[0].y << "," << srcRect[0].z << ")"
<< "->(" << srcRect[1].x << "," << srcRect[1].y << "," << srcRect[1].z << ")"
<< " to=" << dst.texture->getVkImage() << ", level=" << (int) dst.level
<< ", layer=" << (int) dst.layer
<< ", layout=" << dst.getLayout()
<< ", dst-rect=(" << dstRect[0].x << "," << dstRect[0].y << "," << dstRect[0].z << ")"
<< "->(" << dstRect[1].x << "," << dstRect[1].y << "," << dstRect[1].z << ")";
}
VkImageSubresourceRange const srcRange = src.getSubresourceRange();
@@ -69,6 +75,7 @@ inline void blitFast(VulkanCommandBuffer* commands, VkImageAspectFlags aspect, V
if (oldDstLayout == VulkanLayout::UNDEFINED) {
oldDstLayout = dst.texture->getDefaultLayout();
}
src.texture->transitionLayout(commands, srcRange, oldSrcLayout);
dst.texture->transitionLayout(commands, dstRange, oldDstLayout);
}
+15 -2
View File
@@ -206,6 +206,11 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context,
: mPlatform(platform),
mResourceManager(driverConfig.handleArenaSize, driverConfig.disableHandleUseAfterFreeCheck,
driverConfig.disableHeapHandleTags),
// Note that we always create the default rendertarget before createDefaultRenderTarget(). We
// swap the content later when createDefaultRenderTarget() is called. This frees
// createDefaultRenderTarget() from being ordered with makeCurrent().
mDefaultRenderTarget(
fvkmemory::resource_ptr<VulkanRenderTarget>::construct(&mResourceManager)),
mAllocator(createAllocator(mPlatform->getInstance(), mPlatform->getPhysicalDevice(),
mPlatform->getDevice())),
mContext(context),
@@ -698,8 +703,11 @@ void VulkanDriver::destroyProgram(Handle<HwProgram> ph) {
}
void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int) {
assert_invariant(!mDefaultRenderTarget);
auto renderTarget = resource_ptr<VulkanRenderTarget>::make(&mResourceManager, rth);
assert_invariant(mDefaultRenderTarget); // Default render target should already exist.
auto renderTarget = resource_ptr<VulkanRenderTarget>::make(&mResourceManager, rth,
std::move(std::move(*mDefaultRenderTarget.get())));
mDefaultRenderTarget = renderTarget;
}
@@ -775,6 +783,7 @@ void VulkanDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
auto rt = resource_ptr<VulkanRenderTarget>::cast(&mResourceManager, rth);
if (UTILS_UNLIKELY(rt == mDefaultRenderTarget)) {
// Note that this should only happen on driver shutdown.
mDefaultRenderTarget = {};
} else {
rt.dec();
@@ -1366,6 +1375,10 @@ void VulkanDriver::generateMipmaps(Handle<HwTexture> th) {
srcw = dstw;
srch = dsth;
} while ((srcw > 1 || srch > 1) && ++level < t->levels - 1);
VulkanCommandBuffer* commandBuffer = &mCommands.get();
// Here we transition to the whole image to the most likely next layout.
t->transitionLayout(commandBuffer, t->getPrimaryViewRange(), t->getDefaultLayout());
}
void VulkanDriver::compilePrograms(CompilerPriorityQueue priority,
+16 -1
View File
@@ -308,6 +308,15 @@ struct VulkanRenderTarget : private HwRenderTarget, fvkmemory::Resource {
// Creates a special "default" render target (i.e. associated with the swap chain)
explicit VulkanRenderTarget();
VulkanRenderTarget(VulkanRenderTarget&& target) {
swap(std::move(target));
}
VulkanRenderTarget& operator=(VulkanRenderTarget&& target) {
swap(std::move(target));
return *this;
}
void transformClientRectToPlatform(VkRect2D* bounds) const;
void transformViewportToPlatform(VkViewport* bounds) const;
@@ -355,6 +364,12 @@ struct VulkanRenderTarget : private HwRenderTarget, fvkmemory::Resource {
void emitBarriersEndRenderPass(VulkanCommandBuffer& commands);
private:
void swap(VulkanRenderTarget&& target) {
std::swap(mOffscreen, target.mOffscreen);
std::swap(mProtected, target.mProtected);
std::swap(mInfo, target.mInfo);
}
struct Auxiliary {
static constexpr int8_t UNDEFINED_INDEX = -1;
@@ -368,7 +383,7 @@ private:
int8_t msaaDepthIndex = UNDEFINED_INDEX;
int8_t msaaIndex = UNDEFINED_INDEX;
};
bool const mOffscreen;
bool mOffscreen;
bool mProtected;
std::unique_ptr<Auxiliary> mInfo;
@@ -207,16 +207,11 @@ fvkmemory::resource_ptr<VulkanStageImage::Resource> VulkanStagePool::acquireImag
VulkanStageImage* stageImage = new VulkanStageImage(
vkformat, width, height, memory, image, mCurrentFrame);
// We use VK_IMAGE_LAYOUT_GENERAL here because the spec says:
// "Host access to image memory is only well-defined for linear images and for image
// subresources of those images which are currently in either the
// VK_IMAGE_LAYOUT_PREINITIALIZED or VK_IMAGE_LAYOUT_GENERAL layout. Calling
// vkGetImageSubresourceLayout for a linear image returns a subresource layout mapping that is
// valid for either of those image layouts."
fvkutils::transitionLayout(cmdbuffer, {
.image = stageImage->image(),
.oldLayout = VulkanLayout::UNDEFINED,
.newLayout = VulkanLayout::STAGING, // (= VK_IMAGE_LAYOUT_GENERAL)
// TRANSFER_SRC because we're about to blit this to the actual texture.
.newLayout = VulkanLayout::TRANSFER_SRC,
.subresources = { aspectFlags, 0, 1, 0, 1 },
});
@@ -117,12 +117,14 @@ inline VulkanLayout getDefaultLayoutImpl(TextureUsage usage) {
if (any(usage & TextureUsage::DEPTH_ATTACHMENT)) {
if (any(usage & TextureUsage::SAMPLEABLE)) {
return VulkanLayout::DEPTH_SAMPLER;
} else {
return VulkanLayout::DEPTH_ATTACHMENT;
}
return VulkanLayout::DEPTH_ATTACHMENT;
}
if (any(usage & TextureUsage::COLOR_ATTACHMENT)) {
if (any(usage & TextureUsage::SAMPLEABLE)) {
return VulkanLayout::FRAG_READ;
}
return VulkanLayout::COLOR_ATTACHMENT;
}
// Finally, the layout for an immutable texture is optimal read-only.
@@ -162,6 +164,10 @@ VkImageUsageFlags getUsage(VulkanContext const& context, uint8_t samples,
usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
if (any(tusage & TextureUsage::GEN_MIPMAPPABLE)) {
usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
// Determine if we can use the transient usage flag combined with lazily allocated memory.
const bool useTransientAttachment =
// Lazily allocated memory is available.
+237 -107
View File
@@ -18,6 +18,7 @@
#include "WebGPUConstants.h"
#include "WebGPUStrings.h"
#include "WebGPUTextureHelpers.h"
#include "webgpu/utils/StringPlaceholderTemplateProcessor.h"
#include <backend/DriverEnums.h>
@@ -37,6 +38,32 @@ namespace filament::backend {
namespace {
/**
* @return true if copyToTextureToTexture validation would succeed and we could use that for the
* "blit"
* ( see https://www.w3.org/TR/webgpu/#dom-gpucommandencoder-copytexturetotexture )
* NOTE: this does not validate usage of the source and/or destination.
* If canDoDirectCopy(...) == true and the textures don't have the appropriate usages
* we should panic (we should not be doing a renderpass blit when we could have been
* doing a direct copy)
*/
[[nodiscard]] constexpr bool canDoDirectCopy(const uint32_t sourceSampleCount,
const wgpu::TextureFormat sourceFormat, const wgpu::Origin2D sourceOrigin,
const wgpu::Extent2D sourceExtent, const uint32_t destinationSampleCount,
const wgpu::TextureFormat destinationFormat, const wgpu::Origin2D destinationOrigin,
const wgpu::Extent2D destinationExtent) {
const wgpu::Extent2D sourceBlockSize{ getBlockSize(sourceFormat) };
const wgpu::Extent2D destinationBlockSize{ getBlockSize(destinationFormat) };
return sourceSampleCount == destinationSampleCount &&
areCopyCompatible(sourceFormat, destinationFormat) &&
(sourceExtent.width == destinationExtent.width) &&
(sourceExtent.height == destinationExtent.height) &&
((sourceOrigin.x & sourceBlockSize.width) == 0) &&
((sourceOrigin.y & sourceBlockSize.height) == 0) &&
((destinationOrigin.x & destinationBlockSize.width) == 0) &&
((destinationOrigin.y & destinationBlockSize.height) == 0);
}
struct BlitFragmentShaderArgs final {
uint32_t depthPlane{ 0 };
uint32_t padding{ 0 }; // Add 4 bytes of padding to align the vec2 members
@@ -61,11 +88,18 @@ constexpr std::string_view FRAGMENT_SHADER_ENTRY_POINT{ "fragmentShaderMain" };
// otherwise be present in the template:
constexpr std::string_view PLACEHOLDER_PREFIX{ "{{" };
constexpr std::string_view PLACEHOLDER_SUFFIX{ "}}" };
// texture_2d<f32> or texture_multisampled_2d<f32> or texture_3d<f32>
// texture_2d<f32> or texture_multisampled_2d<f32> or texture_3d<f32> or
// texture_depth_2d or texture_depth_multisampled_2d
constexpr std::string_view TEXTURE_TYPE_PLACEHOLDER{ "TEXTURE_TYPE" };
// texture_2d<f32> or texture_depth_2d
[[maybe_unused]] constexpr std::string_view TEXTURE_2D_TYPE_PLACEHOLDER { "TEXTURE_2D_TYPE" };
// "" for no sampler, otherwise "@group(0) @binding(2) var sourceSampler: sampler;"
constexpr std::string_view SAMPLER_DECLARATION_PLACEHOLDER{ "SAMPLER_DECLARATION" };
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_PLACEHOLDER{ "FRAGMENT_SHADER_SNIPPET" };
// @location(0) vec4<f32> or @builtin(frag_depth) f32
constexpr std::string_view FRAGMENT_RETURN_ATTRIBUTE_AND_TYPE_PLACEHOLDER{
"FRAGMENT_RETURN_ATTRIBUTE_AND_TYPE"
};
constexpr std::string_view SHADER_SOURCE_TEMPLATE{ R"(
struct BlitFragmentShaderArgs {
depthPlane: u32,
@@ -95,7 +129,7 @@ constexpr std::string_view SHADER_SOURCE_TEMPLATE{ R"(
fn getNormalized2dSourceTextureCoordinates(
position: vec2<f32>,
sourceTexture: texture_2d<f32>) -> vec2<f32> {
sourceTexture: {{TEXTURE_2D_TYPE}}) -> vec2<f32> {
let sourceDimensions: vec2<u32> = textureDimensions(sourceTexture);
return normalize2dSourceTextureCoordinates(
getUnnormalizedSourceTextureCoordinates(position),
@@ -139,9 +173,9 @@ constexpr std::string_view SHADER_SOURCE_TEMPLATE{ R"(
{{FRAGMENT_SHADER_SNIPPET}}
)" };
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_MSAA_INPUT{ R"(
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_MSAA_INPUT_TEMPLATE{ R"(
@fragment
fn fragmentShaderMain(@builtin(position) position: vec4<f32>) -> @location(0) vec4<f32> {
fn fragmentShaderMain(@builtin(position) position: vec4<f32>) -> {{FRAGMENT_RETURN_ATTRIBUTE_AND_TYPE}} {
var color: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);
let numberOfSamples: u32 = textureNumSamples(sourceTexture);
let coordinatesF: vec2<f32> = getUnnormalizedSourceTextureCoordinates(position.xy);
@@ -154,17 +188,17 @@ constexpr std::string_view FRAGMENT_SHADER_SNIPPET_MSAA_INPUT{ R"(
}
)" };
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_3D_INPUT{ R"(
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_3D_INPUT_TEMPLATE{ R"(
@fragment
fn fragmentShaderMain(@builtin(position) position: vec4<f32>) -> @location(0) vec4<f32> {
fn fragmentShaderMain(@builtin(position) position: vec4<f32>) -> {{FRAGMENT_RETURN_ATTRIBUTE_AND_TYPE}} {
let coordinates: vec3<f32> = getNormalized3dSourceTextureCoordinates(position.xy, sourceTexture);
return textureSample(sourceTexture, sourceSampler, coordinates);
}
)" };
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_2D_INPUT{ R"(
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_2D_INPUT_TEMPLATE{ R"(
@fragment
fn fragmentShaderMain(@builtin(position) position: vec4<f32>) -> @location(0) vec4<f32> {
fn fragmentShaderMain(@builtin(position) position: vec4<f32>) -> {{FRAGMENT_RETURN_ATTRIBUTE_AND_TYPE}} {
let coordinates: vec2<f32> = getNormalized2dSourceTextureCoordinates(position.xy, sourceTexture);
return textureSample(sourceTexture, sourceSampler, coordinates);
}
@@ -199,39 +233,24 @@ void WebGPUBlitter::blit(wgpu::Queue const& queue, wgpu::CommandEncoder const& c
// time no major known graphics API supports this, including WebGPU. Furthermore, the Metal
// blitter does not support this either.
// TODO REMOVE (keeping for troubleshooting/debug purposes for now)
#if FWGPU_ENABLED(FWGPU_DEBUG_VALIDATION)
FWGPU_LOGD << "ABOUT to blit:";
const bool willDirectCopy{ canDoDirectCopy(args.source.texture.GetSampleCount(),
args.source.texture.GetFormat(), args.source.origin, args.source.extent,
args.destination.texture.GetSampleCount(), args.destination.texture.GetFormat(),
args.destination.origin, args.destination.extent) };
#if FWGPU_ENABLED(FWGPU_DEBUG_BLIT)
FWGPU_LOGD << "ABOUT to blit using " << (willDirectCopy ? "copy-texture-to-texture" : "renderpass");
FWGPU_LOGD << " Source:";
FWGPU_LOGD << " texture:" << webGPUPrintableToString(args.source.texture.GetFormat());
FWGPU_LOGD << " depthOrArrayLayers: " << args.source.texture.GetDepthOrArrayLayers();
FWGPU_LOGD << " " << webGPUPrintableToString(args.source.texture.GetDimension());
FWGPU_LOGD << " format: " << webGPUTextureFormatToString(args.source.texture.GetFormat());
FWGPU_LOGD << " height: " << args.source.texture.GetHeight();
FWGPU_LOGD << " mipLevelCount: " << args.source.texture.GetMipLevelCount();
FWGPU_LOGD << " sampleCount: " << args.source.texture.GetSampleCount();
FWGPU_LOGD << " " << webGPUPrintableToString(args.source.texture.GetUsage());
FWGPU_LOGD << " width: " << args.source.texture.GetWidth();
FWGPU_LOGD << " " << webGPUTextureToString(args.source.texture);
FWGPU_LOGD << " aspect: " << webGPUPrintableToString(args.source.aspect);
FWGPU_LOGD << " origin: x: " << args.source.origin.x << " y: " << args.source.origin.y;
FWGPU_LOGD << " extent: width: " << args.source.extent.width
<< " height: " << args.source.extent.height;
FWGPU_LOGD << " extent: width: " << args.source.extent.width << " height: " << args.source.extent.height;
FWGPU_LOGD << " mipLevel: " << args.source.mipLevel;
FWGPU_LOGD << " layerOrDepth: " << args.source.layerOrDepth;
FWGPU_LOGD << " Destination:";
FWGPU_LOGD << " texture:" << webGPUPrintableToString(args.destination.texture.GetFormat());
FWGPU_LOGD << " depthOrArrayLayers: " << args.destination.texture.GetDepthOrArrayLayers();
FWGPU_LOGD << " " << webGPUPrintableToString(args.destination.texture.GetDimension());
FWGPU_LOGD << " format: "
<< webGPUTextureFormatToString(args.destination.texture.GetFormat());
FWGPU_LOGD << " height: " << args.destination.texture.GetHeight();
FWGPU_LOGD << " mipLevelCount: " << args.destination.texture.GetMipLevelCount();
FWGPU_LOGD << " sampleCount: " << args.destination.texture.GetSampleCount();
FWGPU_LOGD << " " << webGPUPrintableToString(args.destination.texture.GetUsage());
FWGPU_LOGD << " width: " << args.destination.texture.GetWidth();
FWGPU_LOGD << " origin: x: " << args.destination.origin.x
<< " y: " << args.destination.origin.y;
FWGPU_LOGD << " extent: width: " << args.destination.extent.width
<< " height: " << args.destination.extent.height;
FWGPU_LOGD << " " << webGPUTextureToString(args.destination.texture);
FWGPU_LOGD << " aspect: " << webGPUPrintableToString(args.destination.aspect);
FWGPU_LOGD << " origin: x: " << args.destination.origin.x << " y: " << args.destination.origin.y;
FWGPU_LOGD << " extent: width: " << args.destination.extent.width << " height: " << args.destination.extent.height;
FWGPU_LOGD << " mipLevel: " << args.destination.mipLevel;
FWGPU_LOGD << " layerOrDepth: " << args.destination.layerOrDepth;
FWGPU_LOGD << " filter: " << (args.filter == SamplerMagFilter::NEAREST ? "NEAREST" : "LINEAR");
@@ -240,6 +259,18 @@ void WebGPUBlitter::blit(wgpu::Queue const& queue, wgpu::CommandEncoder const& c
args.source.texture.GetSampleCount() == 1)
<< "Multispampled 3D textures are not supported (the source 3D texture was configured "
"for multisampling) (this should not be possible?)";
if (willDirectCopy) {
FILAMENT_CHECK_PRECONDITION(args.source.texture.GetUsage() & wgpu::TextureUsage::CopySrc)
<< "source texture usage doesn't have wgpu::TextureUsage::CopySrc";
FILAMENT_CHECK_PRECONDITION(
args.destination.texture.GetUsage() & wgpu::TextureUsage::CopyDst)
<< "destination texture usage doesn't have wgpu::TextureUsage::CopyDst";
copy(commandEncoder, args);
return;
}
// need to do a render pass blit...
FILAMENT_CHECK_PRECONDITION(args.destination.texture.GetSampleCount() == 1)
<< "Blitting does not currently support writing to multisampled output textures.";
@@ -266,7 +297,7 @@ void WebGPUBlitter::blit(wgpu::Queue const& queue, wgpu::CommandEncoder const& c
? 1
: args.source.layerOrDepth,
.arrayLayerCount = 1,
.aspect = wgpu::TextureAspect::All,
.aspect = args.source.aspect,
.usage = wgpu::TextureUsage::TextureBinding,
};
const wgpu::TextureView sourceView{ args.source.texture.CreateView(&sourceViewDescriptor) };
@@ -286,7 +317,7 @@ void WebGPUBlitter::blit(wgpu::Queue const& queue, wgpu::CommandEncoder const& c
? 1
: args.destination.layerOrDepth,
.arrayLayerCount = 1,
.aspect = wgpu::TextureAspect::All,
.aspect = args.destination.aspect,
.usage = wgpu::TextureUsage::RenderAttachment,
};
const wgpu::TextureView destinationView{ args.destination.texture.CreateView(
@@ -353,50 +384,91 @@ void WebGPUBlitter::blit(wgpu::Queue const& queue, wgpu::CommandEncoder const& c
.sampler = sampler, // note: might be nullptr if we don't need it
}
};
const bool multisampledSource{ args.source.texture.GetSampleCount() > 1 };
const bool depthSource{ hasDepth(args.source.texture.GetFormat()) };
const bool depthDestination{ hasDepth(args.destination.texture.GetFormat()) };
const wgpu::BindGroupDescriptor textureBindGroupDescriptor{
.label = "blit_texture_bind_group",
.layout = getOrCreateTextureBindGroupLayout(args.filter, sourceDimension,
args.source.texture.GetSampleCount() > 1),
multisampledSource, depthSource),
.entryCount = textureBindGroupEntriesCount,
.entries = textureBindGroupEntries,
};
const wgpu::BindGroup textureBindGroup{ mDevice.CreateBindGroup(&textureBindGroupDescriptor) };
FILAMENT_CHECK_POSTCONDITION(textureBindGroup)
<< "Failed to create texture bind group for render pass blit?";
// create color attachment (output)...
const wgpu::RenderPassColorAttachment colorAttachment{
.view = destinationView,
.depthSlice = args.destination.texture.GetDimension() == wgpu::TextureDimension::e3D
? args.destination.layerOrDepth
: wgpu::kDepthSliceUndefined,
// we don't need this resolveTarget because we are doing a resolve in software (the shader),
// but we probably should (leveraging a msaa sidecar texture) to take advantage of
// hardware acceleration. Thus, this might be an opportunity for optimization
.resolveTarget = nullptr,
.loadOp = wgpu::LoadOp::Clear,
.storeOp = wgpu::StoreOp::Store,
.clearValue = { .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
};
const wgpu::RenderPassDescriptor renderPassDescriptor{
// create color or depth attachment (output)...
wgpu::RenderPassDescriptor renderPassDescriptor{
.label = "blit_render_pass",
.colorAttachmentCount = 1,
.colorAttachments = &colorAttachment,
.depthStencilAttachment = nullptr, // not applicable
.colorAttachmentCount = 0, // updated if non-depth destination
.colorAttachments = nullptr, // updated if non-depth destination
.depthStencilAttachment = nullptr, // updated if depth destination
.occlusionQuerySet = nullptr, // not applicable
.timestampWrites = nullptr, // not applicable
};
if (depthDestination) {
const wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{
.view = destinationView,
.depthLoadOp = wgpu::LoadOp::Clear,
.depthStoreOp = wgpu::StoreOp::Store,
.depthClearValue = 0.0f, // explicitly defining for consistency
.depthReadOnly = false,
.stencilLoadOp = wgpu::LoadOp::Undefined, // stencil not supported
.stencilStoreOp = wgpu::StoreOp::Undefined, // stencil not supported
};
renderPassDescriptor.depthStencilAttachment = &depthStencilAttachment;
} else {
// color destination...
const wgpu::RenderPassColorAttachment colorAttachment{
.view = destinationView,
.depthSlice = args.destination.texture.GetDimension() == wgpu::TextureDimension::e3D
? args.destination.layerOrDepth
: wgpu::kDepthSliceUndefined,
// we don't need this resolveTarget because we are doing a resolve in software (the
// shader), but we probably should (leveraging a msaa sidecar texture) to take advantage
// of hardware acceleration. Thus, this might be an opportunity for optimization
.resolveTarget = nullptr,
.loadOp = wgpu::LoadOp::Clear,
.storeOp = wgpu::StoreOp::Store,
.clearValue = { .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
};
renderPassDescriptor.colorAttachmentCount = 1;
renderPassDescriptor.colorAttachments = &colorAttachment;
}
const wgpu::RenderPassEncoder renderPassEncoder{ commandEncoder.BeginRenderPass(
&renderPassDescriptor) };
FILAMENT_CHECK_POSTCONDITION(renderPassEncoder)
<< "Failed to create render pass encoder for blit?";
renderPassEncoder.SetPipeline(getOrCreateRenderPipeline(args.filter, sourceDimension,
args.source.texture.GetSampleCount(), args.destination.texture.GetFormat()));
args.source.texture.GetSampleCount(), depthSource,
args.destination.texture.GetFormat()));
renderPassEncoder.SetBindGroup(TEXTURE_BIND_GROUP_INDEX, textureBindGroup);
renderPassEncoder.Draw(3); // draw the full-screen triangle
// with hard-coded vertices in the shader
renderPassEncoder.End();
}
void WebGPUBlitter::copy(wgpu::CommandEncoder const& commandEncoder, BlitArgs const& args) {
const wgpu::TexelCopyTextureInfo sourceCopyInfo{
.texture = args.source.texture,
.mipLevel = args.source.mipLevel,
.origin = { args.source.origin.x, args.source.origin.y, args.source.layerOrDepth },
.aspect = args.source.aspect,
};
const wgpu::TexelCopyTextureInfo destinationCopyInfo{
.texture = args.destination.texture,
.mipLevel = args.destination.mipLevel,
.origin = {
args.destination.origin.x,
args.destination.origin.y,
args.destination.layerOrDepth,
},
.aspect = args.destination.aspect,
};
const wgpu::Extent3D copySize{ args.source.extent.width, args.source.extent.height, 1 };
commandEncoder.CopyTextureToTexture(&sourceCopyInfo, &destinationCopyInfo, &copySize);
}
void WebGPUBlitter::createSampler(const SamplerMagFilter filter) {
wgpu::StringView label;
wgpu::FilterMode magFilter;
@@ -446,32 +518,40 @@ void WebGPUBlitter::createSampler(const SamplerMagFilter filter) {
wgpu::RenderPipeline const& WebGPUBlitter::getOrCreateRenderPipeline(
const SamplerMagFilter filterType, const wgpu::TextureViewDimension sourceDimension,
const uint32_t sourceSampleCount, const wgpu::TextureFormat destinationTextureFormat) {
const size_t key{ hashRenderPipelineKey(filterType, sourceDimension, sourceSampleCount) };
const uint32_t sourceSampleCount, const bool depthSource,
const wgpu::TextureFormat destinationTextureFormat) {
const size_t key{ hashRenderPipelineKey(filterType, sourceDimension, sourceSampleCount,
depthSource, destinationTextureFormat) };
if (mRenderPipelines.find(key) == mRenderPipelines.end()) {
mRenderPipelines[key] = createRenderPipeline(filterType, sourceDimension, sourceSampleCount,
destinationTextureFormat);
depthSource, destinationTextureFormat);
}
return mRenderPipelines[key];
}
wgpu::RenderPipeline WebGPUBlitter::createRenderPipeline(const SamplerMagFilter filterType,
const wgpu::TextureViewDimension sourceDimension, const uint32_t sourceSampleCount,
const wgpu::TextureFormat destinationTextureFormat) {
const bool depthSource, const wgpu::TextureFormat destinationTextureFormat) {
const bool depthDestination{ hasDepth(destinationTextureFormat) };
const wgpu::ColorTargetState colorTargetState{ .format = destinationTextureFormat };
const wgpu::DepthStencilState depthStencilState{
.format = destinationTextureFormat,
.depthWriteEnabled = true,
.depthCompare = wgpu::CompareFunction::Always,
};
wgpu::ShaderModule const& shaderModule{ getOrCreateShaderModule(sourceDimension,
sourceSampleCount > 1) };
sourceSampleCount > 1, depthSource, hasDepth(destinationTextureFormat)) };
const wgpu::FragmentState fragmentState{
.module = shaderModule,
.entryPoint = FRAGMENT_SHADER_ENTRY_POINT,
.constantCount = 0, // should not matter, just being consistently defined
.constants = nullptr, // should not matter, just being consistently defined
.targetCount = 1,
.targets = &colorTargetState,
.targetCount = depthDestination ? 0u : 1u,
.targets = depthDestination ? nullptr : &colorTargetState,
};
const wgpu::RenderPipelineDescriptor pipelineDescriptor{
.label = "render_pass_blit_pipeline",
.layout = getOrCreatePipelineLayout(filterType, sourceDimension, sourceSampleCount > 1),
.layout = getOrCreatePipelineLayout(filterType, sourceDimension, sourceSampleCount > 1, depthSource),
.vertex = {
.module = shaderModule,
.entryPoint = VERTEX_SHADER_ENTRY_POINT,
@@ -491,8 +571,7 @@ wgpu::RenderPipeline WebGPUBlitter::createRenderPipeline(const SamplerMagFilter
.cullMode = wgpu::CullMode::None,
.unclippedDepth = false, // should not matter, just being consistently defined
},
.depthStencil = nullptr, // not applicable, but explicitly set here for
// consistent definition
.depthStencil = depthDestination ? &depthStencilState : nullptr,
.multisample = {
.count = sourceSampleCount,
.mask = 0xFFFFFFFF,
@@ -506,31 +585,36 @@ wgpu::RenderPipeline WebGPUBlitter::createRenderPipeline(const SamplerMagFilter
}
size_t WebGPUBlitter::hashRenderPipelineKey(const SamplerMagFilter filterType,
const wgpu::TextureViewDimension sourceDimension, const uint32_t sourceSampleCount) {
const wgpu::TextureViewDimension sourceDimension, const uint32_t sourceSampleCount,
const bool depthSource, const wgpu::TextureFormat destinationTextureFormat) {
size_t seed{ std::hash<uint8_t>{}(static_cast<uint8_t>(filterType)) };
utils::hash::combine(seed, static_cast<uint32_t>(sourceDimension));
utils::hash::combine(seed, sourceSampleCount);
utils::hash::combine(seed, depthSource);
utils::hash::combine(seed, static_cast<uint32_t>(destinationTextureFormat));
return seed;
}
wgpu::PipelineLayout const& WebGPUBlitter::getOrCreatePipelineLayout(
const SamplerMagFilter filterType, const wgpu::TextureViewDimension sourceDimension,
const bool multisampledSource) {
const size_t key{ hashPipelineLayoutKey(filterType, sourceDimension, multisampledSource) };
const bool multisampledSource, const bool depthSource) {
const size_t key{ hashPipelineLayoutKey(filterType, sourceDimension, multisampledSource,
depthSource) };
if (mPipelineLayouts.find(key) == mPipelineLayouts.end()) {
mPipelineLayouts[key] =
createPipelineLayout(filterType, sourceDimension, multisampledSource);
createPipelineLayout(filterType, sourceDimension, multisampledSource, depthSource);
}
return mPipelineLayouts[key];
}
wgpu::PipelineLayout WebGPUBlitter::createPipelineLayout(const SamplerMagFilter filterType,
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource) {
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource,
const bool depthSource) {
const wgpu::PipelineLayoutDescriptor pipelineLayoutDescriptor{
.label = "render_pass_blit_pipeline_layout",
.bindGroupLayoutCount = 1,
.bindGroupLayouts =
&getOrCreateTextureBindGroupLayout(filterType, sourceDimension, multisampledSource),
.bindGroupLayouts = &getOrCreateTextureBindGroupLayout(filterType, sourceDimension,
multisampledSource, depthSource),
};
const wgpu::PipelineLayout pipelineLayout{ mDevice.CreatePipelineLayout(
&pipelineLayoutDescriptor) };
@@ -540,36 +624,42 @@ wgpu::PipelineLayout WebGPUBlitter::createPipelineLayout(const SamplerMagFilter
}
size_t WebGPUBlitter::hashPipelineLayoutKey(const SamplerMagFilter filterType,
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource) {
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource,
const bool depthSource) {
size_t seed{ std::hash<uint8_t>{}(static_cast<uint8_t>(filterType)) };
utils::hash::combine(seed, static_cast<uint32_t>(sourceDimension));
utils::hash::combine(seed, multisampledSource);
utils::hash::combine(seed, depthSource);
return seed;
}
wgpu::BindGroupLayout const& WebGPUBlitter::getOrCreateTextureBindGroupLayout(
const SamplerMagFilter filterType, const wgpu::TextureViewDimension sourceDimension,
const bool multisampledSource) {
const size_t key{ hashTextureBindGroupLayoutKey(filterType, sourceDimension,
multisampledSource) };
const bool multisampledSource, const bool depthSource) {
const size_t key{ hashTextureBindGroupLayoutKey(filterType, sourceDimension, multisampledSource,
depthSource) };
if (mTextureBindGroupLayouts.find(key) == mTextureBindGroupLayouts.end()) {
mTextureBindGroupLayouts[key] =
createTextureBindGroupLayout(filterType, sourceDimension, multisampledSource);
mTextureBindGroupLayouts[key] = createTextureBindGroupLayout(filterType, sourceDimension,
multisampledSource, depthSource);
}
return mTextureBindGroupLayouts[key];
}
wgpu::BindGroupLayout WebGPUBlitter::createTextureBindGroupLayout(const SamplerMagFilter filterType,
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource) {
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource,
const bool depthSource) {
const wgpu::BindGroupLayoutEntry bindGroupLayoutEntries[MAX_TEXTURE_BIND_GROUP_ENTRY_SIZE] {
{
.binding = TEXTURE_BINDING_INDEX,
.visibility = wgpu::ShaderStage::Fragment,
.texture = {
.sampleType = wgpu::TextureSampleType::Float, // only F32 scalar sample
// type supported for now
// see assumptions listed
// in blit function
.sampleType = depthSource
? wgpu::TextureSampleType::Depth
: wgpu::TextureSampleType::Float, // only F32 scalar sample
// type supported for now
// (aside from depth)
// see assumptions listed
// in blit function
.viewDimension = sourceDimension,
.multisampled = multisampledSource,
},
@@ -608,47 +698,85 @@ wgpu::BindGroupLayout WebGPUBlitter::createTextureBindGroupLayout(const SamplerM
}
size_t WebGPUBlitter::hashTextureBindGroupLayoutKey(const SamplerMagFilter filterType,
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource) {
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource,
const bool depthSource) {
size_t seed{ std::hash<uint8_t>{}(static_cast<uint8_t>(filterType)) };
utils::hash::combine(seed, static_cast<uint32_t>(sourceDimension));
utils::hash::combine(seed, multisampledSource);
utils::hash::combine(seed, depthSource);
return seed;
}
wgpu::ShaderModule const& WebGPUBlitter::getOrCreateShaderModule(
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource) {
const size_t key{ hashShaderModuleKey(sourceDimension, multisampledSource) };
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource,
const bool depthSource, const bool depthDestination) {
const size_t key{ hashShaderModuleKey(sourceDimension, multisampledSource, depthSource,
depthDestination) };
if (mShaderModules.find(key) == mShaderModules.end()) {
mShaderModules[key] = createShaderModule(sourceDimension, multisampledSource);
mShaderModules[key] = createShaderModule(sourceDimension, multisampledSource, depthSource,
depthDestination);
}
return mShaderModules[key];
}
wgpu::ShaderModule WebGPUBlitter::createShaderModule(
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource) {
const std::string_view textureType{
multisampledSource
? "texture_multisampled_2d<f32>"
: (sourceDimension == wgpu::TextureViewDimension::e3D ? "texture_3d<f32>"
: "texture_2d<f32>")
};
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource,
const bool depthSource, const bool depthDestination) {
std::string_view textureType;
if (depthSource) {
if (multisampledSource) {
textureType = "texture_depth_multisampled_2d";
} else {
textureType = "texture_depth_2d";
}
} else {
// non-depth
if (multisampledSource) {
textureType = "texture_multisampled_2d";
} else {
if (sourceDimension == wgpu::TextureViewDimension::e3D) {
textureType = "texture_3d<f32>";
} else {
textureType = "texture_2d<f32>";
}
}
}
const std::string_view texture2dType{ depthSource ? "texture_depth_2d" : "texture_2d<f32>" };
// we don't declare a sampler in the shader or pipeline for the multisampled case
const std::string_view samplerDeclaration{
multisampledSource ? "" : "@group(0) @binding(2) var sourceSampler: sampler;"
};
const std::string_view fragmentShaderSnippet{
multisampledSource ? FRAGMENT_SHADER_SNIPPET_MSAA_INPUT
: (sourceDimension == wgpu::TextureViewDimension::e3D
? FRAGMENT_SHADER_SNIPPET_3D_INPUT
: FRAGMENT_SHADER_SNIPPET_2D_INPUT)
const std::string_view fragmentReturnAttributeAndType{
depthDestination ? "@builtin(frag_depth) f32" : "@location(0) vec4<f32>"
};
std::unordered_map<std::string_view, std::string_view> valueByPlaceholderName{
const std::unordered_map<std::string_view, std::string_view>
valueByPlaceholderNameForFragmentSnippet{
{ FRAGMENT_RETURN_ATTRIBUTE_AND_TYPE_PLACEHOLDER, fragmentReturnAttributeAndType },
};
std::string fragmentShaderSnippet;
if (multisampledSource) {
fragmentShaderSnippet = webgpuutils::processPlaceholderTemplate(
FRAGMENT_SHADER_SNIPPET_MSAA_INPUT_TEMPLATE, PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX,
valueByPlaceholderNameForFragmentSnippet);
} else {
if (sourceDimension == wgpu::TextureViewDimension::e3D) {
fragmentShaderSnippet = webgpuutils::processPlaceholderTemplate(
FRAGMENT_SHADER_SNIPPET_3D_INPUT_TEMPLATE, PLACEHOLDER_PREFIX,
PLACEHOLDER_SUFFIX, valueByPlaceholderNameForFragmentSnippet);
} else {
fragmentShaderSnippet = webgpuutils::processPlaceholderTemplate(
FRAGMENT_SHADER_SNIPPET_2D_INPUT_TEMPLATE, PLACEHOLDER_PREFIX,
PLACEHOLDER_SUFFIX, valueByPlaceholderNameForFragmentSnippet);
}
}
const std::unordered_map<std::string_view, std::string_view> valueByPlaceholderNameForModule{
{ TEXTURE_TYPE_PLACEHOLDER, textureType },
{ TEXTURE_2D_TYPE_PLACEHOLDER, texture2dType },
{ SAMPLER_DECLARATION_PLACEHOLDER, samplerDeclaration },
{ FRAGMENT_SHADER_SNIPPET_PLACEHOLDER, fragmentShaderSnippet }
{ FRAGMENT_SHADER_SNIPPET_PLACEHOLDER, fragmentShaderSnippet },
};
const std::string shaderSource{ webgpuutils::processPlaceholderTemplate(SHADER_SOURCE_TEMPLATE,
PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, valueByPlaceholderName) };
PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, valueByPlaceholderNameForModule) };
wgpu::ShaderModuleWGSLDescriptor wgslDescriptor{};
wgslDescriptor.code = shaderSource.data();
const wgpu::ShaderModuleDescriptor shaderModuleDescriptor{
@@ -662,9 +790,11 @@ wgpu::ShaderModule WebGPUBlitter::createShaderModule(
}
size_t WebGPUBlitter::hashShaderModuleKey(const wgpu::TextureViewDimension sourceDimension,
const bool multisampledSource) {
const bool multisampledSource, const bool depthSource, const bool depthDestination) {
size_t seed{ std::hash<uint32_t>{}(static_cast<uint32_t>(sourceDimension)) };
utils::hash::combine(seed, multisampledSource);
utils::hash::combine(seed, depthSource);
utils::hash::combine(seed, depthDestination);
return seed;
}
+20 -12
View File
@@ -31,6 +31,7 @@ public:
struct BlitArgs final {
struct Attachment final {
wgpu::Texture const& texture;
wgpu::TextureAspect aspect{ wgpu::TextureAspect::Undefined };
wgpu::Origin2D origin{};
wgpu::Extent2D extent{};
uint32_t mipLevel{ 0 };
@@ -47,45 +48,52 @@ public:
void blit(wgpu::Queue const&, wgpu::CommandEncoder const&, BlitArgs const&);
private:
/**
* ONLY should be called if canDoDirectCopy(...) is true (see it in WebGPUBlitter.cpp)
*/
void copy(wgpu::CommandEncoder const&, BlitArgs const&);
void createSampler(SamplerMagFilter);
[[nodiscard]] wgpu::RenderPipeline const& getOrCreateRenderPipeline(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, uint32_t sourceSampleCount,
wgpu::TextureFormat destinationTextureFormat);
bool depthSource, wgpu::TextureFormat destinationTextureFormat);
[[nodiscard]] wgpu::RenderPipeline createRenderPipeline(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, uint32_t sourceSampleCount,
wgpu::TextureFormat destinationTextureFormat);
bool depthSource, wgpu::TextureFormat destinationTextureFormat);
[[nodiscard]] static size_t hashRenderPipelineKey(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, uint32_t sourceSampleCount);
wgpu::TextureViewDimension sourceDimension, uint32_t sourceSampleCount,
bool depthSource, wgpu::TextureFormat destinationTextureFormat);
[[nodiscard]] wgpu::PipelineLayout const& getOrCreatePipelineLayout(SamplerMagFilter,
wgpu::TextureViewDimension, bool multisampledSource);
wgpu::TextureViewDimension, bool multisampledSource, bool depthSource);
[[nodiscard]] wgpu::PipelineLayout createPipelineLayout(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, bool multisampledSource);
wgpu::TextureViewDimension sourceDimension, bool multisampledSource, bool depthSource);
[[nodiscard]] static size_t hashPipelineLayoutKey(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, bool multisampledSource);
wgpu::TextureViewDimension sourceDimension, bool multisampledSource, bool depthSource);
[[nodiscard]] wgpu::BindGroupLayout const& getOrCreateTextureBindGroupLayout(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, bool multisampledSource);
wgpu::TextureViewDimension sourceDimension, bool multisampledSource, bool depthSource);
[[nodiscard]] wgpu::BindGroupLayout createTextureBindGroupLayout(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, bool multisampledSource);
wgpu::TextureViewDimension sourceDimension, bool multisampledSource, bool depthSource);
[[nodiscard]] static size_t hashTextureBindGroupLayoutKey(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, bool multisampledSource);
wgpu::TextureViewDimension sourceDimension, bool multisampledSource, bool depthSource);
[[nodiscard]] wgpu::ShaderModule const& getOrCreateShaderModule(
wgpu::TextureViewDimension sourceDimension, bool multisampledSource);
wgpu::TextureViewDimension sourceDimension, bool multisampledSource, bool depthSource,
bool depthDestination);
[[nodiscard]] wgpu::ShaderModule createShaderModule(wgpu::TextureViewDimension sourceDimension,
bool multisampledSource);
bool multisampledSource, bool depthSource, bool depthDestination);
[[nodiscard]] static size_t hashShaderModuleKey(wgpu::TextureViewDimension sourceDimension,
bool multisampledSource);
bool multisampledSource, bool depthSource, bool depthDestination);
wgpu::Device mDevice;
wgpu::Sampler mNearestSampler{ nullptr };
@@ -36,6 +36,18 @@ constexpr size_t FILAMENT_WEBGPU_BUFFER_SIZE_MODULUS = 4;
// appear in order of calls).
#define FWGPU_DEBUG_FORCE_LOG_TO_I 0x00000004
// Set this to enable logging related to the WebGPU backend's update3DImage function, which would
// otherwise spam the logs.
#define FWGPU_DEBUG_UPDATE_IMAGE 0x00000008
// Set this to enable logging related to the WebGPU backend's WebGPUBlitter functionality,
// which would otherwise spam the logs.
#define FWGPU_DEBUG_BLIT 0x00000010
// Set this to enable logging relating to bind groups (bind group layouts, bind groups themselves,
// textures, samplers, and buffers,...), which would otherwise spam the logs.
#define FWGPU_DEBUG_BIND_GROUPS 0x00000020
// Useful default combinations
#define FWGPU_DEBUG_EVERYTHING 0xFFFFFFFF
@@ -16,7 +16,11 @@
#include "WebGPUDescriptorSet.h"
#include "WebGPUConstants.h"
#include "WebGPUDescriptorSetLayout.h"
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
#include "WebGPUStrings.h"
#endif
#include <backend/DriverEnums.h>
@@ -92,6 +96,29 @@ wgpu::BindGroup WebGPUDescriptorSet::lockAndReturn(wgpu::Device const& device) {
mBindGroup = device.CreateBindGroup(&descriptor);
FILAMENT_CHECK_POSTCONDITION(mBindGroup) << "Failed to create bind group?";
// once we have created the bind group itself we should no longer need any other state
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
FWGPU_LOGD << "WebGPUDescriptorSet (lockAndReturn):";
FWGPU_LOGD << " wgpu::BindGroupLayout handle: " << mLayout.Get();
FWGPU_LOGD << " wgpu::BindGroup handle: " << mBindGroup.Get();
FWGPU_LOGD << " Entries with DynamicOffsets: " << mEntriesWithDynamicOffsetsCount;
FWGPU_LOGD << " Entries (" << mEntries.size() << "):";
for (wgpu::BindGroupEntry const& entry: mEntries) {
if (entry.buffer) {
FWGPU_LOGD << " binding:" << entry.binding << " buffer "
<< webGPUPrintableToString(entry.buffer.GetUsage())
<< " buffer size:" << entry.buffer.GetSize() << " offset:" << entry.offset
<< " size:" << (entry.size == wgpu::kWholeSize
? "Whole Size"
: ("Partial/specified Size (" + std::to_string(entry.size) + ")"));
}
if (entry.sampler) {
FWGPU_LOGD << " binding:" << entry.binding << " sampler";
}
if (entry.textureView) {
FWGPU_LOGD << " binding:" << entry.binding << " texture (view)";
}
}
#endif
mLayout = nullptr;
mEntries.clear();
mEntries.shrink_to_fit();
@@ -19,6 +19,8 @@
#include "WebGPUDescriptorSetLayout.h"
#include "WebGPUConstants.h"
#include "DriverBase.h"
#include <backend/DriverEnums.h>
@@ -49,6 +51,10 @@ public:
// May be nullptr. Use lockAndReturn to create the bind group when appropriate
[[nodiscard]] wgpu::BindGroup const& getBindGroup() const { return mBindGroup; }
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
[[nodiscard]] wgpu::BindGroupLayout const& getLayout() const { return mLayout; }
#endif
private:
wgpu::BindGroupLayout mLayout = nullptr;
std::array<uint8_t, MAX_DESCRIPTOR_COUNT> mEntryIndexByBinding{};
@@ -16,6 +16,11 @@
#include "WebGPUDescriptorSetLayout.h"
#include "WebGPUConstants.h"
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
#include "WebGPUStrings.h"
#endif
#include <backend/DriverEnums.h>
#include <utils/BitmaskEnum.h>
@@ -59,7 +64,7 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
std::string baseLabel;
if (std::holds_alternative<utils::StaticString>(layout.label)) {
const auto& temp = std::get_if<utils::StaticString>(&layout.label);
baseLabel = temp->c_str();
baseLabel = temp->c_str() == nullptr ? "" : temp->c_str();
} else if (std::holds_alternative<utils::CString>(layout.label)) {
const auto& temp = std::get_if<utils::CString>(&layout.label);
baseLabel = temp->c_str();
@@ -184,6 +189,19 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
mLayout = device.CreateBindGroupLayout(&layoutDescriptor);
FILAMENT_CHECK_POSTCONDITION(mLayout)
<< "Failed to create bind group layout with label " << label;
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
FWGPU_LOGD << "WebGPUDescriptorSetLayout:";
FWGPU_LOGD << " label: " << label;
FWGPU_LOGD << " wgpu::BindGroupLayout handle: " << mLayout.Get();
FWGPU_LOGD << " Filament bindings (" << layout.bindings.size() << "):";
for (DescriptorSetLayoutBinding const& layoutBinding: layout.bindings) {
FWGPU_LOGD << " binding:" << +layoutBinding.binding
<< " type:" << filamentDescriptorTypeToString(layoutBinding.type)
<< " stageFlags:" << filamentStageFlagsToString(layoutBinding.stageFlags)
<< " flags:" << filamentDescriptorFlagsToString(layoutBinding.flags)
<< " count:" << layoutBinding.count;
}
#endif
}
} // namespace filament::backend
+139 -67
View File
@@ -16,6 +16,7 @@
#include "webgpu/WebGPUDriver.h"
#include "WebGPUBufferObject.h"
#include "WebGPUConstants.h"
#include "WebGPUDescriptorSet.h"
#include "WebGPUDescriptorSetLayout.h"
#include "WebGPUFence.h"
@@ -63,6 +64,28 @@ using namespace std::chrono_literals;
namespace filament::backend {
namespace {
void setDefaultTargetFlags(WebGPURenderTarget& defaultRenderTarget,
WebGPUSwapChain const& swapChain) {
const wgpu::TextureFormat depthFormat{ swapChain.getDepthFormat() };
TargetBufferFlags newTargetFlags{ filament::backend::TargetBufferFlags::NONE };
// Assuming Color always present in default render target.
newTargetFlags |= filament::backend::TargetBufferFlags::COLOR;
if (depthFormat != wgpu::TextureFormat::Undefined) {
if (hasDepth(depthFormat)) {
newTargetFlags |= filament::backend::TargetBufferFlags::DEPTH;
}
if (hasStencil(depthFormat)) {
newTargetFlags |= filament::backend::TargetBufferFlags::STENCIL;
}
}
defaultRenderTarget.setTargetFlags(newTargetFlags);
}
} // namespace
Driver* WebGPUDriver::create(WebGPUPlatform& platform, const Platform::DriverConfig& driverConfig) noexcept {
constexpr size_t defaultSize = FILAMENT_WEBGPU_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
Platform::DriverConfig validConfig {driverConfig};
@@ -383,6 +406,9 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
"rebuilding Filament with that flag, e.g. ./build.sh -x "
<< FWGPU_PRINT_SYSTEM << " ...";
#endif
if (mDefaultRenderTarget) {
setDefaultTargetFlags(*mDefaultRenderTarget, *mSwapChain);
}
}
void WebGPUDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
@@ -391,6 +417,9 @@ void WebGPUDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t wi
mSwapChain = constructHandle<WebGPUSwapChain>(sch, extent, mAdapter,
mDevice, flags);
assert_invariant(mSwapChain);
if (mDefaultRenderTarget) {
setDefaultTargetFlags(*mDefaultRenderTarget, *mSwapChain);
}
}
void WebGPUDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vertexBufferInfoHandle,
@@ -487,6 +516,9 @@ void WebGPUDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> renderTarge
assert_invariant(!mDefaultRenderTarget);
mDefaultRenderTarget = constructHandle<WebGPURenderTarget>(renderTargetHandle);
assert_invariant(mDefaultRenderTarget);
if (mSwapChain) {
setDefaultTargetFlags(*mDefaultRenderTarget, *mSwapChain);
}
}
void WebGPUDriver::createRenderTargetR(Handle<HwRenderTarget> renderTargetHandle,
@@ -576,7 +608,7 @@ FenceStatus WebGPUDriver::getFenceStatus(Handle<HwFence> fenceHandle) {
// We create all textures using VK_IMAGE_TILING_OPTIMAL, so our definition of "supported" is that
// the GPU supports the given texture format with non-zero optimal tiling features.
bool WebGPUDriver::isTextureFormatSupported(const TextureFormat format) {
return WebGPUTexture::fToWGPUTextureFormat(format) != wgpu::TextureFormat::Undefined;
return toWGPUTextureFormat(format) != wgpu::TextureFormat::Undefined;
}
bool WebGPUDriver::isTextureSwizzleSupported() {
@@ -584,18 +616,18 @@ bool WebGPUDriver::isTextureSwizzleSupported() {
}
bool WebGPUDriver::isTextureFormatMipmappable(const TextureFormat format) {
const wgpu::TextureFormat webGpuFormat{ toWGPUTextureFormat(format) };
// passing 2D and sampleCount 1 to only check the format
const WebGPURenderPassMipmapGenerator::FormatCompatibility renderPassCompatibility{
WebGPURenderPassMipmapGenerator::getCompatibilityFor(
WebGPUTexture::fToWGPUTextureFormat(format), wgpu::TextureDimension::e2D, 1)
WebGPURenderPassMipmapGenerator::getCompatibilityFor(webGpuFormat,
wgpu::TextureDimension::e2D, 1)
};
if (renderPassCompatibility.compatible) {
return true;
}
return WebGPUTexture::supportsMultipleMipLevelsViaStorageBinding(
WebGPUTexture::fToWGPUTextureFormat(format));
return WebGPUTexture::supportsMultipleMipLevelsViaStorageBinding(webGpuFormat);
}
bool WebGPUDriver::isRenderTargetFormatSupported(const TextureFormat format) {
@@ -772,16 +804,15 @@ void WebGPUDriver::update3DImage(Handle<HwTexture> textureHandle, const uint32_t
scheduleDestroy(std::move(pixelBufferDescriptor));
return;
}
const wgpu::TextureFormat inputPixelFormat{ toWebGPUFormat(inputData->format,
inputData->type) };
const wgpu::TextureFormat outputLinearFormat{ toWebGPULinearFormat(
const wgpu::TextureFormat outputLinearFormat{ toLinearFormat(
texture->getTexture().GetFormat()) };
const bool conversionNecessary{
inputPixelFormat != outputLinearFormat && inputData->type != PixelDataType::COMPRESSED
}; // compressed formats should never need conversion
const bool doBlit{ conversionNecessary };
#if FWGPU_ENABLED(FWGPU_DEBUG_VALIDATION)
#if FWGPU_ENABLED(FWGPU_DEBUG_UPDATE_IMAGE)
if (texture->width > 1000 && texture->height > 500) {
FWGPU_LOGD << "Update3DImage(..., level=" << level << ", xoffset=" << xoffset
<< ", yoffset=" << yoffset << ", zoffset=" << zoffset << ", width=" << width
@@ -881,6 +912,15 @@ void WebGPUDriver::update3DImage(Handle<HwTexture> textureHandle, const uint32_t
mBlitter.blit(mQueue, mCommandEncoder, blitArgs);
}
if (!reusedCommandEncoder) {
// TODO consider removing encoder finish + submit once we have test coverage and can
// safely verify doing so will not result in strange errors. We don't think this
// submit is necessary, as the encoder should get finished and the command
// submitted in commit(), finish(), and/or flush() in this frame
// or the next anyway. And, the blit bits will be encoded before other things.
// Thus, not submitting here _seems_ ok. Nonetheless, doing the submit here likely
// represents unnecessary inefficiency and higher bandwidth
// between the CPU and GPU, but we are worried about functional correctness at this
// stage.
const wgpu::CommandBufferDescriptor commandBufferDescriptor{
.label = "blit_command_buffer",
};
@@ -974,6 +1014,17 @@ void WebGPUDriver::generateMipmaps(Handle<HwTexture> textureHandle) {
mSpdComputePassMipmapGenerator.Generate(encoder, wgpuTexture, spdConfig);
// Finish the encoder and submit all the passes at once.
// TODO consider reusing the existing command encoder or creating it in this function
// if it doesn't already exist and removing encoder finish + submit here once
// we have test coverage and can safely verify doing so will not result in
// strange errors. We don't think this submit is necessary, as the encoder
// should get finished and the command submitted in
// commit(), finish(), and/or flush() in this frame or the next anyway.
// And, the mipmap generation bits will be encoded before other things.
// Thus, not submitting here _seems_ ok. Nonetheless, doing the submit here likely
// represents unnecessary inefficiency and higher bandwidth
// between the CPU and GPU, but we are worried about functional correctness at this
// stage.
wgpu::CommandBufferDescriptor cmdBufferDesc = {};
cmdBufferDesc.label = "Mipmap Command Buffer";
wgpu::CommandBuffer commandBuffer = encoder.Finish(&cmdBufferDesc);
@@ -1167,23 +1218,6 @@ void WebGPUDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain>
assert_invariant(mTextureView);
assert_invariant(mDefaultRenderTarget);
wgpu::TextureFormat depthFormat = mSwapChain->getDepthFormat();
TargetBufferFlags newTargetFlags = filament::backend::TargetBufferFlags::NONE;
//Assuming Color always present in default render target.
newTargetFlags |= filament::backend::TargetBufferFlags::COLOR;
if (depthFormat != wgpu::TextureFormat::Undefined) {
if (hasDepth(depthFormat)) {
newTargetFlags |= filament::backend::TargetBufferFlags::DEPTH;
}
if (hasStencil(depthFormat)) {
newTargetFlags |= filament::backend::TargetBufferFlags::STENCIL;
}
}
mDefaultRenderTarget->setTargetFlags(newTargetFlags);
if (!mCommandEncoder) {
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = { .label = "frame_command_encoder" };
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
@@ -1294,8 +1328,7 @@ void WebGPUDriver::readPixels(Handle<HwRenderTarget> sourceRenderTargetHandle, c
const size_t dstBytesPerPixel = PixelBufferDescriptor::computePixelSize(
pixelBufferDescriptor.format, pixelBufferDescriptor.type);
const size_t srcBytesPerPixel =
WebGPUTexture::getWGPUTextureFormatPixelSize(srcTexture.GetFormat());
const size_t srcBytesPerPixel = getWGPUTextureFormatPixelSize(srcTexture.GetFormat());
FILAMENT_CHECK_PRECONDITION(dstBytesPerPixel == srcBytesPerPixel && dstBytesPerPixel > 0)
<< "Source texture pixel size (" << srcBytesPerPixel
@@ -1336,6 +1369,15 @@ void WebGPUDriver::readPixels(Handle<HwRenderTarget> sourceRenderTargetHandle, c
wgpu::Extent3D copySize{ .width = actualWidth,
.height = actualHeight,
.depthOrArrayLayers = 1 };
// TODO consider removing encoder finish + submit once we have test coverage and can
// safely verify doing so will not result in strange errors. We don't think this
// submit is necessary, as the encoder should get finished and the command
// submitted in commit(), finish(), and/or flush() in this frame
// or the next anyway. And, the read/copy bits will be encoded before other things.
// Thus, not submitting here _seems_ ok. Nonetheless, doing the submit here likely
// represents unnecessary inefficiency and higher bandwidth
// between the CPU and GPU, but we are worried about functional correctness at this
// stage.
encoder.CopyTextureToBuffer(&source, &destination, &copySize);
wgpu::CommandBuffer commandBuffer = encoder.Finish();
mQueue.Submit(1, &commandBuffer);
@@ -1388,7 +1430,9 @@ void WebGPUDriver::readBufferSubData(Handle<HwBufferObject> bufferObjectHandle,
void WebGPUDriver::blitDEPRECATED(TargetBufferFlags buffers,
Handle<HwRenderTarget> destinationRenderTargetHandle, const Viewport destinationViewport,
Handle<HwRenderTarget> sourceRenderTargetHandle, const Viewport sourceViewport,
const SamplerMagFilter filter) {}
const SamplerMagFilter filter) {
PANIC_PRECONDITION("WebGPUDriver::blitDEPRECATED not supported");
}
void WebGPUDriver::resolve(Handle<HwTexture> destinationTextureHandle, const uint8_t sourceLevel,
const uint8_t sourceLayer, Handle<HwTexture> sourceTextureHandle,
@@ -1426,45 +1470,56 @@ void WebGPUDriver::blit(Handle<HwTexture> destinationTextureHandle, const uint8_
const uint8_t sourceLayer, const math::uint2 destinationOrigin,
Handle<HwTexture> sourceTextureHandle, const uint8_t destinationLevel,
const uint8_t destinationLayer, const math::uint2 sourceOrigin, const math::uint2 size) {
// TODO uncomment when texture format is taken into account with sampler settings in the
// blitter
// bool reusedCommandEncoder{ true };
// if (!mCommandEncoder) {
// reusedCommandEncoder = false;
// const wgpu::CommandEncoderDescriptor commandEncoderDescriptor{
// .label = "blit_command",
// };
// mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
// FILAMENT_CHECK_POSTCONDITION(mCommandEncoder)
// << "Failed to create command encoder for blit?";
// }
// const WebGPUBlitter::BlitArgs blitArgs{
// .source = {
// .texture = handleCast<WebGPUTexture>(sourceTextureHandle)->getTexture(),
// .origin = {.x = sourceOrigin.x, .y=sourceOrigin.y},
// .extent = {.width=size.x, .height =size.y},
// .mipLevel = sourceLevel,
// .layerOrDepth = sourceLayer,
// },
// .destination = {
// .texture = handleCast<WebGPUTexture>(destinationTextureHandle)->getTexture(),
// .origin = {.x = destinationOrigin.x, .y=destinationOrigin.y},
// .extent = {.width=size.x, .height =size.y},
// .mipLevel = destinationLevel,
// .layerOrDepth = destinationLayer,
// },
// .filter = SamplerMagFilter::NEAREST,
// };
// mBlitter.blit(mQueue, mCommandEncoder, blitArgs);
// if (!reusedCommandEncoder) {
// const wgpu::CommandBufferDescriptor commandBufferDescriptor{
// .label = "blit_command_buffer",
// };
// const wgpu::CommandBuffer blitCommand{ mCommandEncoder.Finish(&commandBufferDescriptor) };
// FILAMENT_CHECK_POSTCONDITION(blitCommand) << "Failed to create command buffer for blit?";
// mQueue.Submit(1, &blitCommand);
// mCommandEncoder = nullptr;
// }
bool reusedCommandEncoder{ true };
if (!mCommandEncoder) {
reusedCommandEncoder = false;
const wgpu::CommandEncoderDescriptor commandEncoderDescriptor{
.label = "blit_command",
};
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
FILAMENT_CHECK_POSTCONDITION(mCommandEncoder)
<< "Failed to create command encoder for blit?";
}
const auto sourceTexture{ handleCast<WebGPUTexture>(sourceTextureHandle) };
const auto destinationTexture{ handleCast<WebGPUTexture>(destinationTextureHandle) };
const WebGPUBlitter::BlitArgs blitArgs{
.source = {
.texture = sourceTexture->getTexture(),
.aspect = sourceTexture->getAspect(),
.origin = {.x = sourceOrigin.x, .y=sourceOrigin.y},
.extent = {.width=size.x, .height =size.y},
.mipLevel = sourceLevel,
.layerOrDepth = sourceLayer,
},
.destination = {
.texture = destinationTexture->getTexture(),
.aspect = destinationTexture->getAspect(),
.origin = {.x = destinationOrigin.x, .y=destinationOrigin.y},
.extent = {.width=size.x, .height =size.y},
.mipLevel = destinationLevel,
.layerOrDepth = destinationLayer,
},
.filter = SamplerMagFilter::NEAREST,
};
mBlitter.blit(mQueue, mCommandEncoder, blitArgs);
if (!reusedCommandEncoder) {
// TODO consider removing encoder finish + submit once we have test coverage and can
// safely verify doing so will not result in strange errors. We don't think this
// submit is necessary, as the encoder should get finished and the command submitted in
// commit(), finish(), and/or flush() in this frame or the next anyway.
// And, the blit bits will be encoded before other things.
// Thus, not submitting here _seems_ ok. Nonetheless, doing the submit here likely
// represents unnecessary inefficiency and higher bandwidth
// between the CPU and GPU, but we are worried about functional correctness at this
// stage.
const wgpu::CommandBufferDescriptor commandBufferDescriptor{
.label = "blit_command_buffer",
};
const wgpu::CommandBuffer blitCommand{ mCommandEncoder.Finish(&commandBufferDescriptor) };
FILAMENT_CHECK_POSTCONDITION(blitCommand) << "Failed to create command buffer for blit?";
mQueue.Submit(1, &blitCommand);
mCommandEncoder = nullptr;
}
}
void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
@@ -1659,6 +1714,23 @@ void WebGPUDriver::updateDescriptorSetTexture(Handle<HwDescriptorSet> descriptor
.binding = static_cast<uint32_t>(binding * 2 + 1),
.sampler = sampler };
bindGroup->addEntry(sEntry.binding, std::move(sEntry));
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
FWGPU_LOGD << "updateDescriptorSetTexture:";
FWGPU_LOGD << " wgpu::BindGroupLayout handle: " << bindGroup->getLayout().Get();
FWGPU_LOGD << " texture: binding:" << tEntry.binding
<< " wgpu handle:" << texture->getTexture().Get()
<< " " << webGPUTextureToString(texture->getTexture())
<< " " << webGPUPrintableToString(texture->getAspect());
FWGPU_LOGD << " sampler: binding:" << sEntry.binding
<< " filterMag:" << filamentSamplerMagFilterToString(params.filterMag)
<< " filterMin:" << filamentSamplerMinFilterToString(params.filterMin)
<< " wrapS:" << filamentSamplerWrapModeToString(params.wrapS)
<< " wrapT:" << filamentSamplerWrapModeToString(params.wrapT)
<< " wrapR:" << filamentSamplerWrapModeToString(params.wrapR)
<< " anisotropyLog2:" << +params.anisotropyLog2
<< " compareMode:" << filamentSamplerCompareModeToString(params.compareMode)
<< " compareFunc:" << filamentSamplerCompareFuncToString(params.compareFunc);
#endif
}
}
@@ -16,7 +16,7 @@
#include "WebGPUMsaaTextureResolver.h"
#include "WebGPUTexture.h"
#include "WebGPUTextureHelpers.h"
#include <utils/Panic.h>
@@ -17,7 +17,7 @@
#include "WebGPUPipelineCache.h"
#include "WebGPUConstants.h"
#include "WebGPUTexture.h"
#include "WebGPUTextureHelpers.h"
#include "WebGPUVertexBufferInfo.h"
#include <backend/DriverEnums.h>
@@ -125,7 +125,7 @@ WebGPURenderTarget::WebGPURenderTarget(const uint32_t width, const uint32_t heig
mDefaultRenderTarget{ false },
mTargetFlags{ targetFlags },
mSamples{ samples },
mLayerCount{ layerCount },
mLayerCount{ layerCount <= 0 ? static_cast<uint8_t>(1) : layerCount },
mColorAttachments{ colorAttachmentsMRT },
mDepthAttachment{ depthAttachmentInfo },
mStencilAttachment{ stencilAttachmentInfo },
@@ -140,7 +140,9 @@ WebGPURenderTarget::WebGPURenderTarget(const uint32_t width, const uint32_t heig
WebGPURenderTarget::WebGPURenderTarget()
: HwRenderTarget{ 0, 0 },
mDefaultRenderTarget{ true },
mTargetFlags{ TargetBufferFlags::NONE },
// starting with the initial assumption that the default render target has a single color
// attachment and a depth attachment, not necessarily a depth attachment
mTargetFlags{ TargetBufferFlags::COLOR0 | TargetBufferFlags::DEPTH },
mSamples{ 1 },
mLayerCount{ 1 },
mSampleCountPerAttachment{ 1 } {}
+235 -1
View File
@@ -36,7 +36,10 @@
namespace filament::backend {
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) \
|| FWGPU_ENABLED(FWGPU_DEBUG_UPDATE_IMAGE) \
|| FWGPU_ENABLED(FWGPU_DEBUG_BLIT)\
|| FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
template<typename WebGPUPrintable>
[[nodiscard]] inline std::string webGPUPrintableToString(const WebGPUPrintable printable) {
std::stringstream out;
@@ -239,6 +242,37 @@ template<typename WebGPUPrintable>
}
}
[[nodiscard]] constexpr std::string_view webGPUTextureDimensionToString(
const wgpu::TextureDimension dimension) {
switch (dimension) {
case wgpu::TextureDimension::Undefined: return "Undefined";
case wgpu::TextureDimension::e1D: return "e1D";
case wgpu::TextureDimension::e2D: return "e2D";
case wgpu::TextureDimension::e3D: return "e3D";
}
}
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) \
|| FWGPU_ENABLED(FWGPU_DEBUG_UPDATE_IMAGE) \
|| FWGPU_ENABLED(FWGPU_DEBUG_BLIT) \
|| FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
[[nodiscard]] inline std::string webGPUTextureToString(wgpu::Texture const& texture) {
if (texture == nullptr) {
return "nullptr (no wgpu::Texture)";
}
std::stringstream out;
out << "wgpu::Texture("
<< " format:" << webGPUTextureFormatToString(texture.GetFormat())
<< " dimension:" << webGPUTextureDimensionToString(texture.GetDimension())
<< " " << webGPUPrintableToString(texture.GetUsage())
<< " mipLevelCount:" << texture.GetMipLevelCount()
<< " sampleCount:" << texture.GetSampleCount() << " width:" << texture.GetWidth()
<< " height:" << texture.GetHeight()
<< " depthOrArrayLayers:" << texture.GetDepthOrArrayLayers() << ")";
return out.str();
}
#endif
[[nodiscard]] constexpr std::string_view filamentShaderStageToString(const ShaderStage stage) {
switch (stage) {
case ShaderStage::VERTEX: return "vertex";
@@ -247,6 +281,206 @@ template<typename WebGPUPrintable>
}
}
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
[[nodiscard]] constexpr std::string_view filamentDescriptorTypeToString(const DescriptorType type) {
switch (type) {
case DescriptorType::SAMPLER_2D_FLOAT: return "SAMPLER_2D_FLOAT";
case DescriptorType::SAMPLER_2D_INT: return "SAMPLER_2D_INT";
case DescriptorType::SAMPLER_2D_UINT: return "SAMPLER_2D_UINT";
case DescriptorType::SAMPLER_2D_DEPTH: return "SAMPLER_2D_DEPTH";
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT: return "SAMPLER_2D_ARRAY_FLOAT";
case DescriptorType::SAMPLER_2D_ARRAY_INT: return "SAMPLER_2D_ARRAY_INT";
case DescriptorType::SAMPLER_2D_ARRAY_UINT: return "SAMPLER_2D_ARRAY_UINT";
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH: return "SAMPLER_2D_ARRAY_DEPTH";
case DescriptorType::SAMPLER_CUBE_FLOAT: return "SAMPLER_CUBE_FLOAT";
case DescriptorType::SAMPLER_CUBE_INT: return "SAMPLER_CUBE_INT";
case DescriptorType::SAMPLER_CUBE_UINT: return "SAMPLER_CUBE_UINT";
case DescriptorType::SAMPLER_CUBE_DEPTH: return "SAMPLER_CUBE_DEPTH";
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT: return "SAMPLER_CUBE_ARRAY_FLOAT";
case DescriptorType::SAMPLER_CUBE_ARRAY_INT: return "SAMPLER_CUBE_ARRAY_INT";
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT: return "SAMPLER_CUBE_ARRAY_UINT";
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH: return "SAMPLER_CUBE_ARRAY_DEPTH";
case DescriptorType::SAMPLER_3D_FLOAT: return "SAMPLER_3D_FLOAT";
case DescriptorType::SAMPLER_3D_INT: return "SAMPLER_3D_INT";
case DescriptorType::SAMPLER_3D_UINT: return "SAMPLER_3D_UINT";
case DescriptorType::SAMPLER_2D_MS_FLOAT: return "SAMPLER_2D_MS_FLOAT";
case DescriptorType::SAMPLER_2D_MS_INT: return "SAMPLER_2D_MS_INT";
case DescriptorType::SAMPLER_2D_MS_UINT: return "SAMPLER_2D_MS_UINT";
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT: return "SAMPLER_2D_MS_ARRAY_FLOAT";
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT: return "SAMPLER_2D_MS_ARRAY_INT";
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT: return "SAMPLER_2D_MS_ARRAY_UINT";
case DescriptorType::SAMPLER_EXTERNAL: return "SAMPLER_EXTERNAL";
case DescriptorType::UNIFORM_BUFFER: return "UNIFORM_BUFFER";
case DescriptorType::SHADER_STORAGE_BUFFER: return "SHADER_STORAGE_BUFFER";
case DescriptorType::INPUT_ATTACHMENT: return "INPUT_ATTACHMENT";
}
}
[[nodiscard]] constexpr std::string_view filamentStageFlagsToString(const ShaderStageFlags flags) {
if (flags == ShaderStageFlags::FRAGMENT) {
return "FRAGMENT";
}
if (flags == (ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT)) {
return "VERTEX | FRAGMENT";
}
if (flags == ShaderStageFlags::VERTEX) {
return "VERTEX";
}
if (flags == ShaderStageFlags::COMPUTE) {
return "COMPUTE";
}
if (flags == ShaderStageFlags::ALL_SHADER_STAGE_FLAGS) {
return "VERTEX | FRAGMENT | COMPUTE";
}
if (flags == (ShaderStageFlags::FRAGMENT | ShaderStageFlags::COMPUTE)) {
return "FRAGMENT | COMPUTE";
}
if (flags == (ShaderStageFlags::VERTEX | ShaderStageFlags::COMPUTE)) {
return "VERTEX | COMPUTE";
}
if (flags == ShaderStageFlags::NONE) {
return "NONE";
}
return "UNKNOWN/UNHANDLED"; // should not be possible
}
[[nodiscard]] constexpr std::string_view filamentDescriptorFlagsToString(const DescriptorFlags flags) {
if (flags == DescriptorFlags::NONE) {
return "NONE";
}
if (flags == DescriptorFlags::DYNAMIC_OFFSET) {
return "DYNAMIC_OFFSET";
}
if (flags == DescriptorFlags::UNFILTERABLE) {
return "UNFILTERABLE";
}
if (flags == (DescriptorFlags::DYNAMIC_OFFSET | DescriptorFlags::UNFILTERABLE)) {
return "DYNAMIC_OFFSET | UNFILTERABLE";
}
return "UNKNOWN/UNHANDLED"; // should not be possible
}
[[nodiscard]] constexpr std::string_view filamentSamplerMagFilterToString(
const SamplerMagFilter filter) {
switch (filter) {
case SamplerMagFilter::NEAREST: return "NEAREST";
case SamplerMagFilter::LINEAR: return "LINEAR";
}
}
[[nodiscard]] constexpr std::string_view filamentSamplerMinFilterToString(
const SamplerMinFilter filter) {
switch (filter) {
case SamplerMinFilter::NEAREST: return "NEAREST";
case SamplerMinFilter::LINEAR: return "LINEAR";
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: return "NEAREST_MIPMAP_NEAREST";
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: return "LINEAR_MIPMAP_NEAREST";
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: return "NEAREST_MIPMAP_LINEAR";
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: return "LINEAR_MIPMAP_LINEAR";
}
}
[[nodiscard]] constexpr std::string_view filamentSamplerWrapModeToString(
const SamplerWrapMode mode) {
switch (mode) {
case SamplerWrapMode::CLAMP_TO_EDGE: return "CLAMP_TO_EDGE";
case SamplerWrapMode::REPEAT: return "REPEAT";
case SamplerWrapMode::MIRRORED_REPEAT: return "MIRRORED_REPEAT";
}
}
[[nodiscard]] constexpr std::string_view filamentSamplerCompareModeToString(
const SamplerCompareMode mode) {
switch (mode) {
case SamplerCompareMode::NONE: return "NONE";
case SamplerCompareMode::COMPARE_TO_TEXTURE: return "COMPARE_TO_TEXTURE";
}
}
[[nodiscard]] constexpr std::string_view filamentSamplerCompareFuncToString(
const SamplerCompareFunc func) {
switch (func) {
case SamplerCompareFunc::LE: return "LE";
case SamplerCompareFunc::GE: return "GE";
case SamplerCompareFunc::L: return "L";
case SamplerCompareFunc::G: return "G";
case SamplerCompareFunc::E: return "E";
case SamplerCompareFunc::NE: return "NE";
case SamplerCompareFunc::A: return "A";
case SamplerCompareFunc::N: return "N";
}
}
[[nodiscard]] inline std::string filamentTextureUsageFlagsToString(const TextureUsage flags) {
if (flags == TextureUsage::NONE) {
return "NONE";
}
bool first{ true };
std::stringstream out;
if (any(flags & TextureUsage::COLOR_ATTACHMENT)) {
first = false;
out << "COLOR_ATTACHMENT";
}
if (any(flags & TextureUsage::DEPTH_ATTACHMENT)) {
if (!first) {
out << " | ";
}
first = false;
out << "DEPTH_ATTACHMENT";
}
if (any(flags & TextureUsage::STENCIL_ATTACHMENT)) {
if (!first) {
out << " | ";
}
first = false;
out << "STENCIL_ATTACHMENT";
}
if (any(flags & TextureUsage::UPLOADABLE)) {
if (!first) {
out << " | ";
}
first = false;
out << "UPLOADABLE";
}
if (any(flags & TextureUsage::SAMPLEABLE)) {
if (!first) {
out << " | ";
}
first = false;
out << "SAMPLEABLE";
}
if (any(flags & TextureUsage::SUBPASS_INPUT)) {
if (!first) {
out << " | ";
}
first = false;
out << "SUBPASS_INPUT";
}
if (any(flags & TextureUsage::BLIT_SRC)) {
if (!first) {
out << " | ";
}
first = false;
out << "BLIT_SRC";
}
if (any(flags & TextureUsage::BLIT_DST)) {
if (!first) {
out << " | ";
}
first = false;
out << "BLIT_DST";
}
if (any(flags & TextureUsage::PROTECTED)) {
if (!first) {
out << " | ";
}
first = false;
out << "PROTECTED";
}
return out.str();
}
#endif // FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
}// namespace filament::backend
#endif// TNT_FILAMENT_BACKEND_WEBGPUSTRINGS_H
+12 -298
View File
@@ -19,6 +19,7 @@
#include "WebGPUConstants.h"
#include "WebGPURenderPassMipmapGenerator.h"
#include "WebGPUStrings.h"
#include "WebGPUTextureHelpers.h"
#include "DriverBase.h"
#include "private/backend/BackendUtils.h"
@@ -64,37 +65,6 @@ namespace {
}
}
/**
* @param format texture format to potentially be used for storage binding
* @return true if the format is compatible with wgpu::TextureUsage::StorageBinding
*/
[[nodiscard]] constexpr bool isFormatStorageCompatible(const wgpu::TextureFormat format) {
switch (format) {
// List of formats that support storage binding
case wgpu::TextureFormat::R32Float:
case wgpu::TextureFormat::R32Sint:
case wgpu::TextureFormat::R32Uint:
case wgpu::TextureFormat::RG32Float:
case wgpu::TextureFormat::RG32Sint:
case wgpu::TextureFormat::RG32Uint:
case wgpu::TextureFormat::RGBA16Float:
case wgpu::TextureFormat::RGBA16Sint:
case wgpu::TextureFormat::RGBA16Uint:
case wgpu::TextureFormat::RGBA32Float:
case wgpu::TextureFormat::RGBA32Sint:
case wgpu::TextureFormat::RGBA32Uint:
case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA8Snorm:
case wgpu::TextureFormat::RGBA8Uint:
case wgpu::TextureFormat::RGBA8Sint:
return true;
default:
// All other formats, including packed floats (RG11B10Ufloat),
// depth/stencil, and sRGB formats do not support storage.
return false;
}
}
/**
* @param viewFormat potential view format to a texture
* @return an underlying texture format that is storage binding compatible for which this view
@@ -173,11 +143,13 @@ namespace {
retUsage |= wgpu::TextureUsage::RenderAttachment;
}
if (any(TextureUsage::BLIT_SRC & fUsage)) {
retUsage |= wgpu::TextureUsage::RenderAttachment;
retUsage |= wgpu::TextureUsage::TextureBinding;
}
if (any(TextureUsage::BLIT_DST & fUsage)) {
retUsage |= wgpu::TextureUsage::RenderAttachment;
retUsage |= wgpu::TextureUsage::TextureBinding;
}
if (any(TextureUsage::GEN_MIPMAPPABLE & fUsage)) {
retUsage |= (wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding);
}
// WGPU Render attachment covers either color or stencil situation dependant
// NOTE: Depth attachment isn't used this way in Vulkan but logically maps to WGPU docs. If
@@ -249,30 +221,6 @@ namespace {
return wgpu::TextureAspect::All;
}
[[nodiscard]] constexpr wgpu::TextureViewDimension toWebGPUTextureViewDimension(
const SamplerType samplerType) {
switch (samplerType) {
case SamplerType::SAMPLER_2D: return wgpu::TextureViewDimension::e2D;
case SamplerType::SAMPLER_2D_ARRAY: return wgpu::TextureViewDimension::e2DArray;
case SamplerType::SAMPLER_CUBEMAP: return wgpu::TextureViewDimension::Cube;
case SamplerType::SAMPLER_EXTERNAL: return wgpu::TextureViewDimension::e2D;
case SamplerType::SAMPLER_3D: return wgpu::TextureViewDimension::e3D;
case SamplerType::SAMPLER_CUBEMAP_ARRAY: return wgpu::TextureViewDimension::CubeArray;
}
}
[[nodiscard]] constexpr wgpu::TextureDimension toWebGPUTextureDimension(
const SamplerType samplerType) {
switch (samplerType) {
case SamplerType::SAMPLER_2D: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_2D_ARRAY: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_CUBEMAP: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_EXTERNAL: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_3D: return wgpu::TextureDimension::e3D;
case SamplerType::SAMPLER_CUBEMAP_ARRAY: return wgpu::TextureDimension::e2D;
}
}
[[nodiscard]] WebGPUTexture::MipmapGenerationStrategy determineMipmapGenerationStrategy(
const wgpu::TextureFormat format, const SamplerType samplerType, const uint8_t sampleCount,
const uint8_t mipmapLevels) {
@@ -324,82 +272,12 @@ namespace {
} // namespace
size_t WebGPUTexture::getWGPUTextureFormatPixelSize(const wgpu::TextureFormat format) {
switch (format) {
// 1 byte
case wgpu::TextureFormat::R8Unorm:
case wgpu::TextureFormat::R8Snorm:
case wgpu::TextureFormat::R8Uint:
case wgpu::TextureFormat::R8Sint:
case wgpu::TextureFormat::Stencil8:
return 1;
// 2 bytes
case wgpu::TextureFormat::R16Uint:
case wgpu::TextureFormat::R16Sint:
case wgpu::TextureFormat::R16Float:
case wgpu::TextureFormat::RG8Unorm:
case wgpu::TextureFormat::RG8Snorm:
case wgpu::TextureFormat::RG8Uint:
case wgpu::TextureFormat::RG8Sint:
case wgpu::TextureFormat::Depth16Unorm:
return 2;
// 4 bytes
// -- 32-bit single-channel formats
case wgpu::TextureFormat::R32Float:
case wgpu::TextureFormat::R32Uint:
case wgpu::TextureFormat::R32Sint:
// -- 16-bit two-channel formats
case wgpu::TextureFormat::RG16Uint:
case wgpu::TextureFormat::RG16Sint:
case wgpu::TextureFormat::RG16Float:
// -- 8-bit four-channel formats
case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA8UnormSrgb:
case wgpu::TextureFormat::RGBA8Snorm:
case wgpu::TextureFormat::RGBA8Uint:
case wgpu::TextureFormat::RGBA8Sint:
case wgpu::TextureFormat::BGRA8Unorm:
case wgpu::TextureFormat::BGRA8UnormSrgb:
// -- Packed 32-bit formats
case wgpu::TextureFormat::RGB10A2Unorm:
case wgpu::TextureFormat::RGB10A2Uint:
case wgpu::TextureFormat::RG11B10Ufloat:
case wgpu::TextureFormat::RGB9E5Ufloat:
// -- Depth/Stencil formats
case wgpu::TextureFormat::Depth32Float:
case wgpu::TextureFormat::Depth24Plus:
case wgpu::TextureFormat::Depth24PlusStencil8:
return 4;
// 8 bytes
case wgpu::TextureFormat::RG32Float:
case wgpu::TextureFormat::RG32Uint:
case wgpu::TextureFormat::RG32Sint:
case wgpu::TextureFormat::RGBA16Uint:
case wgpu::TextureFormat::RGBA16Sint:
case wgpu::TextureFormat::RGBA16Float:
return 8;
// 16 bytes
case wgpu::TextureFormat::RGBA32Float:
case wgpu::TextureFormat::RGBA32Uint:
case wgpu::TextureFormat::RGBA32Sint:
return 16;
// Non-copyable or compressed formats
case wgpu::TextureFormat::Depth32FloatStencil8: // Not copyable from texture to buffer
default:
return 0;
}
}
WebGPUTexture::WebGPUTexture(const SamplerType samplerType, const uint8_t levels,
const TextureFormat format, const uint8_t samples, const uint32_t width,
const uint32_t height, const uint32_t depth, const TextureUsage usage,
wgpu::Device const& device) noexcept
: HwTexture{ samplerType, levels, samples, width, height, depth, format, usage },
mViewFormat{ fToWGPUTextureFormat(format) },
mViewFormat{ toWGPUTextureFormat(format) },
mMipmapGenerationStrategy{ determineMipmapGenerationStrategy(mViewFormat, samplerType,
samples, levels) },
mWebGPUFormat{ mMipmapGenerationStrategy == MipmapGenerationStrategy::SPD_COMPUTE_PASS
@@ -453,6 +331,12 @@ WebGPUTexture::WebGPUTexture(const SamplerType samplerType, const uint8_t levels
<< viewFormatStream.str() << " and texture format " << textureFormatStream.str();
}
#endif
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
FWGPU_LOGD << "WebGPUTexture: wgpu handle " << mTexture.Get()
<< " samplerType:" << to_string(samplerType)
<< " usage flags:" << filamentTextureUsageFlagsToString(usage)
<< " " << webGPUTextureToString(mTexture);
#endif
}
WebGPUTexture::WebGPUTexture(WebGPUTexture const* src, const uint8_t baseLevel,
@@ -565,176 +449,6 @@ wgpu::TextureView WebGPUTexture::makeMsaaSidecarTextureViewIfTextureSidecarExist
return textureView;
}
wgpu::TextureFormat WebGPUTexture::fToWGPUTextureFormat(TextureFormat const& fFormat) {
switch (fFormat) {
case TextureFormat::R8: return wgpu::TextureFormat::R8Unorm;
case TextureFormat::R8_SNORM: return wgpu::TextureFormat::R8Snorm;
case TextureFormat::R8UI: return wgpu::TextureFormat::R8Uint;
case TextureFormat::R8I: return wgpu::TextureFormat::R8Sint;
case TextureFormat::STENCIL8: return wgpu::TextureFormat::Stencil8;
case TextureFormat::R16F: return wgpu::TextureFormat::R16Float;
case TextureFormat::R16UI: return wgpu::TextureFormat::R16Uint;
case TextureFormat::R16I: return wgpu::TextureFormat::R16Sint;
case TextureFormat::RG8: return wgpu::TextureFormat::RG8Unorm;
case TextureFormat::RG8_SNORM: return wgpu::TextureFormat::RG8Snorm;
case TextureFormat::RG8UI: return wgpu::TextureFormat::RG8Uint;
case TextureFormat::RG8I: return wgpu::TextureFormat::RG8Sint;
case TextureFormat::R32F: return wgpu::TextureFormat::R32Float;
case TextureFormat::R32UI: return wgpu::TextureFormat::R32Uint;
case TextureFormat::R32I: return wgpu::TextureFormat::R32Sint;
case TextureFormat::RG16F: return wgpu::TextureFormat::RG16Float;
case TextureFormat::RG16UI: return wgpu::TextureFormat::RG16Uint;
case TextureFormat::RG16I: return wgpu::TextureFormat::RG16Sint;
case TextureFormat::RGBA8: return wgpu::TextureFormat::RGBA8Unorm;
case TextureFormat::SRGB8_A8: return wgpu::TextureFormat::RGBA8UnormSrgb;
case TextureFormat::RGBA8_SNORM: return wgpu::TextureFormat::RGBA8Snorm;
case TextureFormat::RGBA8UI: return wgpu::TextureFormat::RGBA8Uint;
case TextureFormat::RGBA8I: return wgpu::TextureFormat::RGBA8Sint;
case TextureFormat::DEPTH16: return wgpu::TextureFormat::Depth16Unorm;
case TextureFormat::DEPTH24: return wgpu::TextureFormat::Depth24Plus;
case TextureFormat::DEPTH32F: return wgpu::TextureFormat::Depth32Float;
case TextureFormat::DEPTH24_STENCIL8: return wgpu::TextureFormat::Depth24PlusStencil8;
case TextureFormat::DEPTH32F_STENCIL8: return wgpu::TextureFormat::Depth32FloatStencil8;
case TextureFormat::RG32F: return wgpu::TextureFormat::RG32Float;
case TextureFormat::RG32UI: return wgpu::TextureFormat::RG32Uint;
case TextureFormat::RG32I: return wgpu::TextureFormat::RG32Sint;
case TextureFormat::RGBA16F: return wgpu::TextureFormat::RGBA16Float;
case TextureFormat::RGBA16UI: return wgpu::TextureFormat::RGBA16Uint;
case TextureFormat::RGBA16I: return wgpu::TextureFormat::RGBA16Sint;
case TextureFormat::RGBA32F: return wgpu::TextureFormat::RGBA32Float;
case TextureFormat::RGBA32UI: return wgpu::TextureFormat::RGBA32Uint;
case TextureFormat::RGBA32I: return wgpu::TextureFormat::RGBA32Sint;
case TextureFormat::EAC_R11: return wgpu::TextureFormat::EACR11Unorm;
case TextureFormat::EAC_R11_SIGNED: return wgpu::TextureFormat::EACR11Snorm;
case TextureFormat::EAC_RG11: return wgpu::TextureFormat::EACRG11Unorm;
case TextureFormat::EAC_RG11_SIGNED: return wgpu::TextureFormat::EACRG11Snorm;
case TextureFormat::ETC2_RGB8: return wgpu::TextureFormat::ETC2RGB8Unorm;
case TextureFormat::ETC2_SRGB8: return wgpu::TextureFormat::ETC2RGB8UnormSrgb;
case TextureFormat::ETC2_RGB8_A1: return wgpu::TextureFormat::ETC2RGB8A1Unorm;
case TextureFormat::ETC2_SRGB8_A1: return wgpu::TextureFormat::ETC2RGB8A1UnormSrgb;
case TextureFormat::ETC2_EAC_RGBA8: return wgpu::TextureFormat::ETC2RGBA8Unorm;
case TextureFormat::ETC2_EAC_SRGBA8: return wgpu::TextureFormat::ETC2RGBA8UnormSrgb;
case TextureFormat::RGBA_ASTC_4x4: return wgpu::TextureFormat::ASTC4x4Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_4x4: return wgpu::TextureFormat::ASTC4x4UnormSrgb;
case TextureFormat::RGBA_ASTC_5x4: return wgpu::TextureFormat::ASTC5x4Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_5x4: return wgpu::TextureFormat::ASTC5x4UnormSrgb;
case TextureFormat::RGBA_ASTC_5x5: return wgpu::TextureFormat::ASTC5x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_5x5: return wgpu::TextureFormat::ASTC5x5UnormSrgb;
case TextureFormat::RGBA_ASTC_6x5: return wgpu::TextureFormat::ASTC6x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_6x5: return wgpu::TextureFormat::ASTC6x5UnormSrgb;
case TextureFormat::RGBA_ASTC_6x6: return wgpu::TextureFormat::ASTC6x6Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_6x6: return wgpu::TextureFormat::ASTC6x6UnormSrgb;
case TextureFormat::RGBA_ASTC_8x5: return wgpu::TextureFormat::ASTC8x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_8x5: return wgpu::TextureFormat::ASTC8x5UnormSrgb;
case TextureFormat::RGBA_ASTC_8x6: return wgpu::TextureFormat::ASTC8x6Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_8x6: return wgpu::TextureFormat::ASTC8x6UnormSrgb;
case TextureFormat::RGBA_ASTC_8x8: return wgpu::TextureFormat::ASTC8x8Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_8x8: return wgpu::TextureFormat::ASTC8x8UnormSrgb;
case TextureFormat::RGBA_ASTC_10x5: return wgpu::TextureFormat::ASTC10x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x5: return wgpu::TextureFormat::ASTC10x5UnormSrgb;
case TextureFormat::RGBA_ASTC_10x6: return wgpu::TextureFormat::ASTC10x6Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x6: return wgpu::TextureFormat::ASTC10x6UnormSrgb;
case TextureFormat::RGBA_ASTC_10x8: return wgpu::TextureFormat::ASTC10x8Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x8: return wgpu::TextureFormat::ASTC10x8UnormSrgb;
case TextureFormat::RGBA_ASTC_10x10: return wgpu::TextureFormat::ASTC10x10Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x10: return wgpu::TextureFormat::ASTC10x10UnormSrgb;
case TextureFormat::RGBA_ASTC_12x10: return wgpu::TextureFormat::ASTC12x10Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_12x10: return wgpu::TextureFormat::ASTC12x10UnormSrgb;
case TextureFormat::RGBA_ASTC_12x12: return wgpu::TextureFormat::ASTC12x12Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_12x12: return wgpu::TextureFormat::ASTC12x12UnormSrgb;
case TextureFormat::RED_RGTC1: return wgpu::TextureFormat::BC4RUnorm;
case TextureFormat::SIGNED_RED_RGTC1: return wgpu::TextureFormat::BC4RSnorm;
case TextureFormat::RED_GREEN_RGTC2: return wgpu::TextureFormat::BC5RGUnorm;
case TextureFormat::SIGNED_RED_GREEN_RGTC2: return wgpu::TextureFormat::BC5RGSnorm;
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT: return wgpu::TextureFormat::BC6HRGBUfloat;
case TextureFormat::RGB_BPTC_SIGNED_FLOAT: return wgpu::TextureFormat::BC6HRGBFloat;
case TextureFormat::RGBA_BPTC_UNORM: return wgpu::TextureFormat::BC7RGBAUnorm;
case TextureFormat::SRGB_ALPHA_BPTC_UNORM: return wgpu::TextureFormat::BC7RGBAUnormSrgb;
case TextureFormat::RGB565:
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
// and discard the alpha and lower precision.
FWGPU_LOGW << "Requested Filament texture format RGB565 but getting "
"wgpu::TextureFormat::Undefined (no direct mapping in wgpu)";
return wgpu::TextureFormat::Undefined;
case TextureFormat::RGB9_E5: return wgpu::TextureFormat::RGB9E5Ufloat;
case TextureFormat::RGB5_A1:
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
// and handle the packing/unpacking in shaders.
FWGPU_LOGW << "Requested Filament texture format RGB5_A1 but getting "
"wgpu::TextureFormat::Undefined (no direct mapping in wgpu)";
return wgpu::TextureFormat::Undefined;
case TextureFormat::RGBA4:
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
// and handle the packing/unpacking in shaders.
FWGPU_LOGW << "Requested Filament texture format RGBA4 but getting "
"wgpu::TextureFormat::Undefined (no direct mapping in wgpu)";
return wgpu::TextureFormat::Undefined;
case TextureFormat::RGB8:
FWGPU_LOGW << "Requested Filament texture format RGB8 but getting "
"wgpu::TextureFormat::RGBA8Unorm (no direct sRGB equivalent in wgpu "
"without alpha)";
return wgpu::TextureFormat::RGBA8Unorm;
case TextureFormat::SRGB8:
FWGPU_LOGW << "Requested Filament texture format SRGB8 but getting "
"wgpu::TextureFormat::RGBA8UnormSrgb (no direct sRGB equivalent in wgpu "
"without alpha)";
return wgpu::TextureFormat::RGBA8UnormSrgb;
case TextureFormat::RGB8_SNORM:
FWGPU_LOGW
<< "Requested Filament texture format RGB8_SNORM but getting "
"wgpu::TextureFormat::RGBA8Snorm (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA8Snorm;
case TextureFormat::RGB8UI:
FWGPU_LOGW << "Requested Filament texture format RGB8UI but getting "
"wgpu::TextureFormat::RGBA8Uint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA8Uint;
case TextureFormat::RGB8I:
FWGPU_LOGW << "Requested Filament texture format RGB8I but getting "
"wgpu::TextureFormat::RGBA8Sint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA8Sint;
case TextureFormat::R11F_G11F_B10F: return wgpu::TextureFormat::RG11B10Ufloat;
case TextureFormat::UNUSED: return wgpu::TextureFormat::Undefined;
case TextureFormat::RGB10_A2: return wgpu::TextureFormat::RGB10A2Unorm;
case TextureFormat::RGB16F:
FWGPU_LOGW
<< "Requested Filament texture format RGB16F but getting "
"wgpu::TextureFormat::RGBA16Float (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA16Float;
case TextureFormat::RGB16UI:
FWGPU_LOGW
<< "Requested Filament texture format RGB16UI but getting "
"wgpu::TextureFormat::RGBA16Uint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA16Uint;
case TextureFormat::RGB16I:
FWGPU_LOGW
<< "Requested Filament texture format RGB16I but getting "
"wgpu::TextureFormat::RGBA16Sint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA16Sint;
case TextureFormat::RGB32F:
FWGPU_LOGW
<< "Requested Filament texture format RGB32F but getting "
"wgpu::TextureFormat::RGBA32Float (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA32Float;
case TextureFormat::RGB32UI:
FWGPU_LOGW
<< "Requested Filament texture format RGB32UI but getting "
"wgpu::TextureFormat::RGBA32Uint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA32Uint;
case TextureFormat::RGB32I:
FWGPU_LOGW
<< "Requested Filament texture format RGB32I but getting "
"wgpu::TextureFormat::RGBA32Sint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA32Sint;
case TextureFormat::DXT1_RGB: return wgpu::TextureFormat::BC1RGBAUnorm;
case TextureFormat::DXT1_RGBA: return wgpu::TextureFormat::BC1RGBAUnorm;
case TextureFormat::DXT3_RGBA: return wgpu::TextureFormat::BC2RGBAUnorm;
case TextureFormat::DXT5_RGBA: return wgpu::TextureFormat::BC3RGBAUnorm;
case TextureFormat::DXT1_SRGB: return wgpu::TextureFormat::BC1RGBAUnormSrgb;
case TextureFormat::DXT1_SRGBA: return wgpu::TextureFormat::BC1RGBAUnormSrgb;
case TextureFormat::DXT3_SRGBA: return wgpu::TextureFormat::BC2RGBAUnormSrgb;
case TextureFormat::DXT5_SRGBA: return wgpu::TextureFormat::BC3RGBAUnormSrgb;
}
}
wgpu::TextureView WebGPUTexture::makeTextureView(const uint8_t& baseLevel,
const uint8_t& levelCount, const uint32_t& baseArrayLayer, const uint32_t& arrayLayerCount,
const wgpu::TextureViewDimension dimension) const noexcept {
+2 -20
View File
@@ -26,20 +26,6 @@
namespace filament::backend {
[[nodiscard]] constexpr bool hasStencil(const wgpu::TextureFormat textureFormat) {
return textureFormat == wgpu::TextureFormat::Depth24PlusStencil8 ||
textureFormat == wgpu::TextureFormat::Depth32FloatStencil8 ||
textureFormat == wgpu::TextureFormat::Stencil8;
}
[[nodiscard]] constexpr bool hasDepth(const wgpu::TextureFormat textureFormat) {
return textureFormat == wgpu::TextureFormat::Depth16Unorm ||
textureFormat == wgpu::TextureFormat::Depth32Float ||
textureFormat == wgpu::TextureFormat::Depth24Plus ||
textureFormat == wgpu::TextureFormat::Depth24PlusStencil8 ||
textureFormat == wgpu::TextureFormat::Depth32FloatStencil8;
}
class WebGPUTexture : public HwTexture {
public:
enum class MipmapGenerationStrategy : uint8_t {
@@ -104,10 +90,8 @@ public:
/**
* @return nullptr if a MSAA sidecar texture is not appliable, otherwise a view to one
*/
[[nodiscard]] wgpu::TextureView makeMsaaSidecarTextureView(wgpu::Texture const&, uint8_t mipLevel, uint32_t arrayLayer) const;
[[nodiscard]] static wgpu::TextureFormat fToWGPUTextureFormat(
filament::backend::TextureFormat const& fFormat);
[[nodiscard]] wgpu::TextureView makeMsaaSidecarTextureView(wgpu::Texture const&,
uint8_t mipLevel, uint32_t arrayLayer) const;
/**
* @param format a required texture format (can be a view to a different underlying texture
@@ -118,8 +102,6 @@ public:
[[nodiscard]] static bool supportsMultipleMipLevelsViaStorageBinding(
wgpu::TextureFormat format);
[[nodiscard]] static size_t getWGPUTextureFormatPixelSize(const wgpu::TextureFormat format);
private:
// the texture view's format, which may differ from the underlying texture's format itself,
// an example of when this is needed is when certain underlying shaders don't support
@@ -17,6 +17,8 @@
#ifndef TNT_FILAMENT_BACKEND_WEBGPUTEXTUREHELPERS_H
#define TNT_FILAMENT_BACKEND_WEBGPUTEXTUREHELPERS_H
#include "webgpu/WebGPUConstants.h"
#include <backend/DriverEnums.h>
#include <webgpu/webgpu_cpp.h>
@@ -25,6 +27,20 @@
namespace filament::backend {
[[nodiscard]] constexpr bool hasStencil(const wgpu::TextureFormat textureFormat) {
return textureFormat == wgpu::TextureFormat::Depth24PlusStencil8 ||
textureFormat == wgpu::TextureFormat::Depth32FloatStencil8 ||
textureFormat == wgpu::TextureFormat::Stencil8;
}
[[nodiscard]] constexpr bool hasDepth(const wgpu::TextureFormat textureFormat) {
return textureFormat == wgpu::TextureFormat::Depth16Unorm ||
textureFormat == wgpu::TextureFormat::Depth32Float ||
textureFormat == wgpu::TextureFormat::Depth24Plus ||
textureFormat == wgpu::TextureFormat::Depth24PlusStencil8 ||
textureFormat == wgpu::TextureFormat::Depth32FloatStencil8;
}
[[nodiscard]] constexpr std::string_view toString(const PixelDataFormat format) {
switch (format) {
case PixelDataFormat::R: return "R";
@@ -97,7 +113,206 @@ namespace filament::backend {
return wgpu::TextureFormat::Undefined;
}
[[nodiscard]] constexpr wgpu::TextureFormat toWebGPULinearFormat(const wgpu::TextureFormat format) {
[[nodiscard]] constexpr wgpu::TextureFormat toWGPUTextureFormat(const TextureFormat fFormat) {
switch (fFormat) {
case TextureFormat::R8: return wgpu::TextureFormat::R8Unorm;
case TextureFormat::R8_SNORM: return wgpu::TextureFormat::R8Snorm;
case TextureFormat::R8UI: return wgpu::TextureFormat::R8Uint;
case TextureFormat::R8I: return wgpu::TextureFormat::R8Sint;
case TextureFormat::STENCIL8: return wgpu::TextureFormat::Stencil8;
case TextureFormat::R16F: return wgpu::TextureFormat::R16Float;
case TextureFormat::R16UI: return wgpu::TextureFormat::R16Uint;
case TextureFormat::R16I: return wgpu::TextureFormat::R16Sint;
case TextureFormat::RG8: return wgpu::TextureFormat::RG8Unorm;
case TextureFormat::RG8_SNORM: return wgpu::TextureFormat::RG8Snorm;
case TextureFormat::RG8UI: return wgpu::TextureFormat::RG8Uint;
case TextureFormat::RG8I: return wgpu::TextureFormat::RG8Sint;
case TextureFormat::R32F: return wgpu::TextureFormat::R32Float;
case TextureFormat::R32UI: return wgpu::TextureFormat::R32Uint;
case TextureFormat::R32I: return wgpu::TextureFormat::R32Sint;
case TextureFormat::RG16F: return wgpu::TextureFormat::RG16Float;
case TextureFormat::RG16UI: return wgpu::TextureFormat::RG16Uint;
case TextureFormat::RG16I: return wgpu::TextureFormat::RG16Sint;
case TextureFormat::RGBA8: return wgpu::TextureFormat::RGBA8Unorm;
case TextureFormat::SRGB8_A8: return wgpu::TextureFormat::RGBA8UnormSrgb;
case TextureFormat::RGBA8_SNORM: return wgpu::TextureFormat::RGBA8Snorm;
case TextureFormat::RGBA8UI: return wgpu::TextureFormat::RGBA8Uint;
case TextureFormat::RGBA8I: return wgpu::TextureFormat::RGBA8Sint;
case TextureFormat::DEPTH16: return wgpu::TextureFormat::Depth16Unorm;
case TextureFormat::DEPTH24: return wgpu::TextureFormat::Depth24Plus;
case TextureFormat::DEPTH32F: return wgpu::TextureFormat::Depth32Float;
case TextureFormat::DEPTH24_STENCIL8: return wgpu::TextureFormat::Depth24PlusStencil8;
case TextureFormat::DEPTH32F_STENCIL8: return wgpu::TextureFormat::Depth32FloatStencil8;
case TextureFormat::RG32F: return wgpu::TextureFormat::RG32Float;
case TextureFormat::RG32UI: return wgpu::TextureFormat::RG32Uint;
case TextureFormat::RG32I: return wgpu::TextureFormat::RG32Sint;
case TextureFormat::RGBA16F: return wgpu::TextureFormat::RGBA16Float;
case TextureFormat::RGBA16UI: return wgpu::TextureFormat::RGBA16Uint;
case TextureFormat::RGBA16I: return wgpu::TextureFormat::RGBA16Sint;
case TextureFormat::RGBA32F: return wgpu::TextureFormat::RGBA32Float;
case TextureFormat::RGBA32UI: return wgpu::TextureFormat::RGBA32Uint;
case TextureFormat::RGBA32I: return wgpu::TextureFormat::RGBA32Sint;
case TextureFormat::EAC_R11: return wgpu::TextureFormat::EACR11Unorm;
case TextureFormat::EAC_R11_SIGNED: return wgpu::TextureFormat::EACR11Snorm;
case TextureFormat::EAC_RG11: return wgpu::TextureFormat::EACRG11Unorm;
case TextureFormat::EAC_RG11_SIGNED: return wgpu::TextureFormat::EACRG11Snorm;
case TextureFormat::ETC2_RGB8: return wgpu::TextureFormat::ETC2RGB8Unorm;
case TextureFormat::ETC2_SRGB8: return wgpu::TextureFormat::ETC2RGB8UnormSrgb;
case TextureFormat::ETC2_RGB8_A1: return wgpu::TextureFormat::ETC2RGB8A1Unorm;
case TextureFormat::ETC2_SRGB8_A1: return wgpu::TextureFormat::ETC2RGB8A1UnormSrgb;
case TextureFormat::ETC2_EAC_RGBA8: return wgpu::TextureFormat::ETC2RGBA8Unorm;
case TextureFormat::ETC2_EAC_SRGBA8: return wgpu::TextureFormat::ETC2RGBA8UnormSrgb;
case TextureFormat::RGBA_ASTC_4x4: return wgpu::TextureFormat::ASTC4x4Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_4x4: return wgpu::TextureFormat::ASTC4x4UnormSrgb;
case TextureFormat::RGBA_ASTC_5x4: return wgpu::TextureFormat::ASTC5x4Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_5x4: return wgpu::TextureFormat::ASTC5x4UnormSrgb;
case TextureFormat::RGBA_ASTC_5x5: return wgpu::TextureFormat::ASTC5x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_5x5: return wgpu::TextureFormat::ASTC5x5UnormSrgb;
case TextureFormat::RGBA_ASTC_6x5: return wgpu::TextureFormat::ASTC6x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_6x5: return wgpu::TextureFormat::ASTC6x5UnormSrgb;
case TextureFormat::RGBA_ASTC_6x6: return wgpu::TextureFormat::ASTC6x6Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_6x6: return wgpu::TextureFormat::ASTC6x6UnormSrgb;
case TextureFormat::RGBA_ASTC_8x5: return wgpu::TextureFormat::ASTC8x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_8x5: return wgpu::TextureFormat::ASTC8x5UnormSrgb;
case TextureFormat::RGBA_ASTC_8x6: return wgpu::TextureFormat::ASTC8x6Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_8x6: return wgpu::TextureFormat::ASTC8x6UnormSrgb;
case TextureFormat::RGBA_ASTC_8x8: return wgpu::TextureFormat::ASTC8x8Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_8x8: return wgpu::TextureFormat::ASTC8x8UnormSrgb;
case TextureFormat::RGBA_ASTC_10x5: return wgpu::TextureFormat::ASTC10x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x5: return wgpu::TextureFormat::ASTC10x5UnormSrgb;
case TextureFormat::RGBA_ASTC_10x6: return wgpu::TextureFormat::ASTC10x6Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x6: return wgpu::TextureFormat::ASTC10x6UnormSrgb;
case TextureFormat::RGBA_ASTC_10x8: return wgpu::TextureFormat::ASTC10x8Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x8: return wgpu::TextureFormat::ASTC10x8UnormSrgb;
case TextureFormat::RGBA_ASTC_10x10: return wgpu::TextureFormat::ASTC10x10Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x10: return wgpu::TextureFormat::ASTC10x10UnormSrgb;
case TextureFormat::RGBA_ASTC_12x10: return wgpu::TextureFormat::ASTC12x10Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_12x10: return wgpu::TextureFormat::ASTC12x10UnormSrgb;
case TextureFormat::RGBA_ASTC_12x12: return wgpu::TextureFormat::ASTC12x12Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_12x12: return wgpu::TextureFormat::ASTC12x12UnormSrgb;
case TextureFormat::RED_RGTC1: return wgpu::TextureFormat::BC4RUnorm;
case TextureFormat::SIGNED_RED_RGTC1: return wgpu::TextureFormat::BC4RSnorm;
case TextureFormat::RED_GREEN_RGTC2: return wgpu::TextureFormat::BC5RGUnorm;
case TextureFormat::SIGNED_RED_GREEN_RGTC2: return wgpu::TextureFormat::BC5RGSnorm;
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT: return wgpu::TextureFormat::BC6HRGBUfloat;
case TextureFormat::RGB_BPTC_SIGNED_FLOAT: return wgpu::TextureFormat::BC6HRGBFloat;
case TextureFormat::RGBA_BPTC_UNORM: return wgpu::TextureFormat::BC7RGBAUnorm;
case TextureFormat::SRGB_ALPHA_BPTC_UNORM: return wgpu::TextureFormat::BC7RGBAUnormSrgb;
case TextureFormat::RGB565:
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
// and discard the alpha and lower precision.
FWGPU_LOGW << "Requested Filament texture format RGB565 but getting "
"wgpu::TextureFormat::Undefined (no direct mapping in wgpu)";
return wgpu::TextureFormat::Undefined;
case TextureFormat::RGB9_E5: return wgpu::TextureFormat::RGB9E5Ufloat;
case TextureFormat::RGB5_A1:
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
// and handle the packing/unpacking in shaders.
FWGPU_LOGW << "Requested Filament texture format RGB5_A1 but getting "
"wgpu::TextureFormat::Undefined (no direct mapping in wgpu)";
return wgpu::TextureFormat::Undefined;
case TextureFormat::RGBA4:
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
// and handle the packing/unpacking in shaders.
FWGPU_LOGW << "Requested Filament texture format RGBA4 but getting "
"wgpu::TextureFormat::Undefined (no direct mapping in wgpu)";
return wgpu::TextureFormat::Undefined;
case TextureFormat::RGB8:
FWGPU_LOGW << "Requested Filament texture format RGB8 but getting "
"wgpu::TextureFormat::RGBA8Unorm (no direct sRGB equivalent in wgpu "
"without alpha)";
return wgpu::TextureFormat::RGBA8Unorm;
case TextureFormat::SRGB8:
FWGPU_LOGW << "Requested Filament texture format SRGB8 but getting "
"wgpu::TextureFormat::RGBA8UnormSrgb (no direct sRGB equivalent in wgpu "
"without alpha)";
return wgpu::TextureFormat::RGBA8UnormSrgb;
case TextureFormat::RGB8_SNORM:
FWGPU_LOGW
<< "Requested Filament texture format RGB8_SNORM but getting "
"wgpu::TextureFormat::RGBA8Snorm (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA8Snorm;
case TextureFormat::RGB8UI:
FWGPU_LOGW << "Requested Filament texture format RGB8UI but getting "
"wgpu::TextureFormat::RGBA8Uint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA8Uint;
case TextureFormat::RGB8I:
FWGPU_LOGW << "Requested Filament texture format RGB8I but getting "
"wgpu::TextureFormat::RGBA8Sint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA8Sint;
case TextureFormat::R11F_G11F_B10F: return wgpu::TextureFormat::RG11B10Ufloat;
case TextureFormat::UNUSED: return wgpu::TextureFormat::Undefined;
case TextureFormat::RGB10_A2: return wgpu::TextureFormat::RGB10A2Unorm;
case TextureFormat::RGB16F:
FWGPU_LOGW
<< "Requested Filament texture format RGB16F but getting "
"wgpu::TextureFormat::RGBA16Float (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA16Float;
case TextureFormat::RGB16UI:
FWGPU_LOGW
<< "Requested Filament texture format RGB16UI but getting "
"wgpu::TextureFormat::RGBA16Uint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA16Uint;
case TextureFormat::RGB16I:
FWGPU_LOGW
<< "Requested Filament texture format RGB16I but getting "
"wgpu::TextureFormat::RGBA16Sint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA16Sint;
case TextureFormat::RGB32F:
FWGPU_LOGW
<< "Requested Filament texture format RGB32F but getting "
"wgpu::TextureFormat::RGBA32Float (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA32Float;
case TextureFormat::RGB32UI:
FWGPU_LOGW
<< "Requested Filament texture format RGB32UI but getting "
"wgpu::TextureFormat::RGBA32Uint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA32Uint;
case TextureFormat::RGB32I:
FWGPU_LOGW
<< "Requested Filament texture format RGB32I but getting "
"wgpu::TextureFormat::RGBA32Sint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA32Sint;
case TextureFormat::DXT1_RGB: return wgpu::TextureFormat::BC1RGBAUnorm;
case TextureFormat::DXT1_RGBA: return wgpu::TextureFormat::BC1RGBAUnorm;
case TextureFormat::DXT3_RGBA: return wgpu::TextureFormat::BC2RGBAUnorm;
case TextureFormat::DXT5_RGBA: return wgpu::TextureFormat::BC3RGBAUnorm;
case TextureFormat::DXT1_SRGB: return wgpu::TextureFormat::BC1RGBAUnormSrgb;
case TextureFormat::DXT1_SRGBA: return wgpu::TextureFormat::BC1RGBAUnormSrgb;
case TextureFormat::DXT3_SRGBA: return wgpu::TextureFormat::BC2RGBAUnormSrgb;
case TextureFormat::DXT5_SRGBA: return wgpu::TextureFormat::BC3RGBAUnormSrgb;
}
}
[[nodiscard]] constexpr wgpu::TextureViewDimension toWebGPUTextureViewDimension(
const SamplerType samplerType) {
switch (samplerType) {
case SamplerType::SAMPLER_2D: return wgpu::TextureViewDimension::e2D;
case SamplerType::SAMPLER_2D_ARRAY: return wgpu::TextureViewDimension::e2DArray;
case SamplerType::SAMPLER_CUBEMAP: return wgpu::TextureViewDimension::Cube;
case SamplerType::SAMPLER_EXTERNAL: return wgpu::TextureViewDimension::e2D;
case SamplerType::SAMPLER_3D: return wgpu::TextureViewDimension::e3D;
case SamplerType::SAMPLER_CUBEMAP_ARRAY: return wgpu::TextureViewDimension::CubeArray;
}
}
[[nodiscard]] constexpr wgpu::TextureDimension toWebGPUTextureDimension(
const SamplerType samplerType) {
switch (samplerType) {
case SamplerType::SAMPLER_2D: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_2D_ARRAY: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_CUBEMAP: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_EXTERNAL: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_3D: return wgpu::TextureDimension::e3D;
case SamplerType::SAMPLER_CUBEMAP_ARRAY: return wgpu::TextureDimension::e2D;
}
}
/**
* @return the linear version of the format (removing the Srgb part) or the original format if it
* is already linear
*/
[[nodiscard]] constexpr wgpu::TextureFormat toLinearFormat(const wgpu::TextureFormat format) {
switch (format) {
case wgpu::TextureFormat::RGBA8UnormSrgb: return wgpu::TextureFormat::RGBA8Unorm;
case wgpu::TextureFormat::BGRA8UnormSrgb: return wgpu::TextureFormat::BGRA8Unorm;
@@ -126,6 +341,199 @@ namespace filament::backend {
}
}
/**
* @return true if https://www.w3.org/TR/webgpu/#copy-compatible which states:
* Two GPUTextureFormats format1 and format2 are copy-compatible if:
* - format1 equals format2, or
* - format1 and format2 differ only in whether they are srgb formats (have the -srgb suffix).
*/
[[nodiscard]] constexpr bool areCopyCompatible(const wgpu::TextureFormat sourceFormat,
const wgpu::TextureFormat destinationFormat) {
return sourceFormat == destinationFormat ||
(toLinearFormat(sourceFormat) == toLinearFormat(destinationFormat));
}
[[nodiscard]] constexpr wgpu::Extent2D getBlockSize(const wgpu::TextureFormat format) {
// see https://www.w3.org/TR/webgpu/#texture-formats
// and https://www.w3.org/TR/webgpu/#texture-format-caps
switch (format) {
// BC compressed formats
case wgpu::TextureFormat::BC1RGBAUnorm:
case wgpu::TextureFormat::BC1RGBAUnormSrgb:
case wgpu::TextureFormat::BC2RGBAUnorm:
case wgpu::TextureFormat::BC2RGBAUnormSrgb:
case wgpu::TextureFormat::BC3RGBAUnorm:
case wgpu::TextureFormat::BC3RGBAUnormSrgb:
case wgpu::TextureFormat::BC4RUnorm:
case wgpu::TextureFormat::BC4RSnorm:
case wgpu::TextureFormat::BC5RGUnorm:
case wgpu::TextureFormat::BC5RGSnorm:
case wgpu::TextureFormat::BC6HRGBUfloat:
case wgpu::TextureFormat::BC6HRGBFloat:
case wgpu::TextureFormat::BC7RGBAUnorm:
case wgpu::TextureFormat::BC7RGBAUnormSrgb:
// ETC2 compressed formats
case wgpu::TextureFormat::ETC2RGB8Unorm:
case wgpu::TextureFormat::ETC2RGB8UnormSrgb:
case wgpu::TextureFormat::ETC2RGB8A1Unorm:
case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb:
case wgpu::TextureFormat::ETC2RGBA8Unorm:
case wgpu::TextureFormat::ETC2RGBA8UnormSrgb:
case wgpu::TextureFormat::EACR11Unorm:
case wgpu::TextureFormat::EACR11Snorm:
case wgpu::TextureFormat::EACRG11Unorm:
case wgpu::TextureFormat::EACRG11Snorm:
// ASTC compressed formats
case wgpu::TextureFormat::ASTC4x4Unorm:
case wgpu::TextureFormat::ASTC4x4UnormSrgb:
return { .width = 4, .height = 4 };
case wgpu::TextureFormat::ASTC5x4Unorm:
case wgpu::TextureFormat::ASTC5x4UnormSrgb:
return { .width = 5, .height = 4 };
case wgpu::TextureFormat::ASTC5x5Unorm:
case wgpu::TextureFormat::ASTC5x5UnormSrgb:
return { .width = 5, .height = 5 };
case wgpu::TextureFormat::ASTC6x5Unorm:
case wgpu::TextureFormat::ASTC6x5UnormSrgb:
return { .width = 6, .height = 5 };
case wgpu::TextureFormat::ASTC6x6Unorm:
case wgpu::TextureFormat::ASTC6x6UnormSrgb:
return { .width = 6, .height = 6 };
case wgpu::TextureFormat::ASTC8x5Unorm:
case wgpu::TextureFormat::ASTC8x5UnormSrgb:
return { .width = 8, .height = 5 };
case wgpu::TextureFormat::ASTC8x6Unorm:
case wgpu::TextureFormat::ASTC8x6UnormSrgb:
return { .width = 8, .height = 6 };
case wgpu::TextureFormat::ASTC8x8Unorm:
case wgpu::TextureFormat::ASTC8x8UnormSrgb:
return { .width = 8, .height = 8 };
case wgpu::TextureFormat::ASTC10x5Unorm:
case wgpu::TextureFormat::ASTC10x5UnormSrgb:
return { .width = 10, .height = 5 };
case wgpu::TextureFormat::ASTC10x6Unorm:
case wgpu::TextureFormat::ASTC10x6UnormSrgb:
return { .width = 10, .height = 6 };
case wgpu::TextureFormat::ASTC10x8Unorm:
case wgpu::TextureFormat::ASTC10x8UnormSrgb:
return { .width = 10, .height = 8 };
case wgpu::TextureFormat::ASTC10x10Unorm:
case wgpu::TextureFormat::ASTC10x10UnormSrgb:
return { .width = 10, .height = 10 };
case wgpu::TextureFormat::ASTC12x10Unorm:
case wgpu::TextureFormat::ASTC12x10UnormSrgb:
return { .width = 12, .height = 10 };
case wgpu::TextureFormat::ASTC12x12Unorm:
case wgpu::TextureFormat::ASTC12x12UnormSrgb:
return { .width = 12, .height = 12 };
default:
// All other formats are uncompressed and have a 1x1 block size.
return { .width = 1, .height = 1 };
}
}
[[nodiscard]] constexpr size_t getWGPUTextureFormatPixelSize(const wgpu::TextureFormat format) {
switch (format) {
// 1 byte
case wgpu::TextureFormat::R8Unorm:
case wgpu::TextureFormat::R8Snorm:
case wgpu::TextureFormat::R8Uint:
case wgpu::TextureFormat::R8Sint:
case wgpu::TextureFormat::Stencil8:
return 1;
// 2 bytes
case wgpu::TextureFormat::R16Uint:
case wgpu::TextureFormat::R16Sint:
case wgpu::TextureFormat::R16Float:
case wgpu::TextureFormat::RG8Unorm:
case wgpu::TextureFormat::RG8Snorm:
case wgpu::TextureFormat::RG8Uint:
case wgpu::TextureFormat::RG8Sint:
case wgpu::TextureFormat::Depth16Unorm:
return 2;
// 4 bytes
// -- 32-bit single-channel formats
case wgpu::TextureFormat::R32Float:
case wgpu::TextureFormat::R32Uint:
case wgpu::TextureFormat::R32Sint:
// -- 16-bit two-channel formats
case wgpu::TextureFormat::RG16Uint:
case wgpu::TextureFormat::RG16Sint:
case wgpu::TextureFormat::RG16Float:
// -- 8-bit four-channel formats
case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA8UnormSrgb:
case wgpu::TextureFormat::RGBA8Snorm:
case wgpu::TextureFormat::RGBA8Uint:
case wgpu::TextureFormat::RGBA8Sint:
case wgpu::TextureFormat::BGRA8Unorm:
case wgpu::TextureFormat::BGRA8UnormSrgb:
// -- Packed 32-bit formats
case wgpu::TextureFormat::RGB10A2Unorm:
case wgpu::TextureFormat::RGB10A2Uint:
case wgpu::TextureFormat::RG11B10Ufloat:
case wgpu::TextureFormat::RGB9E5Ufloat:
// -- Depth/Stencil formats
case wgpu::TextureFormat::Depth32Float:
case wgpu::TextureFormat::Depth24Plus:
case wgpu::TextureFormat::Depth24PlusStencil8:
return 4;
// 8 bytes
case wgpu::TextureFormat::RG32Float:
case wgpu::TextureFormat::RG32Uint:
case wgpu::TextureFormat::RG32Sint:
case wgpu::TextureFormat::RGBA16Uint:
case wgpu::TextureFormat::RGBA16Sint:
case wgpu::TextureFormat::RGBA16Float:
return 8;
// 16 bytes
case wgpu::TextureFormat::RGBA32Float:
case wgpu::TextureFormat::RGBA32Uint:
case wgpu::TextureFormat::RGBA32Sint:
return 16;
// Non-copyable or compressed formats
case wgpu::TextureFormat::Depth32FloatStencil8: // Not copyable from texture to buffer
default:
return 0;
}
}
/**
* @param format texture format to potentially be used for storage binding
* @return true if the format is compatible with wgpu::TextureUsage::StorageBinding
*/
[[nodiscard]] constexpr bool isFormatStorageCompatible(const wgpu::TextureFormat format) {
switch (format) {
// List of formats that support storage binding
case wgpu::TextureFormat::R32Float:
case wgpu::TextureFormat::R32Sint:
case wgpu::TextureFormat::R32Uint:
case wgpu::TextureFormat::RG32Float:
case wgpu::TextureFormat::RG32Sint:
case wgpu::TextureFormat::RG32Uint:
case wgpu::TextureFormat::RGBA16Float:
case wgpu::TextureFormat::RGBA16Sint:
case wgpu::TextureFormat::RGBA16Uint:
case wgpu::TextureFormat::RGBA32Float:
case wgpu::TextureFormat::RGBA32Sint:
case wgpu::TextureFormat::RGBA32Uint:
case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA8Snorm:
case wgpu::TextureFormat::RGBA8Uint:
case wgpu::TextureFormat::RGBA8Sint:
return true;
default:
// All other formats, including packed floats (RG11B10Ufloat),
// depth/stencil, and sRGB formats do not support storage.
return false;
}
}
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_WEBGPUTEXTUREHELPERS_H
@@ -54,9 +54,10 @@ std::string processPlaceholderTemplate(std::string_view const& stringTemplate,
positionAfterPlaceholder - positionOfPlaceholder) };
if (const auto iter{ valueByPlaceholderName.find(placeholderName) };
iter == valueByPlaceholderName.end()) {
// wrapping placeholderName in a std::string to null terminate the C string....
PANIC_POSTCONDITION("Found placeholder '%s' in template, but this is not present in "
"valueByPlaceholderName",
placeholderName.data());
std::string{ placeholderName }.data());
} else {
const std::string_view value{ iter->second };
out << value;
+2
View File
@@ -46,6 +46,8 @@ Backend parseArgumentsForBackend(int argc, char* argv[]) {
backend = Backend::VULKAN;
} else if (arg == "metal") {
backend = Backend::METAL;
} else if (arg == "webgpu") {
backend = Backend::WEBGPU;
} else {
std::cerr << "Unrecognized target API. Must be 'opengl'|'vulkan'|'metal'."
<< std::endl
+30 -5
View File
@@ -36,14 +36,16 @@
namespace test {
ScreenshotParams::ScreenshotParams(int width, int height, std::string fileName,
uint32_t expectedHash, bool isSrgb, int numAllowedDeviations, int pixelMatchThreshold)
uint32_t expectedHash, bool isSrgb, int numAllowedDeviations, int pixelMatchThreshold,
std::optional<float> forceAlphaValue)
: mWidth(width),
mHeight(height),
mIsSrgb(isSrgb),
mExpectedPixelHash(expectedHash),
mFileName(std::move(fileName)),
mAllowedPixelDeviations(numAllowedDeviations),
mPixelMatchThreshold(pixelMatchThreshold) {}
mPixelMatchThreshold(pixelMatchThreshold),
mForceAlphaValue(forceAlphaValue) {}
int ScreenshotParams::width() const {
return mWidth;
@@ -61,6 +63,10 @@ uint32_t ScreenshotParams::expectedHash() const {
return mExpectedPixelHash;
}
std::optional<float> ScreenshotParams::forceAlphaValue() const {
return mForceAlphaValue;
}
std::filesystem::path ScreenshotParams::actualDirectoryPath() {
return BackendTest::binaryDirectory().append("images/actual_images");
}
@@ -177,9 +183,29 @@ RenderTargetDump::RenderTargetDump(filament::backend::DriverApi& api,
const size_t size = mInternal->params.width() * mInternal->params.height() * 4;
mInternal->bytes.resize(size);
using filament::backend::PixelDataFormat;
using filament::backend::PixelDataType;
constexpr PixelDataFormat readPixelFormat = PixelDataFormat::RGBA;
constexpr PixelDataType readPixelType = PixelDataType::UBYTE;
auto cb = [](void* buffer, size_t size, void* user) {
auto* internal = static_cast<RenderTargetDump::Internal*>(user);
internal->bytesFilled = true;
// If requested, we overwrite the alpha value.
// If the read pixel format or type changes, this logic must be updated.
static_assert(readPixelFormat == PixelDataFormat::RGBA);
static_assert(readPixelType == PixelDataType::UBYTE);
if (auto alphaValue = internal->params.forceAlphaValue(); alphaValue) {
const int pixelCount = internal->params.width() * internal->params.height();
const int channels = 4;
constexpr int kAlphaChannel = 3;
uint8_t* pixelBuffer = static_cast<uint8_t*>(buffer);
for (int p = 0; p < pixelCount; p++) {
pixelBuffer[p * channels + kAlphaChannel] = *alphaValue * 255.0f;
}
}
#ifndef FILAMENT_IOS
image::LinearImage image;
if (internal->params.isSrgb()) {
@@ -203,9 +229,8 @@ RenderTargetDump::RenderTargetDump(filament::backend::DriverApi& api,
filePath);
#endif
};
filament::backend::PixelBufferDescriptor pb(mInternal->bytes.data(), size,
filament::backend::PixelDataFormat::RGBA, filament::backend::PixelDataType::UBYTE, cb,
(void*)mInternal.get());
filament::backend::PixelBufferDescriptor pb(mInternal->bytes.data(), size, readPixelFormat,
readPixelType, cb, (void*) mInternal.get());
api.readPixels(renderTarget, 0, 0, mInternal->params.width(), mInternal->params.height(),
std::move(pb));
}
+65 -3
View File
@@ -19,6 +19,7 @@
#include <filesystem>
#include <vector>
#include <optional>
#include "gtest/gtest.h"
@@ -27,9 +28,9 @@
// Arguments are (RenderTargetHandle renderTarget, ImageExpectations& expectations,
// ScreenshotParams screenshotParams)
#define EXPECT_IMAGE(renderTarget, expectations, screenshotParams) \
#define EXPECT_IMAGE(renderTarget, screenshotParams) \
do { \
expectations.addExpectation( \
getExpectations().addExpectation( \
__FILE__, \
__LINE__, \
renderTarget, \
@@ -45,12 +46,72 @@ class ScreenshotParams {
public:
// TODO(b/422804941): Add a set of environments where this test should use a different golden.
ScreenshotParams(int width, int height, std::string fileName, uint32_t expectedPixelHash,
bool isSrgb = false, int numAllowedDeviations = 0, int pixelMatchThreshold = 0);
bool isSrgb = false, int numAllowedDeviations = 0, int pixelMatchThreshold = 0,
std::optional<float> forceAlphaValue = std::nullopt);
class Builder {
public:
Builder& width(int width) {
mWidth = width;
return *this;
}
Builder& height(int height) {
mHeight = height;
return *this;
}
Builder& fileName(std::string fileName) {
mFileName = fileName;
return *this;
}
Builder& expectedPixelHash(uint32_t pixelHash) {
mExpectedPixelHash = pixelHash;
return *this;
}
Builder& isSrgb(bool isSrgb) {
mIsSrgb = isSrgb;
return *this;
}
Builder& numAllowedDeviations(int numAllowedDeviations) {
mNumAllowedDeviations = numAllowedDeviations;
return *this;
}
Builder& pixelMatchTheshold(int pixelMatchTheshold) {
mPixelMatchThreshold = pixelMatchTheshold;
return *this;
}
Builder& forceAlphaValue(float alphaValue) {
mForceAlphaValue = alphaValue;
return *this;
}
ScreenshotParams build() {
return ScreenshotParams(mWidth, mHeight, mFileName, mExpectedPixelHash, mIsSrgb,
mNumAllowedDeviations, mPixelMatchThreshold, mForceAlphaValue);
}
private:
int mWidth;
int mHeight;
std::string mFileName;
uint32_t mExpectedPixelHash;
bool mIsSrgb;
int mNumAllowedDeviations;
int mPixelMatchThreshold;
std::optional<float> mForceAlphaValue;
};
int width() const;
int height() const;
bool isSrgb() const;
uint32_t expectedHash() const;
std::optional<float> forceAlphaValue() const;
static std::filesystem::path actualDirectoryPath();
std::string actualFileName() const;
@@ -70,6 +131,7 @@ private:
std::string mFileName;
int mAllowedPixelDeviations;
int mPixelMatchThreshold;
std::optional<float> mForceAlphaValue;
};
/**
@@ -173,6 +173,7 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(ShaderStage stage, std::s
return { (uint8_t*)spirv.data(), (uint8_t*)(spirv.data() + spirv.size()) };
} else if (backend == Backend::WEBGPU){
filamat::GLSLPostProcessor::spirvToWgsl(&spirv, &result);
return { result.c_str(), result.c_str() + result.length() + 1 };
}
return {};
+32 -6
View File
@@ -47,7 +47,7 @@ layout(location = 0) in vec4 mesh_position;
void main() {
gl_Position = vec4(mesh_position.xy, 0.0, 1.0);
#if defined(TARGET_VULKAN_ENVIRONMENT)
// In Vulkan, clip space is Y-down. In OpenGL and Metal, clip space is Y-up.
// In Vulkan, clip space is Y-down. In OpenGL, Metal and WebGPU, clip space is Y-up.
gl_Position.y = -gl_Position.y;
#endif
})" };
@@ -64,7 +64,7 @@ void main() {
params.scaleMinusOne.z + 1.0,
1.0);
#if defined(TARGET_VULKAN_ENVIRONMENT)
// In Vulkan, clip space is Y-down. In OpenGL and Metal, clip space is Y-up.
// In Vulkan, clip space is Y-down. In OpenGL, Metal and WebGPU, clip space is Y-up.
gl_Position.y = -gl_Position.y;
#endif
})" };
@@ -80,7 +80,7 @@ void main() {
gl_Position = vec4(mesh_position.xy, 0.0, 1.0);
uv = (mesh_position.xy * 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.
// In Vulkan, clip space is Y-down. In OpenGL, Metal and WebGPU, clip space is Y-up.
gl_Position.y = -gl_Position.y;
#endif
})" };
@@ -158,9 +158,19 @@ layout(binding = 0, set = 0) uniform Params {
} params;
)";
}
case ShaderUniformType::Sampler: {
case ShaderUniformType::Sampler2D: {
return R"(
layout(location = 0, set = 0) uniform sampler2D test_tex;
)";
}
case ShaderUniformType::ISampler2D: {
return R"(
layout(location = 0, set = 0) uniform isampler2D test_tex;
)";
}
case ShaderUniformType::USampler2D: {
return R"(
layout(location = 0, set = 0) uniform usampler2D test_tex;
)";
}
default:
@@ -179,7 +189,7 @@ std::vector<UniformConfig> GetUniformConfig(ShaderUniformType type) {
case ShaderUniformType::SimpleWithPadding: {
return {{ "Params" }};
}
case ShaderUniformType::Sampler: {
case ShaderUniformType::Sampler2D: {
filament::SamplerInterfaceBlock::SamplerInfo samplerInfo{
"backend_test", "test_tex", 0,
SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH, false };
@@ -187,6 +197,22 @@ std::vector<UniformConfig> GetUniformConfig(ShaderUniformType type) {
"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo
}};
}
case ShaderUniformType::ISampler2D: {
filament::SamplerInterfaceBlock::SamplerInfo samplerInfo{
"backend_test", "test_tex", 0,
SamplerType::SAMPLER_2D, SamplerFormat::INT, Precision::HIGH, false };
return {{
"test_tex", DescriptorType::SAMPLER_2D_INT, samplerInfo
}};
}
case ShaderUniformType::USampler2D: {
filament::SamplerInterfaceBlock::SamplerInfo samplerInfo{
"backend_test", "test_tex", 0,
SamplerType::SAMPLER_2D, SamplerFormat::UINT, Precision::HIGH, false };
return {{
"test_tex", DescriptorType::SAMPLER_2D_INT, samplerInfo
}};
}
default:
abort();
}
@@ -252,4 +278,4 @@ std::string SharedShaders::getFragmentShaderText(FragmentShaderType fragment,
return fragmentText->withUniform(*uniformText);
}
} // namespace test
} // namespace test
@@ -23,7 +23,9 @@ enum class ShaderUniformType : uint8_t {
None,
Simple,
SimpleWithPadding,
Sampler,
Sampler2D,
ISampler2D,
USampler2D,
};
struct SimpleMaterialParams {
+3
View File
@@ -49,6 +49,9 @@ test::NativeView getNativeView() {
if (self.backend == test::Backend::VULKAN) {
nativeView.ptr = (void*) view;
}
if (self.backend == test::Backend::WEBGPU) {
nativeView.ptr = (void*) view.layer;
}
CGSize drawableSize = ((CAMetalLayer*) view.layer).drawableSize;
nativeView.width = static_cast<size_t>(drawableSize.width);
nativeView.height = static_cast<size_t>(drawableSize.height);
+6 -6
View File
@@ -199,7 +199,7 @@ TEST_F(BlitTest, ColorMagnify) {
{
RenderFrame frame(api);
EXPECT_IMAGE(dstRenderTargets[0], getExpectations(),
EXPECT_IMAGE(dstRenderTargets[0],
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorMagnify", 0x410bdd31));
api.commit(swapChain);
}
@@ -255,7 +255,7 @@ TEST_F(BlitTest, ColorMinify) {
{ 0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel },
SamplerMagFilter::LINEAR);
EXPECT_IMAGE(dstRenderTargets[0], getExpectations(),
EXPECT_IMAGE(dstRenderTargets[0],
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorMinify", 0xf3d9c53f));
}
@@ -336,7 +336,7 @@ TEST_F(BlitTest, ColorResolve) {
srcRenderTarget, { 0, 0, kSrcTexWidth, kSrcTexHeight },
SamplerMagFilter::NEAREST);
EXPECT_IMAGE(dstRenderTarget, getExpectations(),
EXPECT_IMAGE(dstRenderTarget,
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorResolve", 531759687));
}
@@ -403,7 +403,7 @@ TEST_F(BlitTest, Blit2DTextureArray) {
{
RenderFrame frame(api);
EXPECT_IMAGE(dstRenderTarget, getExpectations(),
EXPECT_IMAGE(dstRenderTarget,
ScreenshotParams(kDstTexWidth, kDstTexHeight, "Blit2DTextureArray",
0x8de7d55b));
api.commit(swapChain);
@@ -479,7 +479,7 @@ TEST_F(BlitTest, BlitRegion) {
RenderFrame frame(api);
// TODO: for some reason, this test has very, very slight (as in one pixel) differences
// between OpenGL and Metal. So disable golden checking for now.
// EXPECT_IMAGE(dstRenderTarget, expectations, ScreenshotParams(kDstTexWidth,
// EXPECT_IMAGE(dstRenderTarget, ScreenshotParams(kDstTexWidth,
// kDstTexHeight, "BlitRegion", 0x74fa34ed));
api.commit(swapChain);
}
@@ -546,7 +546,7 @@ TEST_F(BlitTest, BlitRegionToSwapChain) {
// TODO: for some reason, this test has been disabled. It needs to be tested on all
// machines.
// EXPECT_IMAGE(dstRenderTarget, expectations,
// EXPECT_IMAGE(dstRenderTarget,
// ScreenshotParams(kDstTexWidth, kDstTexHeight, "BlitRegionToSwapChain", 0x0));
}
+2 -3
View File
@@ -237,9 +237,8 @@ TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
}
EXPECT_IMAGE(renderTarget, getExpectations(),
ScreenshotParams(screenWidth(), screenHeight(), "BufferObjectUpdateWithOffset",
2320747245));
EXPECT_IMAGE(renderTarget, ScreenshotParams(screenWidth(), screenHeight(),
"BufferObjectUpdateWithOffset", 2320747245));
api.flush();
api.commit(swapChain);
+2
View File
@@ -27,6 +27,7 @@ namespace test {
TEST_F(BackendTest, FrameScheduledCallback) {
SKIP_IF(Backend::OPENGL, "Frame callbacks are unsupported in OpenGL");
SKIP_IF(Backend::VULKAN, "Frame callbacks are unsupported in Vulkan, see b/417254479");
SKIP_IF(Backend::WEBGPU, "Frame callbacks are unsupported in WebGPU");
auto& api = getDriverApi();
Cleanup cleanup(api);
@@ -87,6 +88,7 @@ TEST_F(BackendTest, FrameScheduledCallback) {
TEST_F(BackendTest, FrameCompletedCallback) {
SKIP_IF(Backend::OPENGL, "Frame callbacks are unsupported in OpenGL");
SKIP_IF(Backend::VULKAN, "Frame callbacks are unsupported in Vulkan, see b/417254479");
SKIP_IF(Backend::WEBGPU, "Frame callbacks are unsupported in WebGPU");
auto& api = getDriverApi();
Cleanup cleanup(api);
+2 -1
View File
@@ -104,6 +104,7 @@ TEST_F(BackendTest, FeedbackLoops) {
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL),
"OpenGL image is upside down due to readPixels failing for texture with uploaded image "
"data");
FAIL_IF(Backend::WEBGPU, "BUG");
auto& api = getDriverApi();
Cleanup cleanup(api);
@@ -246,7 +247,7 @@ TEST_F(BackendTest, FeedbackLoops) {
// NOTE: Calling glReadPixels on any miplevel other than the base level
// seems to be un-reliable on some GPU's.
if (frame == kNumFrames - 1) {
EXPECT_IMAGE(renderTargets[0], getExpectations(),
EXPECT_IMAGE(renderTargets[0],
ScreenshotParams(kTexWidth, kTexHeight, "FeedbackLoops", 4192780705));
}
+30 -16
View File
@@ -287,9 +287,9 @@ TEST_F(LoadImageTest, UpdateImage2D) {
// Test integer format uploads.
// TODO: These cases fail on OpenGL and Vulkan.
// TODO: These cases now also fail on Metal, but at some point previously worked.
testCases.emplace_back("RGB_INTEGER UBYTE to RGB8UI", PixelDataFormat::RGB_INTEGER, PixelDataType::UBYTE, TextureFormat::RGB8UI);
testCases.emplace_back("RGB_INTEGER USHORT to RGB16UI", PixelDataFormat::RGB_INTEGER, PixelDataType::USHORT, TextureFormat::RGB16UI);
testCases.emplace_back("RGB_INTEGER INT to RGB32I", PixelDataFormat::RGB_INTEGER, PixelDataType::INT, TextureFormat::RGB32I);
testCases.emplace_back("RGB_INTEGER UBYTE to RGB8UI", PixelDataFormat::RGB_INTEGER, PixelDataType::UBYTE, TextureFormat::RGB8UI);
testCases.emplace_back("RGB_INTEGER USHORT to RGB16UI", PixelDataFormat::RGB_INTEGER, PixelDataType::USHORT, TextureFormat::RGB16UI);
testCases.emplace_back("RGB_INTEGER INT to RGB32I", PixelDataFormat::RGB_INTEGER, PixelDataType::INT, TextureFormat::RGB32I);
// Test uploads with buffer padding.
// TODO: Vulkan crashes with "Assertion failed: (offset + size <= allocationSize)"
@@ -319,14 +319,23 @@ TEST_F(LoadImageTest, UpdateImage2D) {
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
// Create a program.
filament::SamplerInterfaceBlock::SamplerInfo samplerInfo { "test", "tex", 0,
SamplerType::SAMPLER_2D, getSamplerFormat(t.textureFormat), Precision::HIGH, false };
std::string const fragment = getFormattedFragment(fragmentTemplate, t.textureFormat);
Shader shader(api, cleanup, ShaderConfig{
.vertexShader = mVertexShader,
.fragmentShader= fragment,
.uniforms = {{"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo}}
ShaderUniformType uniformType;
switch (getSamplerFormat(t.textureFormat)) {
case SamplerFormat::FLOAT:
case SamplerFormat::SHADOW: // not used for tests, but must cover all cases
uniformType = ShaderUniformType::Sampler2D;
break;
case SamplerFormat::INT:
uniformType = ShaderUniformType::ISampler2D;
break;
case SamplerFormat::UINT:
uniformType = ShaderUniformType::USampler2D;
break;
}
Shader shader = SharedShaders::makeShader(api, cleanup, {
.mVertexType = VertexShaderType::Textured,
.mFragmentType = FragmentShaderType::Textured,
.mUniformType = uniformType,
});
// Create a Texture.
@@ -374,8 +383,13 @@ TEST_F(LoadImageTest, UpdateImage2D) {
api.draw2(0, 3, 1);
api.endRenderPass();
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
ScreenshotParams(kTexSize, kTexSize, t.name, expectedHash));
EXPECT_IMAGE(defaultRenderTarget, ScreenshotParams::Builder()
.width(kTexSize)
.height(kTexSize)
.fileName(t.name)
.expectedPixelHash(expectedHash)
.forceAlphaValue(1.0f)
.build());
api.commit(swapChain);
api.endFrame(0);
@@ -463,7 +477,7 @@ TEST_F(LoadImageTest, UpdateImageSRGB) {
api.draw2(0, 3, 1);
api.endRenderPass();
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
EXPECT_IMAGE(defaultRenderTarget,
ScreenshotParams(kTexSize, kTexSize, "UpdateImageSRGB", 3300305265));
api.commit(swapChain);
@@ -539,7 +553,7 @@ TEST_F(LoadImageTest, UpdateImageMipLevel) {
api.endRenderPass();
}
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
EXPECT_IMAGE(defaultRenderTarget,
ScreenshotParams(kTexSize, kTexSize, "UpdateImageMipLevel", 1875922935));
api.commit(swapChain);
@@ -625,7 +639,7 @@ TEST_F(LoadImageTest, UpdateImage3D) {
api.draw2(0, 3, 1);
api.endRenderPass();
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
EXPECT_IMAGE(defaultRenderTarget,
ScreenshotParams(kTexSize, kTexSize, "UpdateImage3D", 1875922935));
}
+3 -3
View File
@@ -40,7 +40,7 @@ std::string fragmentTexturedLod (R"(#version 450 core
layout(location = 0) out vec4 fragColor;
layout(location = 0) in vec2 uv;
layout(location = 0, set = 0) uniform sampler2D backend_test_sib_tex;
layout(binding = 0, set = 0) uniform sampler2D backend_test_sib_tex;
void main() {
fragColor = textureLod(backend_test_sib_tex, uv, 1);
@@ -69,12 +69,12 @@ TEST_F(BackendTest, TextureViewLod) {
Shader whiteShader = SharedShaders::makeShader(api, cleanup, ShaderRequest {
.mVertexType = VertexShaderType::Textured,
.mFragmentType = FragmentShaderType::White,
.mUniformType = ShaderUniformType::Sampler
.mUniformType = ShaderUniformType::Sampler2D
});
// Create a program that samples a texture.
std::string vertexShader = SharedShaders::getVertexShaderText(
VertexShaderType::Textured, ShaderUniformType::Sampler);
VertexShaderType::Textured, ShaderUniformType::Sampler2D);
filament::SamplerInterfaceBlock::SamplerInfo samplerInfo {
"backend_test", "sib_tex", 0,
SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH, false };
+3 -3
View File
@@ -105,6 +105,7 @@ void initPushConstants() {
TEST_F(BackendTest, PushConstants) {
SKIP_IF(Backend::OPENGL, "Push constants not supported on OpenGL");
SKIP_IF(Backend::WEBGPU, "Push constants not supported on WebGPU");
initPushConstants();
@@ -178,9 +179,8 @@ TEST_F(BackendTest, PushConstants) {
api.endRenderPass();
EXPECT_IMAGE(renderTarget, getExpectations(),
ScreenshotParams(params.viewport.width, params.viewport.height, "pushConstants",
3575588741));
EXPECT_IMAGE(renderTarget, ScreenshotParams(params.viewport.width, params.viewport.height,
"pushConstants", 3575588741));
api.commit(swapChain);
api.endFrame(0);
@@ -40,7 +40,7 @@ Shader createShader(DriverApi& api, Cleanup& cleanup, Backend backend) {
return SharedShaders::makeShader(api, cleanup, ShaderRequest{
.mVertexType = VertexShaderType::Textured,
.mFragmentType = FragmentShaderType::Textured,
.mUniformType = ShaderUniformType::Sampler
.mUniformType = ShaderUniformType::Sampler2D
});
}
@@ -199,7 +199,7 @@ TEST_F(BackendTest, RenderExternalImage) {
api.flush();
api.commit(swapChain);
api.endFrame(0);
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
EXPECT_IMAGE(defaultRenderTarget,
ScreenshotParams(screenWidth(), screenHeight(), "RenderExternalImage", 1206264951));
api.stopCapture(0);
+2 -2
View File
@@ -132,7 +132,7 @@ TEST_F(BackendTest, ScissorViewportRegion) {
api.draw2(0, 3, 1);
api.endRenderPass();
EXPECT_IMAGE(fullRenderTarget, getExpectations(),
EXPECT_IMAGE(fullRenderTarget,
ScreenshotParams(kSrcTexWidth >> 1, kSrcTexHeight >> 1, "scissor", 15842520));
api.commit(swapChain);
@@ -224,7 +224,7 @@ TEST_F(BackendTest, ScissorViewportEdgeCases) {
api.draw2(0, 3, 1);
api.endRenderPass();
EXPECT_IMAGE(renderTarget, getExpectations(),
EXPECT_IMAGE(renderTarget,
ScreenshotParams(512, 512, "ScissorViewportEdgeCases", 2199186852));
api.commit(swapChain);
+4 -5
View File
@@ -144,7 +144,7 @@ TEST_F(BasicStencilBufferTest, StencilBuffer) {
RunTest(renderTarget);
EXPECT_IMAGE(renderTarget, getExpectations(),
EXPECT_IMAGE(renderTarget,
ScreenshotParams(screenWidth(), screenHeight(), "StencilBuffer", 0x3B1AEF0F));
flushAndWait();
@@ -170,7 +170,7 @@ TEST_F(BasicStencilBufferTest, DepthAndStencilBuffer) {
RunTest(renderTarget);
EXPECT_IMAGE(renderTarget, getExpectations(),
EXPECT_IMAGE(renderTarget,
ScreenshotParams(screenWidth(), screenHeight(), "DepthAndStencilBuffer", 0x3B1AEF0F));
flushAndWait();
@@ -266,9 +266,8 @@ TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
api.stopCapture(0);
api.endFrame(0);
EXPECT_IMAGE(renderTarget1, getExpectations(),
ScreenshotParams(screenWidth(), screenHeight(), "StencilBufferAutoResolve",
3353562179));
EXPECT_IMAGE(renderTarget1, ScreenshotParams(screenWidth(), screenHeight(),
"StencilBufferAutoResolve", 3353562179));
flushAndWait();
getDriver().purge();
+18 -5
View File
@@ -164,7 +164,9 @@ struct BloomOptions {
};
/**
* Options to control large-scale fog in the scene
* Options to control large-scale fog in the scene. Materials can enable the `linearFog` property,
* which uses a simplified, linear equation for fog calculation; in this mode, the heightFalloff
* is ignored as well as the mipmap selection in IBL or skyColor mode.
*/
struct FogOptions {
/**
@@ -183,7 +185,7 @@ struct FogOptions {
float cutOffDistance = INFINITY;
/**
* fog's maximum opacity between 0 and 1
* fog's maximum opacity between 0 and 1. Ignored in `linearFog` mode.
*/
float maximumOpacity = 1.0f;
@@ -193,12 +195,15 @@ struct FogOptions {
float height = 0.0f;
/**
* How fast the fog dissipates with altitude. heightFalloff has a unit of [1/m].
* How fast the fog dissipates with the altitude. heightFalloff has a unit of [1/m].
* It can be expressed as 1/H, where H is the altitude change in world units [m] that causes a
* factor 2.78 (e) change in fog density.
*
* A falloff of 0 means the fog density is constant everywhere and may result is slightly
* faster computations.
*
* In `linearFog` mode, only use to compute the slope of the linear equation. Completely
* ignored if set to 0.
*/
float heightFalloff = 1.0f;
@@ -220,7 +225,7 @@ struct FogOptions {
LinearColor color = { 1.0f, 1.0f, 1.0f };
/**
* Extinction factor in [1/m] at altitude 'height'. The extinction factor controls how much
* Extinction factor in [1/m] at an altitude 'height'. The extinction factor controls how much
* light is absorbed and out-scattered per unit of distance. Each unit of extinction reduces
* the incoming light to 37% of its original value.
*
@@ -229,11 +234,16 @@ struct FogOptions {
* the composition of the fog/atmosphere.
*
* For historical reason this parameter is called `density`.
*
* In `linearFog` mode this is the slope of the linear equation if heightFalloff is set to 0.
* Otherwise, heightFalloff affects the slope calculation such that it matches the slope of
* the standard equation at the camera height.
*/
float density = 0.1f;
/**
* Distance in world units [m] from the camera where the Sun in-scattering starts.
* Ignored in `linearFog` mode.
*/
float inScatteringStart = 0.0f;
@@ -242,6 +252,7 @@ struct FogOptions {
* is scattered (by the fog) towards the camera.
* Size of the Sun in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100).
* Smaller values result is a larger scattering size.
* Ignored in `linearFog` mode.
*/
float inScatteringSize = -1.0f;
@@ -269,6 +280,8 @@ struct FogOptions {
*
* `fogColorFromIbl` is ignored when skyTexture is specified.
*
* In `linearFog` mode mipmap level 0 is always used.
*
* @see Texture
* @see fogColorFromIbl
*/
@@ -283,7 +296,7 @@ struct FogOptions {
/**
* Options to control Depth of Field (DoF) effect in the scene.
*
* cocScale can be used to set the depth of field blur independently from the camera
* cocScale can be used to set the depth of field blur independently of the camera
* aperture, e.g. for artistic reasons. This can be achieved by setting:
* cocScale = cameraAperture / desiredDoFAperture
*
+47 -13
View File
@@ -16,32 +16,66 @@
#include "DFG.h"
#include "ZstdHelper.h"
#include "details/Engine.h"
#include "details/Texture.h"
#include <filament/Texture.h>
#include <backend/DriverEnums.h>
#include <utils/debug.h>
#include <utils/compiler.h>
#include <utils/Panic.h>
#include <cstdlib>
#include <cstdint>
#include <cstddef>
#include <utility>
#include "generated/resources/dfg.h"
namespace filament {
const uint16_t DFG::DFG_LUT[] = {
#include "generated/data/dfg.inc"
};
void DFG::init(FEngine& engine) noexcept {
void DFG::init(FEngine& engine) {
constexpr size_t fp16Count = DFG_LUT_SIZE * DFG_LUT_SIZE * 3;
constexpr size_t byteCount = fp16Count * sizeof(uint16_t);
static_assert(sizeof(DFG_LUT) == byteCount, "DFG_LUT_SIZE doesn't match size of the DFG LUT");
Texture* lut = Texture::Builder()
Texture::Builder builder = Texture::Builder()
.width(DFG_LUT_SIZE)
.height(DFG_LUT_SIZE)
.format(backend::TextureFormat::RGB16F)
.build(engine);
.format(backend::TextureFormat::RGB16F);
Texture::PixelBufferDescriptor buffer(DFG_LUT, byteCount,
Texture::Format::RGB, Texture::Type::HALF);
if (ZstdHelper::isCompressed(DFG_PACKAGE, DFG_DFG_SIZE)) {
const size_t decodedSize = ZstdHelper::getDecodedSize(DFG_PACKAGE, byteCount);
assert_invariant(decodedSize == byteCount);
lut->setImage(engine, 0, std::move(buffer));
// If the LUT is Zstd compressed, decompress it.
void* decodedData = malloc(decodedSize);
FILAMENT_CHECK_POSTCONDITION(decodedData)
<< "Couldn't allocate " << decodedSize << " bytes for DFG LUT decompression.";
if (UTILS_LIKELY(decodedData)) {
bool const success = ZstdHelper::decompress(
decodedData, decodedSize, DFG_PACKAGE, byteCount);
FILAMENT_CHECK_POSTCONDITION(success) << "Couldn't decompress DFG LUT.";
// Use decodedData for the texture
Texture* lut = builder.build(engine);
lut->setImage(engine, 0, { decodedData, decodedSize,
Texture::Format::RGB, Texture::Type::HALF,
+[](void* buffer, size_t, void*) { free(buffer); } });
mLUT = downcast(lut);
return;
}
}
assert_invariant(DFG_DFG_SIZE == byteCount);
Texture* lut = builder.build(engine);
lut->setImage(engine, 0, { DFG_PACKAGE, byteCount, Texture::Format::RGB, Texture::Type::HALF });
mLUT = downcast(lut);
}
+4 -4
View File
@@ -23,6 +23,9 @@
#include <utils/compiler.h>
#include <cstdint>
#include <cstddef>
namespace filament {
class FEngine;
@@ -40,7 +43,7 @@ public:
DFG& operator=(DFG const& rhs) = delete;
DFG& operator=(DFG&& rhs) = delete;
void init(FEngine& engine) noexcept;
void init(FEngine& engine);
size_t getLutSize() const noexcept {
return DFG_LUT_SIZE;
@@ -61,9 +64,6 @@ private:
// make sure to use the right size here
static constexpr size_t DFG_LUT_SIZE = FILAMENT_DFG_LUT_SIZE;
// this lookup table is generated with cmgen
static const uint16_t DFG_LUT[];
};
#undef FILAMENT_DFG_LUT_SIZE
+4
View File
@@ -363,6 +363,10 @@ bool MaterialParser::getStereoscopicType(StereoscopicType* value) const noexcept
return mImpl.getFromSimpleChunk(MaterialStereoscopicType, reinterpret_cast<uint8_t*>(value));
}
bool MaterialParser::getMaterialCrc32(uint32_t* value) const noexcept {
return mImpl.getFromSimpleChunk(MaterialCrc32, value);
}
bool MaterialParser::getRequiredAttributes(AttributeBitset* value) const noexcept {
uint32_t rawAttributes = 0;
if (!mImpl.getFromSimpleChunk(MaterialRequiredAttributes, &rawAttributes)) {
+1
View File
@@ -126,6 +126,7 @@ public:
bool getSpecularAntiAliasingVariance(float* value) const noexcept;
bool getSpecularAntiAliasingThreshold(float* value) const noexcept;
bool getStereoscopicType(backend::StereoscopicType*) const noexcept;
bool getMaterialCrc32(uint32_t* value) const noexcept;
bool getShader(filaflat::ShaderContent& shader, backend::ShaderModel shaderModel,
Variant variant, backend::ShaderStage stage) noexcept;
+2 -1
View File
@@ -198,7 +198,8 @@ FMaterial* PostProcessManager::PostProcessMaterial::getMaterial(FEngine& engine,
if (UTILS_UNLIKELY(mSize)) {
loadMaterial(engine);
}
mMaterial->prepareProgram(Variant{ Variant::type_t(variant) });
mMaterial->prepareProgram(Variant{ Variant::type_t(variant) },
CompilerPriorityQueue::CRITICAL);
return mMaterial;
}
+4 -3
View File
@@ -243,7 +243,7 @@ void RenderPass::appendCommands(FEngine const& engine,
for (Command const* first = curr, *last = curr + commandCount ; first != last ; ++first) {
if (UTILS_LIKELY((first->key & CUSTOM_MASK) == uint64_t(CustomCommand::PASS))) {
auto ma = first->info.mi->getMaterial();
ma->prepareProgram(first->info.materialVariant);
ma->prepareProgram(first->info.materialVariant, CompilerPriorityQueue::CRITICAL);
}
}
}
@@ -1067,7 +1067,8 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
// Each material has a per-material descriptor-set layout which encodes the
// material's parameters (ubo and samplers)
pipeline.pipelineLayout.setLayout[+DescriptorSetBindingPoints::PER_MATERIAL] =
ma->getDescriptorSetLayout().getHandle();
ma->getDescriptorSetLayout(info.materialVariant).getHandle();
if (UTILS_UNLIKELY(ma->getMaterialDomain() == MaterialDomain::POST_PROCESS)) {
// It is possible to get a post-process material here (even though it's
@@ -1091,7 +1092,7 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
}
// Each MaterialInstance has its own descriptor set. This binds it.
mi->use(driver);
mi->use(driver, info.materialVariant);
}
assert_invariant(ma);
+5 -2
View File
@@ -112,6 +112,8 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
const bool canAutoResolveDepth = engine.getDriverApi().isAutoDepthResolveSupported();
FrameGraphTexture::Usage depthStencilUsage = FrameGraphTexture::Usage::DEPTH_ATTACHMENT;
if (!data.depth) {
// clear newly allocated depth/stencil buffers, regardless of given clear flags
clearDepthFlags = TargetBufferFlags::DEPTH;
@@ -151,6 +153,7 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
.format = format,
});
if (config.enabledStencilBuffer) {
depthStencilUsage |= FrameGraphTexture::Usage::STENCIL_ATTACHMENT;
data.stencil = data.depth;
}
}
@@ -172,10 +175,10 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
// We set a "read" constraint on these attachments here because we need to preserve them
// when the color pass happens in several passes (e.g. with SSR)
data.color = builder.read(data.color, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.depth = builder.read(data.depth, FrameGraphTexture::Usage::DEPTH_ATTACHMENT);
data.depth = builder.read(data.depth, depthStencilUsage);
data.color = builder.write(data.color, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.depth = builder.write(data.depth, FrameGraphTexture::Usage::DEPTH_ATTACHMENT);
data.depth = builder.write(data.depth, depthStencilUsage);
/*
* There is a bit of magic happening here regarding the viewport used.
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ZstdHelper.h"
#include <zstd.h>
#include <cstddef>
#include <cstdint>
namespace filament {
bool ZstdHelper::isCompressed(const void* src, size_t src_size) noexcept {
if (src_size < 4) {
return false;
}
const uint32_t magic = *static_cast<const uint32_t*>(src);
return magic == ZSTD_MAGICNUMBER;
}
size_t ZstdHelper::getDecodedSize(const void* src, size_t src_size) noexcept {
return ZSTD_getFrameContentSize(src, src_size);
}
size_t ZstdHelper::decompress(void* dst, size_t dst_size, const void* src, size_t src_size) noexcept {
return ZSTD_decompress(dst, dst_size, src, src_size);
}
} // namespace filament
+55
View File
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_ZSTD_HELPER_H
#define TNT_FILAMENT_ZSTD_HELPER_H
#include <stddef.h>
namespace filament {
class ZstdHelper {
public:
/**
* Checks if the given binary blob is Zstd compressed.
* @param src Pointer to the source data.
* @param src_size Size of the source data.
* @return True if the data is Zstd compressed, false otherwise.
*/
static bool isCompressed(const void* src, size_t src_size) noexcept;
/**
* Returns the decompressed size of a Zstd compressed blob.
* @param src Pointer to the source data.
* @param src_size Size of the source data.
* @return The decompressed size, or 0 if an error occurs.
*/
static size_t getDecodedSize(const void* src, size_t src_size) noexcept;
/**
* Decompresses a Zstd compressed blob into a pre-allocated buffer.
* @param dst Pointer to the destination buffer.
* @param dst_size Size of the destination buffer.
* @param src Pointer to the source data.
* @param src_size Size of the source data.
* @return The number of bytes decompressed, or 0 if an error occurs.
*/
static size_t decompress(void* dst, size_t dst_size, const void* src, size_t src_size) noexcept;
};
} // namespace filament
#endif // TNT_FILAMENT_ZSTD_HELPER_H
+12 -14
View File
@@ -101,6 +101,8 @@ backend::Platform::DriverConfig getDriverConfig(FEngine* instance) {
.handleArenaSize = instance->getRequestedDriverHandleArenaSize(),
.metalUploadBufferSizeBytes = instance->getConfig().metalUploadBufferSizeBytes,
.disableParallelShaderCompile = instance->features.backend.disable_parallel_shader_compile,
.disableAmortizedShaderCompile =
instance->features.backend.disable_amortized_shader_compile,
.disableHandleUseAfterFreeCheck =
instance->features.backend.disable_handle_use_after_free_check,
.disableHeapHandleTags = instance->features.backend.disable_heap_handle_tags,
@@ -465,6 +467,9 @@ void FEngine::init() {
}
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*this));
}
// We must commit the default material instance here. It may not be used in a scene, but its
// descriptor set may still be used for shared variants.
mDefaultMaterial->getDefaultInstance()->commit(driverApi);
if (UTILS_UNLIKELY(getSupportedFeatureLevel() >= FeatureLevel::FEATURE_LEVEL_1)) {
mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this));
@@ -1235,20 +1240,13 @@ bool FEngine::destroy(const FMaterialInstance* p) {
size_t const primitiveCount = rcm.getPrimitiveCount(ri, 0);
for (size_t j = 0; j < primitiveCount; j++) {
auto const* const mi = rcm.getMaterialInstanceAt(ri, 0, j);
if (features.engine.debug.assert_material_instance_in_use) {
FILAMENT_CHECK_PRECONDITION(mi != p)
<< "destroying MaterialInstance \""
<< mi->getName() << "\" which is still in use by Renderable (entity="
<< entity.getId() << ", instance="
<< ri.asValue() << ", index=" << j << ")";
} else {
if (UTILS_UNLIKELY(mi == p)) {
LOG(ERROR) << "destroying MaterialInstance \"" << mi->getName()
<< "\" which is still in use by Renderable (entity="
<< entity.getId() << ", instance=" << ri.asValue()
<< ", index=" << j << ")";
}
}
auto const& featureFlags = features.engine.debug;
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(
mi != p,
featureFlags.assert_material_instance_in_use)
<< "destroying MaterialInstance \"" << mi->getName()
<< "\" which is still in use by Renderable (entity=" << entity.getId()
<< ", instance=" << ri.asValue() << ", index=" << j << ")";
}
}
}
+24 -1
View File
@@ -731,6 +731,10 @@ public:
bool assert_vertex_buffer_count_exceeds_8 = CORRECTNESS_ASSERTION_DEFAULT;
bool assert_vertex_buffer_attribute_stride_mult_of_4 =
CORRECTNESS_ASSERTION_DEFAULT;
bool assert_material_instance_texture_descriptor_set_compatible =
CORRECTNESS_ASSERTION_DEFAULT;
bool assert_texture_format_mipmappable = CORRECTNESS_ASSERTION_DEFAULT;
bool assert_texture_can_generate_mipmap = CORRECTNESS_ASSERTION_DEFAULT;
} debug;
} engine;
struct {
@@ -744,15 +748,22 @@ public:
bool enable_staging_buffer_bypass = false;
} vulkan;
bool disable_parallel_shader_compile = false;
bool disable_amortized_shader_compile = false;
bool disable_handle_use_after_free_check = false;
bool disable_heap_handle_tags = true; // FIXME: this should be false
} backend;
struct {
bool check_crc32_after_loading = false;
} material;
} features;
std::array<FeatureFlag, sizeof(features)> const mFeatures{{
{ "backend.disable_parallel_shader_compile",
"Disable parallel shader compilation in GL and Metal backends.",
&features.backend.disable_parallel_shader_compile, true },
{ "backend.disable_amortized_shader_compile",
"Disable amortized shader compilation in GL backend.",
&features.backend.disable_amortized_shader_compile, true },
{ "backend.disable_handle_use_after_free_check",
"Disable Handle<> use-after-free checks.",
&features.backend.disable_handle_use_after_free_check, true },
@@ -781,8 +792,20 @@ public:
"Assert that the attribute stride of a vertex buffer is a multiple of 4.",
&features.engine.debug.assert_vertex_buffer_attribute_stride_mult_of_4, false },
{ "backend.vulkan.enable_staging_buffer_bypass",
"vulkan: enable a staging bypass logic for unified memory architecture",
"vulkan: enable a staging bypass logic for unified memory architecture.",
&features.backend.vulkan.enable_staging_buffer_bypass, false },
{ "engine.debug.assert_material_instance_texture_descriptor_set_compatible",
"Assert that the textures in a material instance are compatible with descriptor set.",
&features.engine.debug.assert_material_instance_texture_descriptor_set_compatible, false },
{ "engine.debug.assert_texture_format_mipmappable",
"Assert if a texture (with levels > 1) that the format is mipmappable.",
&features.engine.debug.assert_texture_format_mipmappable, false },
{ "engine.debug.assert_texture_can_generate_mipmap",
"Assert if a texture has the correct usage set for generating mipmaps.",
&features.engine.debug.assert_texture_can_generate_mipmap, false },
{ "material.check_crc32_after_loading",
"Verify the checksum of package data when a material is loaded.",
&features.material.check_crc32_after_loading, false },
}};
utils::Slice<const FeatureFlag> getFeatureFlags() const noexcept {
+29 -12
View File
@@ -188,6 +188,28 @@ Material* Material::Builder::build(Engine& engine) const {
return nullptr;
}
// Try checking CRC32 value for the package and skip if it's unavailable.
if (downcast(engine).features.material.check_crc32_after_loading) {
uint32_t parsedCrc32 = 0;
materialParser->getMaterialCrc32(&parsedCrc32);
constexpr size_t crc32ChunkSize = sizeof(uint64_t) + sizeof(uint32_t) + sizeof(uint32_t);
const size_t originalSize = mImpl->mSize - crc32ChunkSize;
assert_invariant(mImpl->mSize > crc32ChunkSize);
std::vector<uint32_t> crc32Table;
hash::crc32GenerateTable(crc32Table);
uint32_t expectedCrc32 = hash::crc32Update(0, mImpl->mPayload, originalSize, crc32Table);
if (parsedCrc32 != expectedCrc32) {
CString name;
materialParser->getName(&name);
LOG(ERROR) << "The material '" << name.c_str_safe()
<< "' is corrupted: crc32_expected=" << expectedCrc32
<< ", crc32_parsed=" << parsedCrc32;
return nullptr;
}
}
uint32_t v = 0;
materialParser->getShaderModels(&v);
bitset32 shaderModels;
@@ -223,7 +245,7 @@ Material* Material::Builder::build(Engine& engine) const {
materialParser->getName(&name);
LOG(WARNING) << "The stereoscopic type in the compiled material '"
<< name.c_str_safe() << "' is " << (int) materialStereoscopicType
<< ", which is not compatiable with the engine's setting "
<< ", which is not compatible with the engine's setting "
<< (int) engineStereoscopicType << ".";
}
}
@@ -391,16 +413,11 @@ void FMaterial::terminate(FEngine& engine) {
auto const& materialInstanceResourceList = engine.getMaterialInstanceResourceList();
auto pos = materialInstanceResourceList.find(this);
if (UTILS_LIKELY(pos != materialInstanceResourceList.cend())) {
if (engine.features.engine.debug.assert_destroy_material_before_material_instance) {
FILAMENT_CHECK_PRECONDITION(pos->second.empty())
<< "destroying material \"" << this->getName().c_str_safe() << "\" but "
<< pos->second.size() << " instances still alive.";
} else {
if (UTILS_UNLIKELY(!pos->second.empty())) {
LOG(ERROR) << "destroying material \"" << this->getName().c_str_safe() << "\" but "
<< pos->second.size() << " instances still alive.";
}
}
auto const& featureFlags = engine.features.engine.debug;
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(pos->second.empty(),
featureFlags.assert_destroy_material_before_material_instance)
<< "destroying material \"" << this->getName().c_str_safe() << "\" but "
<< pos->second.size() << " instances still alive.";
}
#if FILAMENT_ENABLE_MATDBG
@@ -1169,7 +1186,7 @@ void FMaterial::precacheDepthVariants(FEngine& engine) {
}
assert_invariant(Variant::isValidDepthVariant(variant));
if (hasVariant(variant)) {
prepareProgram(variant);
prepareProgram(variant, CompilerPriorityQueue::HIGH);
}
}
return;
+30 -3
View File
@@ -96,8 +96,18 @@ public:
DescriptorSetLayout const& getPerViewDescriptorSetLayout(
Variant const variant, bool const useVsmDescriptorSetLayout) const noexcept;
DescriptorSetLayout const& getDescriptorSetLayout() const noexcept {
return mDescriptorSetLayout;
// Returns the layout that should be used when this material is bound to the pipeline for the
// given variant. Shared variants use the Engine's default material's variants, so we should
// also use the default material's layout.
DescriptorSetLayout const& getDescriptorSetLayout(Variant variant = {}) const noexcept {
if (!isSharedVariant(variant)) {
return mDescriptorSetLayout;
}
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
if (UTILS_UNLIKELY(!pDefaultMaterial)) {
return mDescriptorSetLayout;
}
return pDefaultMaterial->getDescriptorSetLayout();
}
void compile(CompilerPriorityQueue priority,
@@ -132,7 +142,7 @@ public:
// Must be called outside of backend render pass.
// Must be called before getProgram() below.
void prepareProgram(Variant const variant,
backend::CompilerPriorityQueue const priorityQueue = CompilerPriorityQueue::HIGH) const noexcept {
backend::CompilerPriorityQueue const priorityQueue) const noexcept {
// prepareProgram() is called for each RenderPrimitive in the scene, so it must be efficient.
if (UTILS_UNLIKELY(!isCached(variant))) {
prepareProgramSlow(variant, priorityQueue);
@@ -150,6 +160,23 @@ public:
return mCachedPrograms[variant.key];
}
// MaterialInstance::use() binds descriptor sets before drawing. For shared variants,
// however, the material instance will call useShared() to bind the default material's sets
// instead.
// Returns true if this is a shared variant.
bool useShared(backend::DriverApi& driver, Variant variant) const noexcept {
if (!isSharedVariant(variant)) {
return false;
}
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
if (UTILS_UNLIKELY(!pDefaultMaterial)) {
return false;
}
FMaterialInstance const* const pDefaultInstance = pDefaultMaterial->getDefaultInstance();
pDefaultInstance->use(driver, variant);
return true;
}
[[nodiscard]]
backend::Handle<backend::HwProgram> getProgramWithMATDBG(Variant variant) const noexcept;
+12 -4
View File
@@ -286,9 +286,11 @@ void FMaterialInstance::setParameterImpl(std::string_view const name,
DescriptorType const descriptorType = descriptorSetLayout.getDescriptorType(binding);
TextureType const textureType = texture->getTextureType();
SamplerType const samplerType = texture->getTarget();
FILAMENT_CHECK_PRECONDITION(
DescriptorSet::isTextureCompatibleWithDescriptor(textureType, samplerType, descriptorType))
auto const& featureFlags = mMaterial->getEngine().features.engine.debug;
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(
DescriptorSet::isTextureCompatibleWithDescriptor(
textureType, samplerType, descriptorType),
featureFlags.assert_material_instance_texture_descriptor_set_compatible)
<< "Texture format " << int(texture->getFormat())
<< " of type " << to_string(textureType)
<< " with sampler type " << to_string(samplerType)
@@ -381,7 +383,7 @@ const char* FMaterialInstance::getName() const noexcept {
// ------------------------------------------------------------------------------------------------
void FMaterialInstance::use(FEngine::DriverApi& driver) const {
void FMaterialInstance::use(FEngine::DriverApi& driver, Variant variant) const {
if (UTILS_UNLIKELY(mMissingSamplerDescriptors.any())) {
std::call_once(mMissingSamplersFlag, [this] {
@@ -402,6 +404,12 @@ void FMaterialInstance::use(FEngine::DriverApi& driver) const {
mMissingSamplerDescriptors.clear();
}
// Checks if this variant is shared. If so, FMaterial takes responsibility for binding the
// descriptor sets.
if (mMaterial->useShared(driver, variant)) {
return;
}
mDescriptorSet.bind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
}
+3 -1
View File
@@ -29,6 +29,8 @@
#include <filament/MaterialInstance.h>
#include <private/filament/Variant.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
@@ -71,7 +73,7 @@ public:
void commit(FEngine::DriverApi& driver) const;
void use(FEngine::DriverApi& driver) const;
void use(FEngine::DriverApi& driver, Variant variant = {}) const;
FMaterial const* getMaterial() const noexcept { return mMaterial; }
+2 -1
View File
@@ -446,7 +446,8 @@ void FScene::updateUBOs(
// We capture state shared between Scene and the update buffer callback, because the Scene could
// be destroyed before the callback executes.
std::weak_ptr<SharedState>* const weakShared = new(std::nothrow) std::weak_ptr(mSharedState);
std::weak_ptr<SharedState>* const weakShared =
new (std::nothrow) std::weak_ptr<SharedState>(mSharedState);
// update the UBO
driver.resetBufferObject(renderableUbh);
+26 -10
View File
@@ -242,16 +242,29 @@ Texture* Texture::Builder::build(Engine& engine) {
if (mImpl->mUsage == TextureUsage::NONE) {
mImpl->mUsage = TextureUsage::DEFAULT;
if (mImpl->mLevels > 1 &&
(mImpl->mWidth > 1 || mImpl->mHeight > 1) &&
!mImpl->mExternal) {
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;
}
}
}
auto const& featureFlags = downcast(engine).features.engine.debug;
bool const formatMipmappable =
downcast(engine).getDriverApi().isTextureFormatMipmappable(mImpl->mFormat);
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(mImpl->mLevels == 1 || formatMipmappable,
featureFlags.assert_texture_format_mipmappable)
<< "Texture levels is > 1 (levels=" << +mImpl->mLevels
<< " dim=" << mImpl->mWidth << "x" << mImpl->mHeight
<< ", but the format ("
<< int(mImpl->mFormat) << ") "
<< " is not mipmppable";
// TODO: This exists for backwards compatibility, but should remove when safe.
if (!featureFlags.assert_texture_can_generate_mipmap &&
// Guess whether GEN_MIPMAPPABLE should be added or not based the following criteria.
(formatMipmappable &&
mImpl->mLevels > 1 &&
(mImpl->mWidth > 1 || mImpl->mHeight > 1) &&
!mImpl->mExternal)) {
mImpl->mUsage |= TextureUsage::GEN_MIPMAPPABLE;
}
// TODO: remove in a future filament release.
@@ -640,6 +653,9 @@ void FTexture::generateMipmaps(FEngine& engine) const noexcept {
FILAMENT_CHECK_PRECONDITION(formatMipmappable)
<< "Texture format " << (unsigned)mFormat << " is not mipmappable.";
FILAMENT_CHECK_PRECONDITION(any(mUsage & TextureUsage::GEN_MIPMAPPABLE))
<< "Texture usage does not have GEN_MIPMAPPABLE set";
if (mLevelCount < 2 || (mWidth == 1 && mHeight == 1)) {
return;
}
+9 -15
View File
@@ -158,12 +158,11 @@ VertexBuffer* VertexBuffer::Builder::build(Engine& engine) {
static_assert(DOCUMENTED_MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_BUFFER_COUNT);
if (downcast(engine).features.engine.debug.assert_vertex_buffer_count_exceeds_8) {
FILAMENT_CHECK_PRECONDITION(mImpl->mBufferCount <= DOCUMENTED_MAX_VERTEX_BUFFER_COUNT)
<< "bufferCount cannot be more than " << DOCUMENTED_MAX_VERTEX_BUFFER_COUNT;
} else if (mImpl->mBufferCount > DOCUMENTED_MAX_VERTEX_BUFFER_COUNT) {
LOG(WARNING) << "bufferCount cannot be more than " << DOCUMENTED_MAX_VERTEX_BUFFER_COUNT;
}
auto const& featureFlags = static_cast<FEngine*>(&engine)->features.engine.debug;
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(
mImpl->mBufferCount <= DOCUMENTED_MAX_VERTEX_BUFFER_COUNT,
featureFlags.assert_vertex_buffer_count_exceeds_8)
<< "bufferCount cannot be more than " << DOCUMENTED_MAX_VERTEX_BUFFER_COUNT;
// Next we check if any unused buffer slots have been allocated. This helps prevent errors
// because uploading to an unused slot can trigger undefined behavior in the backend.
@@ -177,15 +176,10 @@ VertexBuffer* VertexBuffer::Builder::build(Engine& engine) {
<< "attribute " << j << " offset=" << attributes[j].offset
<< " is not multiple of 4";
FEngine* fengine = static_cast<FEngine*>(&engine);
if (fengine->features.engine.debug.assert_vertex_buffer_attribute_stride_mult_of_4) {
FILAMENT_CHECK_PRECONDITION((attributes[j].stride & 0x3u) == 0)
<< "attribute " << j << " stride=" << attributes[j].stride
<< " is not multiple of 4";
} else if ((attributes[j].stride & 0x3u) != 0) {
LOG(WARNING) << "attribute " << j << " stride=" << attributes[j].stride
<< " is not multiple of 4";
}
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION((attributes[j].stride & 0x3u) == 0,
featureFlags.assert_vertex_buffer_attribute_stride_mult_of_4)
<< "attribute " << j << " stride=" << +attributes[j].stride
<< " is not multiple of 4";
if (engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0) {
FILAMENT_CHECK_PRECONDITION(!(attributes[j].flags & Attribute::FLAG_INTEGER_TARGET))
+22 -6
View File
@@ -19,8 +19,6 @@
#include "Froxelizer.h"
#include "PerViewDescriptorSetUtils.h"
#include "HwDescriptorSetLayoutFactory.h"
#include "ShadowMapManager.h"
#include "TypedUniformBuffer.h"
#include "components/LightManager.h"
@@ -30,10 +28,8 @@
#include "details/IndirectLight.h"
#include "details/Texture.h"
#include <filament/Engine.h>
#include <filament/Exposure.h>
#include <filament/Options.h>
#include <filament/TextureSampler.h>
#include <filament/MaterialEnums.h>
#include <filament/Viewport.h>
@@ -56,9 +52,11 @@
#include <algorithm>
#include <array>
#include <cmath>
#include <cstring>
#include <cstddef>
#include <limits>
#include <random>
#include <stddef.h>
#include <stdint.h>
namespace filament {
@@ -243,6 +241,22 @@ void ColorPassDescriptorSet::prepareFog(FEngine& engine, const CameraInfo& camer
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_LINEAR
});
// Fog calculation details:
// Optical path: (
// f = heightFalloff
// Te(y, z) = z * density * (exp(-f * eye_y) - exp(-f * eye_y - f * y)) / (f * y)
// Transmittance:
// t(y , z) = exp(-Te(y, z))
// In Linear Mode, formally the slope of the linear equation is: dt(y,z)/dz(0, eye_y)
// (the derivative of the transmittance at distance 0 and camera height). When the height
// falloff is disabled, the density parameter exactly represents this value.
constexpr double EPSILON = std::numeric_limits<float>::epsilon();
double const f = heightFalloff;
double const eye = userCameraPosition.y - options.height;
double const dt = options.density * (f <= EPSILON ? 1.0 : (std::exp(-f * eye) - std::exp(-2.0 * f * eye)) / (f * eye));
float const fogEndLinear = float(1.0 / dt);
s.fogStart = options.distance;
s.fogMaxOpacity = options.maximumOpacity;
s.fogHeightFalloff = heightFalloff;
@@ -253,6 +267,8 @@ void ColorPassDescriptorSet::prepareFog(FEngine& engine, const CameraInfo& camer
s.fogInscatteringSize = options.inScatteringSize;
s.fogColorFromIbl = fogColorTextureHandle ? 1.0f : 0.0f;
s.fogFromWorldMatrix = mat3f{ cof(fogFromWorld) };
s.fogLinearParams = { 1.0f / (fogEndLinear - options.distance),
-options.distance / (fogEndLinear - options.distance) };
}
void ColorPassDescriptorSet::prepareSSAO(Handle<HwTexture> ssao,
@@ -332,7 +348,7 @@ void ColorPassDescriptorSet::prepareDirectionalLight(FEngine& engine,
}
}
void ColorPassDescriptorSet::prepareAmbientLight(FEngine& engine, FIndirectLight const& ibl,
void ColorPassDescriptorSet::prepareAmbientLight(FEngine const& engine, FIndirectLight const& ibl,
float const intensity, float const exposure) noexcept {
auto& s = mUniforms.edit();
+1 -1
View File
@@ -115,7 +115,7 @@ public:
void prepareDirectionalLight(FEngine& engine, float exposure,
math::float3 const& sceneSpaceDirection, LightManagerInstance instance) noexcept;
void prepareAmbientLight(FEngine& engine,
void prepareAmbientLight(FEngine const& engine,
FIndirectLight const& ibl, float intensity, float exposure) noexcept;
void prepareDynamicLights(Froxelizer& froxelizer) noexcept;
+2 -1
View File
@@ -4,7 +4,8 @@ material {
{
type : sampler2dArray,
name : shadowmap,
precision : high
precision : high,
filterable : false
},
{
type : float,
@@ -4,7 +4,8 @@ material {
{
type : sampler2dArray,
name : ssao,
precision: medium
precision: medium,
filterable: false
},
{
type : float2,
@@ -4,7 +4,8 @@ material {
{
type : sampler2dArray,
name : ssao,
precision: medium
precision: medium,
filterable: false
},
{
type : float2,
@@ -5,7 +5,7 @@ material {
type : sampler2d,
name : depth,
precision: high,
unfilterable: true
filterable: false
},
{
type : mat4,
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.62.2"
spec.version = "1.63.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.62.2/filament-v1.62.2-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.63.0/filament-v1.63.0-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
+1 -1
View File
@@ -21,7 +21,7 @@ targetTemplates:
base:
OTHER_LDFLAGS: ["-lfilament", "-lbackend", "-lfilaflat", "-lktxreader",
"-lfilabridge", "-lutils", "-lsmol-v", "-lgeometry", "-libl",
"-labseil"]
"-labseil", "-lzstd"]
ENABLE_BITCODE: NO
CLANG_CXX_LANGUAGE_STANDARD: gnu++17
# This allows users to not have to specify a unique bundle ID when building the sample apps.
@@ -255,6 +255,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lfilamat",
"-force_load ../../../out/ios-debug/filament/lib/arm64/libbackend_test.a",
);
@@ -363,6 +364,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lfilamat",
"-force_load ../../../out/ios-debug/filament/lib/arm64/libbackend_test.a",
);
@@ -464,6 +466,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lfilamat",
"-force_load ../../../out/ios-debug/filament/lib/arm64/libbackend_test.a",
);
@@ -510,6 +513,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lfilamat",
"-force_load ../../../out/ios-debug/filament/lib/arm64/libbackend_test.a",
);
@@ -426,6 +426,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lgltfio_core",
"-luberarchive",
"-limage",
@@ -482,6 +483,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lgltfio_core",
"-luberarchive",
"-limage",
@@ -600,6 +602,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lgltfio_core",
"-luberarchive",
"-limage",
@@ -656,6 +659,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lgltfio_core",
"-luberarchive",
"-limage",
@@ -293,6 +293,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lfilameshio",
"-lmeshoptimizer",
"-limage",
@@ -340,6 +341,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lfilameshio",
"-lmeshoptimizer",
"-limage",
@@ -449,6 +451,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lfilameshio",
"-lmeshoptimizer",
"-limage",
@@ -613,6 +616,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lfilameshio",
"-lmeshoptimizer",
"-limage",
@@ -329,6 +329,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lgltfio_core",
"-luberarchive",
"-limage",
@@ -382,6 +383,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lgltfio_core",
"-luberarchive",
"-limage",
@@ -607,6 +609,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lgltfio_core",
"-luberarchive",
"-limage",
@@ -660,6 +663,7 @@
"-lgeometry",
"-libl",
"-labseil",
"-lzstd",
"-lgltfio_core",
"-luberarchive",
"-limage",

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