Compare commits
49
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ed10d77de | ||
|
|
e8e99a0de6 | ||
|
|
6630aa5f36 | ||
|
|
bc83ffdcd1 | ||
|
|
c21f211a13 | ||
|
|
58d4671c24 | ||
|
|
93caca7245 | ||
|
|
bf77c023b9 | ||
|
|
95128d5f55 | ||
|
|
6d17d858de | ||
|
|
05003ea358 | ||
|
|
98847d6509 | ||
|
|
d3828cdd1c | ||
|
|
4beda6feee | ||
|
|
7cacef9509 | ||
|
|
5cd7de7318 | ||
|
|
9c87e72a81 | ||
|
|
652d973ad8 | ||
|
|
84661777e7 | ||
|
|
c8ab2f335e | ||
|
|
db14efc151 | ||
|
|
d1ca059dad | ||
|
|
c71a22914f | ||
|
|
71d0723026 | ||
|
|
5c371089f2 | ||
|
|
2c7064e93d | ||
|
|
3961989aca | ||
|
|
b92af357f7 | ||
|
|
f2a1051df9 | ||
|
|
594ab3e9e3 | ||
|
|
7f18c7fd43 | ||
|
|
9c1a252ba5 | ||
|
|
bf8e798b60 | ||
|
|
b94e90416a | ||
|
|
e9fde8346e | ||
|
|
3ae747b544 | ||
|
|
5924633085 | ||
|
|
a07c19e5b7 | ||
|
|
59f4d1ba20 | ||
|
|
ac076e872e | ||
|
|
9e55331801 | ||
|
|
f70a11ced4 | ||
|
|
455545f024 | ||
|
|
f35ec42125 | ||
|
|
4242bc43fd | ||
|
|
bbe6d35bf2 | ||
|
|
c8894521c8 | ||
|
|
a2475b5dcb | ||
|
|
b7b89168a7 |
@@ -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,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**]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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**]
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
|
||||
+1
@@ -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);
|
||||
|
||||
@@ -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
@@ -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', '~> 1.62.2'
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 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
@@ -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', '~> 1.62.2'
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 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
@@ -235,36 +235,38 @@ counter-increment: h6;margin-right:10px}
|
||||
<a href="#materialdefinitions/materialblock/general:constants" target="_self" class="level3"><span class="tocNumber">4.2.5 </span>General: constants</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/general:variantfilter" target="_self" class="level3"><span class="tocNumber">4.2.6 </span>General: variantFilter</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/general:flipuv" target="_self" class="level3"><span class="tocNumber">4.2.7 </span>General: flipUV</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/general:quality" target="_self" class="level3"><span class="tocNumber">4.2.8 </span>General: quality</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/general:instanced" target="_self" class="level3"><span class="tocNumber">4.2.9 </span>General: instanced</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/general:vertexdomaindevicejittered" target="_self" class="level3"><span class="tocNumber">4.2.10 </span>General: vertexDomainDeviceJittered</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:requires" target="_self" class="level3"><span class="tocNumber">4.2.11 </span>Vertex and attributes: requires</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:variables" target="_self" class="level3"><span class="tocNumber">4.2.12 </span>Vertex and attributes: variables</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:vertexdomain" target="_self" class="level3"><span class="tocNumber">4.2.13 </span>Vertex and attributes: vertexDomain</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:interpolation" target="_self" class="level3"><span class="tocNumber">4.2.14 </span>Vertex and attributes: interpolation</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:blending" target="_self" class="level3"><span class="tocNumber">4.2.15 </span>Blending and transparency: blending</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:blendfunction" target="_self" class="level3"><span class="tocNumber">4.2.16 </span>Blending and transparency: blendFunction</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:postlightingblending" target="_self" class="level3"><span class="tocNumber">4.2.17 </span>Blending and transparency: postLightingBlending</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:transparency" target="_self" class="level3"><span class="tocNumber">4.2.18 </span>Blending and transparency: transparency</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:maskthreshold" target="_self" class="level3"><span class="tocNumber">4.2.19 </span>Blending and transparency: maskThreshold</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:refractionmode" target="_self" class="level3"><span class="tocNumber">4.2.20 </span>Blending and transparency: refractionMode</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:refractiontype" target="_self" class="level3"><span class="tocNumber">4.2.21 </span>Blending and transparency: refractionType</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:culling" target="_self" class="level3"><span class="tocNumber">4.2.22 </span>Rasterization: culling</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:colorwrite" target="_self" class="level3"><span class="tocNumber">4.2.23 </span>Rasterization: colorWrite</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:depthwrite" target="_self" class="level3"><span class="tocNumber">4.2.24 </span>Rasterization: depthWrite</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:depthculling" target="_self" class="level3"><span class="tocNumber">4.2.25 </span>Rasterization: depthCulling</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:doublesided" target="_self" class="level3"><span class="tocNumber">4.2.26 </span>Rasterization: doubleSided</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:alphatocoverage" target="_self" class="level3"><span class="tocNumber">4.2.27 </span>Rasterization: alphaToCoverage</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/lighting:reflections" target="_self" class="level3"><span class="tocNumber">4.2.28 </span>Lighting: reflections</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/lighting:shadowmultiplier" target="_self" class="level3"><span class="tocNumber">4.2.29 </span>Lighting: shadowMultiplier</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/lighting:transparentshadow" target="_self" class="level3"><span class="tocNumber">4.2.30 </span>Lighting: transparentShadow</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/lighting:clearcoatiorchange" target="_self" class="level3"><span class="tocNumber">4.2.31 </span>Lighting: clearCoatIorChange</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/lighting:multibounceambientocclusion" target="_self" class="level3"><span class="tocNumber">4.2.32 </span>Lighting: multiBounceAmbientOcclusion</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/lighting:specularambientocclusion" target="_self" class="level3"><span class="tocNumber">4.2.33 </span>Lighting: specularAmbientOcclusion</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasing" target="_self" class="level3"><span class="tocNumber">4.2.34 </span>Anti-aliasing: specularAntiAliasing</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasingvariance" target="_self" class="level3"><span class="tocNumber">4.2.35 </span>Anti-aliasing: specularAntiAliasingVariance</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasingthreshold" target="_self" class="level3"><span class="tocNumber">4.2.36 </span>Anti-aliasing: specularAntiAliasingThreshold</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/shading:customsurfaceshading" target="_self" class="level3"><span class="tocNumber">4.2.37 </span>Shading: customSurfaceShading</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/general:linearfog" target="_self" class="level3"><span class="tocNumber">4.2.8 </span>General: linearFog</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/general:quality" target="_self" class="level3"><span class="tocNumber">4.2.9 </span>General: quality</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/general:instanced" target="_self" class="level3"><span class="tocNumber">4.2.10 </span>General: instanced</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/general:vertexdomaindevicejittered" target="_self" class="level3"><span class="tocNumber">4.2.11 </span>General: vertexDomainDeviceJittered</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/general:usedefaultdepthvariant" target="_self" class="level3"><span class="tocNumber">4.2.12 </span>General: useDefaultDepthVariant</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:requires" target="_self" class="level3"><span class="tocNumber">4.2.13 </span>Vertex and attributes: requires</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:variables" target="_self" class="level3"><span class="tocNumber">4.2.14 </span>Vertex and attributes: variables</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:vertexdomain" target="_self" class="level3"><span class="tocNumber">4.2.15 </span>Vertex and attributes: vertexDomain</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:interpolation" target="_self" class="level3"><span class="tocNumber">4.2.16 </span>Vertex and attributes: interpolation</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:blending" target="_self" class="level3"><span class="tocNumber">4.2.17 </span>Blending and transparency: blending</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:blendfunction" target="_self" class="level3"><span class="tocNumber">4.2.18 </span>Blending and transparency: blendFunction</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:postlightingblending" target="_self" class="level3"><span class="tocNumber">4.2.19 </span>Blending and transparency: postLightingBlending</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:transparency" target="_self" class="level3"><span class="tocNumber">4.2.20 </span>Blending and transparency: transparency</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:maskthreshold" target="_self" class="level3"><span class="tocNumber">4.2.21 </span>Blending and transparency: maskThreshold</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:refractionmode" target="_self" class="level3"><span class="tocNumber">4.2.22 </span>Blending and transparency: refractionMode</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:refractiontype" target="_self" class="level3"><span class="tocNumber">4.2.23 </span>Blending and transparency: refractionType</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:culling" target="_self" class="level3"><span class="tocNumber">4.2.24 </span>Rasterization: culling</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:colorwrite" target="_self" class="level3"><span class="tocNumber">4.2.25 </span>Rasterization: colorWrite</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:depthwrite" target="_self" class="level3"><span class="tocNumber">4.2.26 </span>Rasterization: depthWrite</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:depthculling" target="_self" class="level3"><span class="tocNumber">4.2.27 </span>Rasterization: depthCulling</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:doublesided" target="_self" class="level3"><span class="tocNumber">4.2.28 </span>Rasterization: doubleSided</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:alphatocoverage" target="_self" class="level3"><span class="tocNumber">4.2.29 </span>Rasterization: alphaToCoverage</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/lighting:reflections" target="_self" class="level3"><span class="tocNumber">4.2.30 </span>Lighting: reflections</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/lighting:shadowmultiplier" target="_self" class="level3"><span class="tocNumber">4.2.31 </span>Lighting: shadowMultiplier</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/lighting:transparentshadow" target="_self" class="level3"><span class="tocNumber">4.2.32 </span>Lighting: transparentShadow</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/lighting:clearcoatiorchange" target="_self" class="level3"><span class="tocNumber">4.2.33 </span>Lighting: clearCoatIorChange</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/lighting:multibounceambientocclusion" target="_self" class="level3"><span class="tocNumber">4.2.34 </span>Lighting: multiBounceAmbientOcclusion</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/lighting:specularambientocclusion" target="_self" class="level3"><span class="tocNumber">4.2.35 </span>Lighting: specularAmbientOcclusion</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasing" target="_self" class="level3"><span class="tocNumber">4.2.36 </span>Anti-aliasing: specularAntiAliasing</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasingvariance" target="_self" class="level3"><span class="tocNumber">4.2.37 </span>Anti-aliasing: specularAntiAliasingVariance</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasingthreshold" target="_self" class="level3"><span class="tocNumber">4.2.38 </span>Anti-aliasing: specularAntiAliasingThreshold</a><br/>
|
||||
<a href="#materialdefinitions/materialblock/shading:customsurfaceshading" target="_self" class="level3"><span class="tocNumber">4.2.39 </span>Shading: customSurfaceShading</a><br/>
|
||||
<a href="#materialdefinitions/vertexblock" target="_self" class="level2"><span class="tocNumber">4.3 </span>Vertex block</a><br/>
|
||||
<a href="#materialdefinitions/vertexblock/materialvertexinputs" target="_self" class="level3"><span class="tocNumber">4.3.1 </span>Material vertex inputs</a><br/>
|
||||
<a href="#materialdefinitions/vertexblock/customvertexattributes" target="_self" class="level3"><span class="tocNumber">4.3.2 </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 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"> </a><a class="target" name="materialdefinitions/materialblock/general:quality"> </a><a class="target" name="toc4.2.8"> </a><h3 id="general-quality"><a class="header" href="#general-quality">General: quality</a></h3>
|
||||
<a class="target" name="general:linearfog"> </a><a class="target" name="materialdefinitions/materialblock/general:linearfog"> </a><a class="target" name="toc4.2.8"> </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"> </a><a class="target" name="materialdefinitions/materialblock/general:quality"> </a><a class="target" name="toc4.2.9"> </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"> </a><a class="target" name="materialdefinitions/materialblock/general:instanced"> </a><a class="target" name="toc4.2.9"> </a><h3 id="general-instanced"><a class="header" href="#general-instanced">General: instanced</a></h3>
|
||||
<a class="target" name="general:instanced"> </a><a class="target" name="materialdefinitions/materialblock/general:instanced"> </a><a class="target" name="toc4.2.10"> </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"> </a><a class="target" name="materialdefinitions/materialblock/general:vertexdomaindevicejittered"> </a><a class="target" name="toc4.2.10"> </a><h3 id="general-vertexdomaindevicejittered"><a class="header" href="#general-vertexdomaindevicejittered">General: vertexDomainDeviceJittered</a></h3>
|
||||
<a class="target" name="general:vertexdomaindevicejittered"> </a><a class="target" name="materialdefinitions/materialblock/general:vertexdomaindevicejittered"> </a><a class="target" name="toc4.2.11"> </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"> </a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:requires"> </a><a class="target" name="toc4.2.11"> </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"> </a><a class="target" name="materialdefinitions/materialblock/general:usedefaultdepthvariant"> </a><a class="target" name="toc4.2.12"> </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"> </a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:requires"> </a><a class="target" name="toc4.2.13"> </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"> </a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:variables"> </a><a class="target" name="toc4.2.12"> </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"> </a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:variables"> </a><a class="target" name="toc4.2.14"> </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"> </a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:vertexdomain"> </a><a class="target" name="toc4.2.13"> </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"> </a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:vertexdomain"> </a><a class="target" name="toc4.2.15"> </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"> </a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:interpolation"> </a><a class="target" name="toc4.2.14"> </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"> </a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:interpolation"> </a><a class="target" name="toc4.2.16"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:blending"> </a><a class="target" name="toc4.2.15"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:blending"> </a><a class="target" name="toc4.2.17"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:blendfunction"> </a><a class="target" name="toc4.2.16"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:blendfunction"> </a><a class="target" name="toc4.2.18"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:postlightingblending"> </a><a class="target" name="toc4.2.17"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:postlightingblending"> </a><a class="target" name="toc4.2.19"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:transparency"> </a><a class="target" name="toc4.2.18"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:transparency"> </a><a class="target" name="toc4.2.20"> </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"> </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 35:</b> In <code>twoPassesTwoSides</code> mode, both set of faces are visible
|
||||
</span></center></div></center>
|
||||
</p>
|
||||
<a class="target" name="blendingandtransparency:maskthreshold"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:maskthreshold"> </a><a class="target" name="toc4.2.19"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:maskthreshold"> </a><a class="target" name="toc4.2.21"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:refractionmode"> </a><a class="target" name="toc4.2.20"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:refractionmode"> </a><a class="target" name="toc4.2.22"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:refractiontype"> </a><a class="target" name="toc4.2.21"> </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"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:refractiontype"> </a><a class="target" name="toc4.2.23"> </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"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:culling"> </a><a class="target" name="toc4.2.22"> </a><h3 id="rasterization-culling"><a class="header" href="#rasterization-culling">Rasterization: culling</a></h3>
|
||||
<a class="target" name="rasterization:culling"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:culling"> </a><a class="target" name="toc4.2.24"> </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"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:colorwrite"> </a><a class="target" name="toc4.2.23"> </a><h3 id="rasterization-colorwrite"><a class="header" href="#rasterization-colorwrite">Rasterization: colorWrite</a></h3>
|
||||
<a class="target" name="rasterization:colorwrite"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:colorwrite"> </a><a class="target" name="toc4.2.25"> </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"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:depthwrite"> </a><a class="target" name="toc4.2.24"> </a><h3 id="rasterization-depthwrite"><a class="header" href="#rasterization-depthwrite">Rasterization: depthWrite</a></h3>
|
||||
<a class="target" name="rasterization:depthwrite"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:depthwrite"> </a><a class="target" name="toc4.2.26"> </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"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:depthculling"> </a><a class="target" name="toc4.2.25"> </a><h3 id="rasterization-depthculling"><a class="header" href="#rasterization-depthculling">Rasterization: depthCulling</a></h3>
|
||||
<a class="target" name="rasterization:depthculling"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:depthculling"> </a><a class="target" name="toc4.2.27"> </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"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:doublesided"> </a><a class="target" name="toc4.2.26"> </a><h3 id="rasterization-doublesided"><a class="header" href="#rasterization-doublesided">Rasterization: doubleSided</a></h3>
|
||||
<a class="target" name="rasterization:doublesided"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:doublesided"> </a><a class="target" name="toc4.2.28"> </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"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:alphatocoverage"> </a><a class="target" name="toc4.2.27"> </a><h3 id="rasterization-alphatocoverage"><a class="header" href="#rasterization-alphatocoverage">Rasterization: alphaToCoverage</a></h3>
|
||||
<a class="target" name="rasterization:alphatocoverage"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:alphatocoverage"> </a><a class="target" name="toc4.2.29"> </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"> </a><a class="target" name="materialdefinitions/materialblock/lighting:reflections"> </a><a class="target" name="toc4.2.28"> </a><h3 id="lighting-reflections"><a class="header" href="#lighting-reflections">Lighting: reflections</a></h3>
|
||||
<a class="target" name="lighting:reflections"> </a><a class="target" name="materialdefinitions/materialblock/lighting:reflections"> </a><a class="target" name="toc4.2.30"> </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">"Glossy metal"</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"> </a><a class="target" name="materialdefinitions/materialblock/lighting:shadowmultiplier"> </a><a class="target" name="toc4.2.29"> </a><h3 id="lighting-shadowmultiplier"><a class="header" href="#lighting-shadowmultiplier">Lighting: shadowMultiplier</a></h3>
|
||||
<a class="target" name="lighting:shadowmultiplier"> </a><a class="target" name="materialdefinitions/materialblock/lighting:shadowmultiplier"> </a><a class="target" name="toc4.2.31"> </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"> </a><a class="target" name="materialdefinitions/materialblock/lighting:transparentshadow"> </a><a class="target" name="toc4.2.30"> </a><h3 id="lighting-transparentshadow"><a class="header" href="#lighting-transparentshadow">Lighting: transparentShadow</a></h3>
|
||||
<a class="target" name="lighting:transparentshadow"> </a><a class="target" name="materialdefinitions/materialblock/lighting:transparentshadow"> </a><a class="target" name="toc4.2.32"> </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"> </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 36:</b> Objects rendered with transparent shadows and blurry VSM with a
|
||||
</span></center></div></center>
|
||||
</p>
|
||||
<a class="target" name="lighting:clearcoatiorchange"> </a><a class="target" name="materialdefinitions/materialblock/lighting:clearcoatiorchange"> </a><a class="target" name="toc4.2.31"> </a><h3 id="lighting-clearcoatiorchange"><a class="header" href="#lighting-clearcoatiorchange">Lighting: clearCoatIorChange</a></h3>
|
||||
<a class="target" name="lighting:clearcoatiorchange"> </a><a class="target" name="materialdefinitions/materialblock/lighting:clearcoatiorchange"> </a><a class="target" name="toc4.2.33"> </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"> </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 37:</b> The same rough metallic ball with a clear coat layer rendered
|
||||
</span></center></div></center>
|
||||
</p>
|
||||
<a class="target" name="lighting:multibounceambientocclusion"> </a><a class="target" name="materialdefinitions/materialblock/lighting:multibounceambientocclusion"> </a><a class="target" name="toc4.2.32"> </a><h3 id="lighting-multibounceambientocclusion"><a class="header" href="#lighting-multibounceambientocclusion">Lighting: multiBounceAmbientOcclusion</a></h3>
|
||||
<a class="target" name="lighting:multibounceambientocclusion"> </a><a class="target" name="materialdefinitions/materialblock/lighting:multibounceambientocclusion"> </a><a class="target" name="toc4.2.34"> </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"> </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 39:</b> Brick texture rendered with multi-bounce ambient
|
||||
</span></center></div></center>
|
||||
</p>
|
||||
<a class="target" name="lighting:specularambientocclusion"> </a><a class="target" name="materialdefinitions/materialblock/lighting:specularambientocclusion"> </a><a class="target" name="toc4.2.33"> </a><h3 id="lighting-specularambientocclusion"><a class="header" href="#lighting-specularambientocclusion">Lighting: specularAmbientOcclusion</a></h3>
|
||||
<a class="target" name="lighting:specularambientocclusion"> </a><a class="target" name="materialdefinitions/materialblock/lighting:specularambientocclusion"> </a><a class="target" name="toc4.2.35"> </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"> </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 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"> </a><a class="target" name="materialdefinitions/materialblock/anti-aliasing:specularantialiasing"> </a><a class="target" name="toc4.2.34"> </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"> </a><a class="target" name="materialdefinitions/materialblock/anti-aliasing:specularantialiasing"> </a><a class="target" name="toc4.2.36"> </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"> </a><a class="target" name="materialdefinitions/materialblock/anti-aliasing:specularantialiasingvariance"> </a><a class="target" name="toc4.2.35"> </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"> </a><a class="target" name="materialdefinitions/materialblock/anti-aliasing:specularantialiasingvariance"> </a><a class="target" name="toc4.2.37"> </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"> </a><a class="target" name="materialdefinitions/materialblock/anti-aliasing:specularantialiasingthreshold"> </a><a class="target" name="toc4.2.36"> </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"> </a><a class="target" name="materialdefinitions/materialblock/anti-aliasing:specularantialiasingthreshold"> </a><a class="target" name="toc4.2.38"> </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"> </a><a class="target" name="materialdefinitions/materialblock/shading:customsurfaceshading"> </a><a class="target" name="toc4.2.37"> </a><h3 id="shading-customsurfaceshading"><a class="header" href="#shading-customsurfaceshading">Shading: customSurfaceShading</a></h3>
|
||||
<a class="target" name="shading:customsurfaceshading"> </a><a class="target" name="materialdefinitions/materialblock/shading:customsurfaceshading"> </a><a class="target" name="toc4.2.39"> </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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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
@@ -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
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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, ©Size);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, ©Size);
|
||||
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 } {}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user