Compare commits
257
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6dbee125b3 | ||
|
|
e64b498d6e | ||
|
|
31ab4a13c9 | ||
|
|
e9728dcc8d | ||
|
|
40a3644086 | ||
|
|
41ef71abdf | ||
|
|
3b40e52c98 | ||
|
|
de8c7969f3 | ||
|
|
f2c049222b | ||
|
|
be30ac1fcb | ||
|
|
c5cc7fe26a | ||
|
|
d04b0a5c73 | ||
|
|
72ab2aef0a | ||
|
|
1527bb7ad3 | ||
|
|
8cb26fc9ac | ||
|
|
c21794d0a0 | ||
|
|
1a6338569a | ||
|
|
c5ebe1a88a | ||
|
|
a3f2028ae4 | ||
|
|
c393ee4591 | ||
|
|
83a82ae10e | ||
|
|
676694e458 | ||
|
|
2ca218928f | ||
|
|
776ce223fc | ||
|
|
0d4d1f55c9 | ||
|
|
d6dba71ace | ||
|
|
61ee11ae6c | ||
|
|
90f32e7277 | ||
|
|
b85d9afdb3 | ||
|
|
4297d43d9a | ||
|
|
cfcf714c21 | ||
|
|
f7cfc6a65e | ||
|
|
4ead3bcebf | ||
|
|
21e0677039 | ||
|
|
107b5a4854 | ||
|
|
9761b65137 | ||
|
|
b1831d2786 | ||
|
|
977d369e40 | ||
|
|
5cf5b25175 | ||
|
|
e75c3020c8 | ||
|
|
aeb0a4008d | ||
|
|
2d43ad59ec | ||
|
|
f86ec07c45 | ||
|
|
fc012d6d65 | ||
|
|
6b71232e38 | ||
|
|
e157023fc1 | ||
|
|
6e38db882f | ||
|
|
09600699cb | ||
|
|
6a5e74f031 | ||
|
|
795bd1e995 | ||
|
|
784416f658 | ||
|
|
b151afe567 | ||
|
|
117ae1d648 | ||
|
|
7165d8aa54 | ||
|
|
6b461b2d89 | ||
|
|
affc5be840 | ||
|
|
e3ff5616ef | ||
|
|
d9a401d57e | ||
|
|
acd5823953 | ||
|
|
9b13565750 | ||
|
|
734d8ff85c | ||
|
|
a02ef1a6c7 | ||
|
|
f13bf11d0f | ||
|
|
7d0b5fed8f | ||
|
|
e1f51f04c1 | ||
|
|
f6d74be123 | ||
|
|
50a1935b68 | ||
|
|
694ecce150 | ||
|
|
3e3bd2722f | ||
|
|
44fdf83e4c | ||
|
|
99c4ce67e4 | ||
|
|
71aceec4cf | ||
|
|
98e4cdbd4c | ||
|
|
86ef0109f4 | ||
|
|
b4142261c2 | ||
|
|
359624e8eb | ||
|
|
5bcc11d9e8 | ||
|
|
5aa414dd24 | ||
|
|
1e51b03971 | ||
|
|
fc484bd319 | ||
|
|
9c4783142e | ||
|
|
4dc03318e8 | ||
|
|
15ba54c4c5 | ||
|
|
342138aecb | ||
|
|
9f53c62e06 | ||
|
|
2d996033e3 | ||
|
|
9fa6dc4131 | ||
|
|
4930227743 | ||
|
|
fbfcce563d | ||
|
|
7f5ad3743b | ||
|
|
981020e72b | ||
|
|
7c1a705a07 | ||
|
|
3d53ae583f | ||
|
|
dc9f03cbd0 | ||
|
|
de7bca7ef8 | ||
|
|
f151f56a2e | ||
|
|
fe3d1713a4 | ||
|
|
2cad3be7a3 | ||
|
|
5262512eea | ||
|
|
fabba73b1e | ||
|
|
d291ec739b | ||
|
|
0dc0bbd4f3 | ||
|
|
984a029ce4 | ||
|
|
1cbc1f30a6 | ||
|
|
08fb39a1e4 | ||
|
|
d8a71ce195 | ||
|
|
13986c12bc | ||
|
|
cc64704a82 | ||
|
|
df2ad99260 | ||
|
|
fb1f277b9a | ||
|
|
0388161464 | ||
|
|
e989d5603f | ||
|
|
defaa0d008 | ||
|
|
e161ba80f2 | ||
|
|
034aaff56c | ||
|
|
b0fb52c5f4 | ||
|
|
a05f9c172f | ||
|
|
adde936d18 | ||
|
|
feda999eb3 | ||
|
|
8dae181c2f | ||
|
|
8cdac431a6 | ||
|
|
0ecf5118ba | ||
|
|
f21638a1e2 | ||
|
|
8dc16494a7 | ||
|
|
a8765b1dc0 | ||
|
|
d346b94b8a | ||
|
|
c4abe4f46a | ||
|
|
ad6a5eb4e1 | ||
|
|
c84834d666 | ||
|
|
334fe70d6c | ||
|
|
3b4fbaccc9 | ||
|
|
58401e0b6e | ||
|
|
3496f3a8ba | ||
|
|
441708ea12 | ||
|
|
ba8abb9031 | ||
|
|
2718a22f64 | ||
|
|
85fb4be37e | ||
|
|
f772c92eed | ||
|
|
cd58d39eb9 | ||
|
|
2d730a4618 | ||
|
|
da6d17531c | ||
|
|
37b9b182b1 | ||
|
|
eaa86060e2 | ||
|
|
5e128214fa | ||
|
|
9a7b967889 | ||
|
|
5e498e7442 | ||
|
|
25990ecd37 | ||
|
|
ead5a97871 | ||
|
|
a66495b2e0 | ||
|
|
f83172f9f9 | ||
|
|
80a957c1e3 | ||
|
|
e983169b35 | ||
|
|
b21d633c0c | ||
|
|
f538d028d5 | ||
|
|
4e15b7abc2 | ||
|
|
e80ea5eae2 | ||
|
|
6215050086 | ||
|
|
1fdb44ff42 | ||
|
|
1768a2f8b7 | ||
|
|
2f26ef0873 | ||
|
|
ac61fd7ba4 | ||
|
|
a886166489 | ||
|
|
2073a9f3e5 | ||
|
|
be12049a87 | ||
|
|
de7dfc2ea6 | ||
|
|
7337a467b9 | ||
|
|
8118b4a774 | ||
|
|
b295743330 | ||
|
|
4f8d7092e0 | ||
|
|
2701e57779 | ||
|
|
f9375d5c33 | ||
|
|
d04f049fa3 | ||
|
|
8b8e724761 | ||
|
|
45e8c57f77 | ||
|
|
d01b3301d0 | ||
|
|
a7a55c7617 | ||
|
|
0695c12420 | ||
|
|
4af533c010 | ||
|
|
6a28d2b81c | ||
|
|
54769a2ad3 | ||
|
|
87cece8379 | ||
|
|
fe3790cb9c | ||
|
|
39cb238065 | ||
|
|
2182149b7a | ||
|
|
006e0548c1 | ||
|
|
8257fbdbf3 | ||
|
|
f57224952a | ||
|
|
3c982cae64 | ||
|
|
3ffe63c02c | ||
|
|
7aa5d4a375 | ||
|
|
1d06dd630a | ||
|
|
f630fb6732 | ||
|
|
df3ea47a3c | ||
|
|
6ceb122ae8 | ||
|
|
ec92a0c458 | ||
|
|
60294c2514 | ||
|
|
94f72ea137 | ||
|
|
9b7295fd8f | ||
|
|
c93b49e714 | ||
|
|
a81b9a0f09 | ||
|
|
82d9d2a016 | ||
|
|
d529a7514a | ||
|
|
a5c91a6ed4 | ||
|
|
357000a0e7 | ||
|
|
80e26ba4af | ||
|
|
6310a15650 | ||
|
|
5909215967 | ||
|
|
f0eb1c59b1 | ||
|
|
22aa429059 | ||
|
|
3cc5f38da2 | ||
|
|
83985ba910 | ||
|
|
263d4bfc1e | ||
|
|
8c608cdce5 | ||
|
|
ceea495da1 | ||
|
|
a0af0a98cb | ||
|
|
9e99cfef61 | ||
|
|
b6e6733361 | ||
|
|
d3cf84680c | ||
|
|
8dc6fde588 | ||
|
|
1938c8239a | ||
|
|
bf43c61a05 | ||
|
|
1e3ddd612e | ||
|
|
bb5d82fce9 | ||
|
|
b2ec57776d | ||
|
|
7c092a8714 | ||
|
|
53350bbec0 | ||
|
|
c6502054e9 | ||
|
|
35204faa6b | ||
|
|
9e87a312ab | ||
|
|
e1911eef3a | ||
|
|
e0c11cfeed | ||
|
|
b9efd4fbf0 | ||
|
|
38ca4ceb52 | ||
|
|
bfe8a8aa18 | ||
|
|
430f060db2 | ||
|
|
62cffc51bb | ||
|
|
75004e9d3e | ||
|
|
efba9a636a | ||
|
|
e2161fa3af | ||
|
|
6d6e9f965b | ||
|
|
9307422e54 | ||
|
|
df5b763d33 | ||
|
|
90ff85b04d | ||
|
|
c1505f3513 | ||
|
|
1bd4a15d5c | ||
|
|
7a2ecf8435 | ||
|
|
3c7ff0ee19 | ||
|
|
d3073a8ebd | ||
|
|
59e9f36e25 | ||
|
|
7e21db1de1 | ||
|
|
1f451777b4 | ||
|
|
832442d092 | ||
|
|
7101757bff | ||
|
|
3090ed1523 | ||
|
|
1dd2b32a1f | ||
|
|
f75e37cf83 | ||
|
|
3fba6754c5 |
@@ -39,8 +39,8 @@ jobs:
|
||||
run: |
|
||||
REF=${RELEASE_TAG:-${GITHUB_REF}}
|
||||
TAG=${REF##*/}
|
||||
echo ::set-output name=ref::${REF}
|
||||
echo ::set-output name=tag::${TAG}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v2.0.0
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
@@ -69,8 +69,8 @@ jobs:
|
||||
run: |
|
||||
REF=${RELEASE_TAG:-${GITHUB_REF}}
|
||||
TAG=${REF##*/}
|
||||
echo ::set-output name=ref::${REF}
|
||||
echo ::set-output name=tag::${TAG}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v2.0.0
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
@@ -97,8 +97,8 @@ jobs:
|
||||
run: |
|
||||
REF=${RELEASE_TAG:-${GITHUB_REF}}
|
||||
TAG=${REF##*/}
|
||||
echo ::set-output name=ref::${REF}
|
||||
echo ::set-output name=tag::${TAG}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v2.0.0
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
@@ -143,8 +143,8 @@ jobs:
|
||||
run: |
|
||||
REF=${RELEASE_TAG:-${GITHUB_REF}}
|
||||
TAG=${REF##*/}
|
||||
echo ::set-output name=ref::${REF}
|
||||
echo ::set-output name=tag::${TAG}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v2.0.0
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
@@ -171,8 +171,8 @@ jobs:
|
||||
run: |
|
||||
REF=${RELEASE_TAG:-${GITHUB_REF}}
|
||||
TAG=${REF##*/}
|
||||
echo ::set-output name=ref::${REF}
|
||||
echo ::set-output name=tag::${TAG}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
- uses: actions/checkout@v2.0.0
|
||||
with:
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ To build Filament for Android you must also install the following:
|
||||
|
||||
- Android Studio Arctic Fox or more recent
|
||||
- Android SDK
|
||||
- Android NDK "side-by-side" 23.1 or higher
|
||||
- Android NDK 25.1 or higher
|
||||
|
||||
### Environment variables
|
||||
|
||||
|
||||
+16
-12
@@ -35,16 +35,16 @@ set(FILAMENT_NDK_VERSION "" CACHE STRING
|
||||
"Android NDK version or version prefix to be used when building for Android."
|
||||
)
|
||||
|
||||
set(FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB "2" CACHE STRING
|
||||
"Per render pass arena size. Must be roughly 1 MB larger than FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB, default 2."
|
||||
set(FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB "3" CACHE STRING
|
||||
"Per render pass arena size. Must be roughly 1 MB larger than FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB, default 3."
|
||||
)
|
||||
|
||||
set(FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB "1" CACHE STRING
|
||||
"Size of the high-level draw commands buffer. Rule of thumb, 1 MB less than FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB, default 1."
|
||||
set(FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB "2" CACHE STRING
|
||||
"Size of the high-level draw commands buffer. Rule of thumb, 1 MB less than FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB, default 2."
|
||||
)
|
||||
|
||||
set(FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB "1" CACHE STRING
|
||||
"Size of the command-stream buffer. As a rule of thumb use the same value as FILAMENT_PER_FRRAME_COMMANDS_SIZE_IN_MB, default 1."
|
||||
set(FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB "2" CACHE STRING
|
||||
"Size of the command-stream buffer. As a rule of thumb use the same value as FILAMENT_PER_FRRAME_COMMANDS_SIZE_IN_MB, default 2."
|
||||
)
|
||||
|
||||
set(FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB "4" CACHE STRING
|
||||
@@ -337,19 +337,23 @@ endif()
|
||||
# ==================================================================================================
|
||||
# Release compiler flags
|
||||
# ==================================================================================================
|
||||
if (NOT MSVC)
|
||||
if (NOT MSVC AND NOT IOS)
|
||||
# Omitting stack frame pointers prevents the generation of readable stack traces in crash reports on iOS
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer")
|
||||
|
||||
# These aren't compatible with -fembed-bitcode (and seem to have no effect on Apple platforms anyway)
|
||||
if (NOT IOS)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffunction-sections -fdata-sections")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffunction-sections -fdata-sections")
|
||||
endif()
|
||||
|
||||
# On Android RELEASE builds, we disable exceptions and RTTI to save some space (about 75 KiB
|
||||
# saved by -fno-exception and 10 KiB saved by -fno-rtti).
|
||||
if (ANDROID OR IOS OR WEBGL)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-exceptions -fno-rtti")
|
||||
|
||||
if (ANDROID OR WEBGL)
|
||||
# Omitting unwind info prevents the generation of readable stack traces in crash reports on iOS
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-unwind-tables -fno-asynchronous-unwind-tables")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# With WebGL, we disable RTTI even for debug builds because we pass emscripten::val back and forth
|
||||
@@ -666,7 +670,7 @@ add_subdirectory(${EXTERNAL}/imgui/tnt)
|
||||
add_subdirectory(${EXTERNAL}/robin-map/tnt)
|
||||
add_subdirectory(${EXTERNAL}/smol-v/tnt)
|
||||
add_subdirectory(${EXTERNAL}/benchmark/tnt)
|
||||
add_subdirectory(${EXTERNAL}/meshoptimizer)
|
||||
add_subdirectory(${EXTERNAL}/meshoptimizer/tnt)
|
||||
add_subdirectory(${EXTERNAL}/cgltf/tnt)
|
||||
add_subdirectory(${EXTERNAL}/draco/tnt)
|
||||
add_subdirectory(${EXTERNAL}/jsmn/tnt)
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.25.5'
|
||||
implementation 'com.google.android.filament:filament-android:1.28.2'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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:
|
||||
|
||||
```
|
||||
pod 'Filament', '~> 1.25.5'
|
||||
pod 'Filament', '~> 1.28.2'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
@@ -179,6 +179,7 @@ steps:
|
||||
- [x] KHR_mesh_quantization
|
||||
- [x] KHR_texture_basisu
|
||||
- [x] KHR_texture_transform
|
||||
- [x] EXT_meshopt_compression
|
||||
|
||||
|
||||
## Rendering with Filament
|
||||
|
||||
@@ -5,6 +5,84 @@ A new header is inserted each time a *tag* is created.
|
||||
|
||||
## main branch
|
||||
|
||||
- backend: add support for GGP platform
|
||||
- gltfio: calculate primitive's AABB correctly.
|
||||
- gltfio: fix glTF breaking issue
|
||||
- gltfio: recompute bounding boxes with morph targets
|
||||
- engine: primitives with `CullingMode::FRONT_AND_BACK` are now skipped.
|
||||
- engine: add missing getters on `MaterialInstance`
|
||||
|
||||
## v1.28.2
|
||||
|
||||
- gltfio: support EXT_meshopt_compression
|
||||
- release packaging: fixed location of default IBL file
|
||||
|
||||
## v1.28.1
|
||||
|
||||
- gltfio: fix reloading crash in ubershader mode
|
||||
- Vulkan: improve performance in the readPixels path
|
||||
- engine: raise the spot shadows limit to 64, from 14.
|
||||
- engine: add experimental support for point light shadows.
|
||||
- gltfio: fix ubershader issues with assignment of dummy textures
|
||||
- gltfio: material instances and variants are now accessed via `FilamentInstance` [⚠️ **API Change**]
|
||||
- gltfio: the animator can now only be accessed via `FilamentInstance` [⚠️ **API Change**]
|
||||
- engine: fix "stable" shadows and make the default cascade splits logarithmic.
|
||||
- engine: Add new quality options to EVSM shadows + rendering fixes
|
||||
|
||||
## v1.28.0
|
||||
|
||||
- engine: LiSPSM is now a user settable option
|
||||
- engine: get the morph target buffer to the given primitive
|
||||
- Java: Fix TransformManager.getChildren()
|
||||
- Metal: newer devices are no longer limited to 16 samplers per Material.
|
||||
- gltfio: fix interpretation of occlusion strength
|
||||
- engine: minsdk is now 21 instead of 19. This allows the use of OpenGL ES 3.1
|
||||
- Vulkan: fix black screen regression
|
||||
|
||||
## v1.27.2
|
||||
|
||||
- gltfio: punctual lights are now duplicated when adding new asset instances
|
||||
- gltfio: FilamentInstance getAsset method now returns an immutable asset
|
||||
- gltfio: allow zero-instance assets
|
||||
- gltfio: fix regression with meshes that have no material
|
||||
- gltfio: fix regression with recomputeBoundingBoxes()
|
||||
- filamesh / matinfo: fix minor ASAN issues
|
||||
- engine: Added `Engine::resetBackendState()`, available only in WebGL builds
|
||||
|
||||
## v1.27.1
|
||||
|
||||
- Java: add methods for TransformManager.getChildCount(), TransformManager.getChildren() and Scene.hasEntity()
|
||||
- engine: Fix stencil buffer writes with OpenGL backend.
|
||||
- gltfio: add new virtual method to MaterialProvider that all plugins must implement
|
||||
- gltfio: add an assert for inconsistent sRGB flags among usages of a particular texture
|
||||
- engine: improve scissor documentation
|
||||
- backend: scissor is no longer clipped to the viewport (done on filament side)
|
||||
- samples: add debug overdraw visualization to gltf_viewer
|
||||
|
||||
## v1.27.0
|
||||
|
||||
- WebGL: reduce max instance count to work around Chrome issues [⚠️ **Recompile Materials**]
|
||||
- engine: rework material/shader sampler binding code [⚠️ **Recompile Materials**]
|
||||
- gltfio: move the API for `recomputeBoundingBoxes` [⚠️ **API Change**]
|
||||
- engine: add support for specialization constants [⚠️ **Recompile Materials**]
|
||||
- gltfio: fix spotlight regression
|
||||
- gltfio: clear the MaterialInstance cache when creating new instances
|
||||
|
||||
## v1.26.0
|
||||
|
||||
- engine: new feature level APIs, see `Engine::getSupportedFeatureLevel()`
|
||||
- engine: add new stencil API to `View` and stencil state APIs to `MaterialInstance` [**NEW API**].
|
||||
- engine: Fix guard bands and TAA with `vertexDomain:Device` [⚠️ **Recompile Materials**]
|
||||
- engine: `clipSpaceTransform` is now only available with `vertexDomain:Device` [⚠️ **API Change**]
|
||||
- gltfio: add unified `AssetLoader::createAsset()` method [⚠️ **API Change**]
|
||||
- gltfio: all assets are now "instanced" [⚠️ **API Change**]
|
||||
|
||||
## v1.25.6
|
||||
|
||||
- engine: Add `CONFIG_MINSPEC_UBO_SIZE` as a nicer way to allow exceeding the ES3.0 minspec.
|
||||
- gltfio: minor efficiency improvement for Android and WebGL builds.
|
||||
- gltfio: add support for concurrent texture downloading and decoding.
|
||||
|
||||
## v1.25.5
|
||||
|
||||
- WebGL: upgraded the JS bindings to work with emsdk 3.1.15
|
||||
|
||||
+21
-21
@@ -29,15 +29,12 @@
|
||||
|
||||
// Publishing to Maven Central:
|
||||
// - Build and upload artifacts with ./gradlew publish
|
||||
// - Close and release staging repo on Nexus with ./gradlew closeAndReleaseRepository
|
||||
// - Close and release staging repo on Nexus with ./gradlew closeAndReleaseStagingRepository
|
||||
//
|
||||
// The following is needed in ~/gradle/gradle.properties:
|
||||
//
|
||||
// SONATYPE_NEXUS_USERNAME=nexus_user
|
||||
// SONATYPE_NEXUS_PASSWORD=nexus_password
|
||||
//
|
||||
// nexusUsername=nexus_user
|
||||
// nexusPassword=nexus_password
|
||||
// sonatypeUsername=nexus_user
|
||||
// sonatypePassword=nexus_password
|
||||
//
|
||||
// signing.keyId=pgp_key_id
|
||||
// signing.password=pgp_key_password
|
||||
@@ -47,7 +44,7 @@
|
||||
buildscript {
|
||||
def path = providers
|
||||
.gradleProperty("com.google.android.filament.dist-dir")
|
||||
.forUseAtConfigurationTime().get()
|
||||
.get()
|
||||
|
||||
def directory = objects.fileProperty().fileValue(new File(path)).getAsFile().get()
|
||||
def filamentPath = directory.absolutePath
|
||||
@@ -59,18 +56,15 @@ buildscript {
|
||||
// Warning: changing this property does not work well with incremental builds.
|
||||
def excludeVulkan = providers
|
||||
.gradleProperty("com.google.android.filament.exclude-vulkan")
|
||||
.forUseAtConfigurationTime()
|
||||
.isPresent()
|
||||
|
||||
def matdbg = providers
|
||||
.gradleProperty("com.google.android.filament.matdbg")
|
||||
.forUseAtConfigurationTime()
|
||||
.isPresent()
|
||||
|
||||
def abis = ["arm64-v8a", "armeabi-v7a", "x86_64", "x86"]
|
||||
def newAbis = providers
|
||||
.gradleProperty("com.google.android.filament.abis")
|
||||
.forUseAtConfigurationTime()
|
||||
.get()
|
||||
.split(',')
|
||||
if (!newAbis.contains("all")) {
|
||||
@@ -79,18 +73,20 @@ buildscript {
|
||||
|
||||
ext.versions = [
|
||||
'minSdk': 19,
|
||||
'targetSdk': 31,
|
||||
'compileSdk': 31,
|
||||
'targetSdk': 33,
|
||||
'compileSdk': 33,
|
||||
'kotlin': '1.7.10',
|
||||
'kotlin_coroutines': '1.6.1',
|
||||
'buildTools': '33.0.0',
|
||||
'ndk': '25.0.8775105'
|
||||
'ndk': '25.1.8937393',
|
||||
'androidx_core': '1.9.0',
|
||||
'androidx_annotations': '1.3.0'
|
||||
]
|
||||
|
||||
ext.deps = [
|
||||
'androidx': [
|
||||
'annotations': "androidx.annotation:annotation:1.3.0",
|
||||
'core': "androidx.core:core:1.7.0",
|
||||
'annotations': "androidx.annotation:annotation:${versions.androidx_annotations}",
|
||||
'core': "androidx.core:core:${versions.androidx_core}",
|
||||
],
|
||||
'kotlin': "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}",
|
||||
'coroutines': [
|
||||
@@ -101,7 +97,7 @@ buildscript {
|
||||
|
||||
dependencies {
|
||||
// NOTE: See TODO in gradle.properties once we move to Gradle 7.4
|
||||
classpath 'com.android.tools.build:gradle:7.2.1'
|
||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
|
||||
}
|
||||
|
||||
@@ -148,14 +144,18 @@ buildscript {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'io.codearte.nexus-staging' version '0.30.0'
|
||||
id "io.github.gradle-nexus.publish-plugin" version "1.1.0"
|
||||
}
|
||||
|
||||
// Nexus Staging configuration
|
||||
// See https://github.com/Codearte/gradle-nexus-staging-plugin/
|
||||
nexusStaging {
|
||||
// See https://github.com/gradle-nexus/publish-plugin
|
||||
// Publish to https://oss.sonatype.org/ (not s01)
|
||||
nexusPublishing {
|
||||
packageGroup = 'com.google.android'
|
||||
stagingProfileId = '9a75a224a4f17b'
|
||||
repositories {
|
||||
sonatype {
|
||||
stagingProfileId = '9a75a224a4f17b'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
||||
@@ -126,8 +126,8 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderUniform
|
||||
JNIEnv* env, jclass, jlong nativeBuilder, jint uniformType, jint precision, jstring name_) {
|
||||
auto builder = (MaterialBuilder*) nativeBuilder;
|
||||
const char* name = env->GetStringUTFChars(name_, nullptr);
|
||||
builder->parameter((MaterialBuilder::UniformType) uniformType,
|
||||
(MaterialBuilder::ParameterPrecision) precision, name);
|
||||
builder->parameter(name, (MaterialBuilder::UniformType) uniformType,
|
||||
(MaterialBuilder::ParameterPrecision) precision);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
@@ -137,8 +137,8 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderUniform
|
||||
jstring name_) {
|
||||
auto builder = (MaterialBuilder*) nativeBuilder;
|
||||
const char* name = env->GetStringUTFChars(name_, nullptr);
|
||||
builder->parameter((MaterialBuilder::UniformType) uniformType, (size_t) size,
|
||||
(MaterialBuilder::ParameterPrecision) precision, name);
|
||||
builder->parameter(name, (size_t) size, (MaterialBuilder::UniformType) uniformType,
|
||||
(MaterialBuilder::ParameterPrecision) precision);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
@@ -148,9 +148,8 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderSampler
|
||||
jint precision, jstring name_) {
|
||||
auto builder = (MaterialBuilder*) nativeBuilder;
|
||||
const char* name = env->GetStringUTFChars(name_, nullptr);
|
||||
builder->parameter((MaterialBuilder::SamplerType) samplerType,
|
||||
(MaterialBuilder::SamplerFormat) format, (MaterialBuilder::ParameterPrecision) precision,
|
||||
name);
|
||||
builder->parameter(name, (MaterialBuilder::SamplerType) samplerType,
|
||||
(MaterialBuilder::SamplerFormat) format, (MaterialBuilder::ParameterPrecision) precision);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
|
||||
@@ -328,3 +328,24 @@ Java_com_google_android_filament_Engine_nIsAutomaticInstancingEnabled(JNIEnv*, j
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return (jboolean)engine->isAutomaticInstancingEnabled();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Engine_nGetSupportedFeatureLevel(JNIEnv *, jclass,
|
||||
jlong nativeEngine) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return (jint)engine->getSupportedFeatureLevel();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Engine_nSetActiveFeatureLevel(JNIEnv *, jclass,
|
||||
jlong nativeEngine, jint ordinal) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return (jint)engine->setActiveFeatureLevel((Engine::FeatureLevel)ordinal);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Engine_nGetActiveFeatureLevel(JNIEnv *, jclass,
|
||||
jlong nativeEngine) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return (jint)engine->getActiveFeatureLevel();
|
||||
}
|
||||
@@ -76,10 +76,10 @@ extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env, jclass,
|
||||
jlong nativeBuilder, jint mapSize, jint cascades, jfloatArray splitPositions,
|
||||
jfloat constantBias, jfloat normalBias, jfloat shadowFar, jfloat shadowNearHint,
|
||||
jfloat shadowFarHint, jboolean stable,
|
||||
jfloat shadowFarHint, jboolean stable, jboolean lispsm,
|
||||
jfloat polygonOffsetConstant, jfloat polygonOffsetSlope,
|
||||
jboolean screenSpaceContactShadows, jint stepCount,
|
||||
jfloat maxShadowDistance, jint vsmMsaaSamples, jfloat blurWidth, jfloat shadowBulbRadius) {
|
||||
jfloat maxShadowDistance, jint vsmMsaaSamples, jboolean elvsm, jfloat blurWidth, jfloat shadowBulbRadius) {
|
||||
LightManager::Builder *builder = (LightManager::Builder *) nativeBuilder;
|
||||
LightManager::ShadowOptions shadowOptions {
|
||||
.mapSize = (uint32_t)mapSize,
|
||||
@@ -90,6 +90,7 @@ Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env,
|
||||
.shadowNearHint = shadowNearHint,
|
||||
.shadowFarHint = shadowFarHint,
|
||||
.stable = (bool)stable,
|
||||
.lispsm = (bool)lispsm,
|
||||
.polygonOffsetConstant = polygonOffsetConstant,
|
||||
.polygonOffsetSlope = polygonOffsetConstant,
|
||||
.screenSpaceContactShadows = (bool)screenSpaceContactShadows,
|
||||
@@ -97,6 +98,7 @@ Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env,
|
||||
.maxShadowDistance = maxShadowDistance,
|
||||
.vsm = {
|
||||
.msaaSamples = (uint8_t) vsmMsaaSamples,
|
||||
.elvsm = (bool)elvsm,
|
||||
.blurWidth = blurWidth
|
||||
},
|
||||
.shadowBulbRadius = shadowBulbRadius
|
||||
|
||||
@@ -341,6 +341,14 @@ Java_com_google_android_filament_MaterialInstance_nSetDepthWrite(JNIEnv*,
|
||||
instance->setDepthWrite(enable);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetStencilWrite(JNIEnv*, jclass,
|
||||
jlong nativeMaterialInstance, jboolean enable) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
instance->setStencilWrite(enable);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetDepthCulling(JNIEnv*,
|
||||
@@ -349,6 +357,70 @@ Java_com_google_android_filament_MaterialInstance_nSetDepthCulling(JNIEnv*,
|
||||
instance->setDepthCulling(enable);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetStencilCompareFunction(JNIEnv*, jclass,
|
||||
jlong nativeMaterialInstance, jlong function, jlong face) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
instance->setStencilCompareFunction(
|
||||
static_cast<MaterialInstance::StencilCompareFunc>(function),
|
||||
static_cast<MaterialInstance::StencilFace>(face));
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetStencilOpStencilFail(JNIEnv*, jclass,
|
||||
jlong nativeMaterialInstance, jlong op, jlong face) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
instance->setStencilOpStencilFail(
|
||||
static_cast<MaterialInstance::StencilOperation>(op),
|
||||
static_cast<MaterialInstance::StencilFace>(face));
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetStencilOpDepthFail(JNIEnv*, jclass,
|
||||
jlong nativeMaterialInstance, jlong op, jlong face) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
instance->setStencilOpDepthFail(
|
||||
static_cast<MaterialInstance::StencilOperation>(op),
|
||||
static_cast<MaterialInstance::StencilFace>(face));
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetStencilOpDepthStencilPass(JNIEnv*, jclass,
|
||||
jlong nativeMaterialInstance, jlong op, jlong face) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
instance->setStencilOpDepthStencilPass(
|
||||
static_cast<MaterialInstance::StencilOperation>(op),
|
||||
static_cast<MaterialInstance::StencilFace>(face));
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetStencilReferenceValue(JNIEnv*, jclass,
|
||||
jlong nativeMaterialInstance, jint value, jlong face) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
instance->setStencilReferenceValue(value, static_cast<MaterialInstance::StencilFace>(face));
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetStencilReadMask(JNIEnv*, jclass,
|
||||
jlong nativeMaterialInstance, jint readMask, jlong face) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
instance->setStencilReadMask(readMask, static_cast<MaterialInstance::StencilFace>(face));
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetStencilWriteMask(JNIEnv*, jclass,
|
||||
jlong nativeMaterialInstance, jint writeMask, jlong face) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
instance->setStencilWriteMask(writeMask, static_cast<MaterialInstance::StencilFace>(face));
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetName(JNIEnv* env, jclass,
|
||||
@@ -380,3 +452,84 @@ Java_com_google_android_filament_MaterialInstance_nDuplicate(JNIEnv* env, jclass
|
||||
}
|
||||
return (jlong)mi;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetMaskThreshold(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nGetMaskThreshold()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->getMaskThreshold();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetSpecularAntiAliasingVariance(JNIEnv* env,
|
||||
jclass clazz, jlong nativeMaterialInstance) {
|
||||
// TODO: implement nGetSpecularAntiAliasingVariance()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->getSpecularAntiAliasingVariance();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetSpecularAntiAliasingThreshold(JNIEnv* env,
|
||||
jclass clazz, jlong nativeMaterialInstance) {
|
||||
// TODO: implement nGetSpecularAntiAliasingThreshold()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->getSpecularAntiAliasingThreshold();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsDoubleSided(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsDoubleSided()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isDoubleSided();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetCullingMode(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nGetCullingMode()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return (jint)instance->getCullingMode();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsColorWriteEnabled(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsColorWriteEnabled()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isColorWriteEnabled();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsDepthWriteEnabled(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsDepthWriteEnabled()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isDepthWriteEnabled();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsStencilWriteEnabled(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsStencilWriteEnabled()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isStencilWriteEnabled();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsDepthCullingEnabled(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsDepthCullingEnabled()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isDepthCullingEnabled();
|
||||
}
|
||||
|
||||
@@ -83,3 +83,11 @@ Java_com_google_android_filament_Scene_nGetLightCount(JNIEnv *env, jclass type,
|
||||
Scene* scene = (Scene*) nativeScene;
|
||||
return (jint) scene->getLightCount();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Scene_nHasEntity(JNIEnv *env, jclass type, jlong nativeScene,
|
||||
jint entityId) {
|
||||
Scene* scene = (Scene*) nativeScene;
|
||||
Entity entity = Entity::import(entityId);
|
||||
return (jboolean) scene->hasEntity(entity);
|
||||
}
|
||||
|
||||
@@ -110,6 +110,26 @@ Java_com_google_android_filament_TransformManager_nGetParent(JNIEnv*, jclass,
|
||||
return tm->getParent((TransformManager::Instance) i).getId();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_TransformManager_nGetChildCount(JNIEnv*, jclass,
|
||||
jlong nativeTransformManager, jint i) {
|
||||
TransformManager* tm = (TransformManager*) nativeTransformManager;
|
||||
return tm->getChildCount((TransformManager::Instance) i);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_TransformManager_nGetChildren(JNIEnv* env,
|
||||
jclass, jlong nativeTransformManager, jint i,
|
||||
jintArray outEntities_, jint count) {
|
||||
TransformManager* tm = (TransformManager*) nativeTransformManager;
|
||||
jint* entities = env->GetIntArrayElements(outEntities_, nullptr);
|
||||
// This is very very gross, we just pretend Entity is just like an jint
|
||||
// (which it is), but still.
|
||||
tm->getChildren((TransformManager::Instance) i,
|
||||
reinterpret_cast<Entity *>(entities), (size_t) count);
|
||||
env->ReleaseIntArrayElements(outEntities_, entities, 0);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_TransformManager_nSetTransform(JNIEnv* env,
|
||||
jclass, jlong nativeTransformManager, jint i,
|
||||
|
||||
@@ -149,12 +149,13 @@ Java_com_google_android_filament_View_nSetShadowType(JNIEnv*, jclass, jlong nati
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_View_nSetVsmShadowOptions(JNIEnv*, jclass, jlong nativeView,
|
||||
jint anisotropy, jboolean mipmapping, jfloat minVarianceScale,
|
||||
jint anisotropy, jboolean mipmapping, jboolean highPrecision, jfloat minVarianceScale,
|
||||
jfloat lightBleedReduction) {
|
||||
View* view = (View*) nativeView;
|
||||
View::VsmShadowOptions options;
|
||||
options.anisotropy = (uint8_t)anisotropy;
|
||||
options.mipmapping = (bool)mipmapping;
|
||||
options.highPrecision = (bool)highPrecision;
|
||||
options.minVarianceScale = minVarianceScale;
|
||||
options.lightBleedReduction = lightBleedReduction;
|
||||
view->setVsmShadowOptions(options);
|
||||
@@ -462,6 +463,21 @@ Java_com_google_android_filament_View_nPick(JNIEnv* env, jclass,
|
||||
}, callback->getHandler());
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_View_nSetStencilBufferEnabled(JNIEnv *, jclass, jlong nativeView,
|
||||
jboolean enabled) {
|
||||
View* view = (View*) nativeView;
|
||||
view->setStencilBufferEnabled(enabled);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_View_nIsStencilBufferEnabled(JNIEnv *, jclass, jlong nativeView) {
|
||||
View* view = (View*) nativeView;
|
||||
return view->isStencilBufferEnabled();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_View_nSetGuardBandOptions(JNIEnv *, jclass,
|
||||
|
||||
@@ -47,7 +47,7 @@ import com.google.android.filament.proguard.UsedByReflection;
|
||||
* <pre>
|
||||
* import com.google.android.filament.*
|
||||
*
|
||||
* Engin engine = Engine.create();
|
||||
* Engine engine = Engine.create();
|
||||
* SwapChain swapChain = engine.createSwapChain(nativeWindow);
|
||||
* Renderer renderer = engine.createRenderer();
|
||||
* Scene scene = engine.createScene();
|
||||
@@ -107,6 +107,7 @@ import com.google.android.filament.proguard.UsedByReflection;
|
||||
*/
|
||||
public class Engine {
|
||||
private static final Backend[] sBackendValues = Backend.values();
|
||||
private static final FeatureLevel[] sFeatureLevelValues = FeatureLevel.values();
|
||||
|
||||
private long mNativeObject;
|
||||
|
||||
@@ -141,6 +142,18 @@ public class Engine {
|
||||
NOOP,
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the backend's feature levels.
|
||||
*/
|
||||
public enum FeatureLevel {
|
||||
/** Reserved, don't use */
|
||||
FEATURE_LEVEL_0,
|
||||
/** OpenGL ES 3.0 features (default) */
|
||||
FEATURE_LEVEL_1,
|
||||
/** OpenGL ES 3.1 features + 31 textures units + cubemap arrays */
|
||||
FEATURE_LEVEL_2
|
||||
};
|
||||
|
||||
private Engine(long nativeEngine) {
|
||||
mNativeObject = nativeEngine;
|
||||
mTransformManager = new TransformManager(nGetTransformManager(nativeEngine));
|
||||
@@ -269,6 +282,50 @@ public class Engine {
|
||||
getTransformManager().setAccurateTranslationsEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the feature level supported by the selected backend.
|
||||
*
|
||||
* A specific feature level needs to be set before the corresponding features can be used.
|
||||
*
|
||||
* @return FeatureLevel supported the selected backend.
|
||||
* @see #setActiveFeatureLevel
|
||||
*/
|
||||
@NonNull
|
||||
public FeatureLevel getSupportedFeatureLevel() {
|
||||
return sFeatureLevelValues[(int) nGetSupportedFeatureLevel(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate all features of a given feature level. By default FeatureLevel::FEATURE_LEVEL_1 is
|
||||
* active. The selected feature level must not be higher than the value returned by
|
||||
* getActiveFeatureLevel() and it's not possible lower the active feature level.
|
||||
*
|
||||
* @param featureLevel the feature level to activate. If featureLevel is lower than
|
||||
* getActiveFeatureLevel(), the current (higher) feature level is kept.
|
||||
* If featureLevel is higher than getSupportedFeatureLevel(), an exception
|
||||
* is thrown, or the program is terminated if exceptions are disabled.
|
||||
*
|
||||
* @return the active feature level.
|
||||
*
|
||||
* @see #getSupportedFeatureLevel
|
||||
* @see #getActiveFeatureLevel
|
||||
*/
|
||||
@NonNull
|
||||
public FeatureLevel setActiveFeatureLevel(@NonNull FeatureLevel featureLevel) {
|
||||
return sFeatureLevelValues[(int) nSetActiveFeatureLevel(getNativeObject(), featureLevel.ordinal())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently active feature level.
|
||||
* @return currently active feature level
|
||||
* @see #getSupportedFeatureLevel
|
||||
* @see #setActiveFeatureLevel
|
||||
*/
|
||||
@NonNull
|
||||
public FeatureLevel getActiveFeatureLevel() {
|
||||
return sFeatureLevelValues[(int) nGetActiveFeatureLevel(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables automatic instancing of render primitives. Instancing of render primitive
|
||||
* can greatly reduce CPU overhead but requires the instanced primitives to be identical
|
||||
@@ -289,7 +346,7 @@ public class Engine {
|
||||
|
||||
/**
|
||||
* @return true if automatic instancing is enabled, false otherwise.
|
||||
* @see setAutomaticInstancingEnabled
|
||||
* @see #setAutomaticInstancingEnabled
|
||||
*/
|
||||
public boolean isAutomaticInstancingEnabled() {
|
||||
return nIsAutomaticInstancingEnabled(getNativeObject());
|
||||
@@ -760,4 +817,7 @@ public class Engine {
|
||||
private static native long nGetEntityManager(long nativeEngine);
|
||||
private static native void nSetAutomaticInstancingEnabled(long nativeEngine, boolean enable);
|
||||
private static native boolean nIsAutomaticInstancingEnabled(long nativeEngine);
|
||||
private static native int nGetSupportedFeatureLevel(long nativeEngine);
|
||||
private static native int nSetActiveFeatureLevel(long nativeEngine, int ordinal);
|
||||
private static native int nGetActiveFeatureLevel(long nativeEngine);
|
||||
}
|
||||
|
||||
+36
-9
@@ -240,7 +240,7 @@ public class LightManager {
|
||||
*/
|
||||
@NonNull
|
||||
@Size(min = 3)
|
||||
public float[] cascadeSplitPositions = { 0.25f, 0.50f, 0.75f };
|
||||
public float[] cascadeSplitPositions = { 0.125f, 0.25f, 0.50f };
|
||||
|
||||
/** Constant bias in world units (e.g. meters) by which shadows are moved away from the
|
||||
* light. 1mm by default.
|
||||
@@ -280,9 +280,25 @@ public class LightManager {
|
||||
* Controls whether the shadow map should be optimized for resolution or stability.
|
||||
* When set to true, all resolution enhancing features that can affect stability are
|
||||
* disabling, resulting in significantly lower resolution shadows, albeit stable ones.
|
||||
*
|
||||
* Setting this flag to true always disables LiSPSM (see below).
|
||||
*/
|
||||
public boolean stable = false;
|
||||
|
||||
/**
|
||||
* LiSPSM, or light-space perspective shadow-mapping is a technique allowing to better
|
||||
* optimize the use of the shadow-map texture. When enabled the effective resolution of
|
||||
* shadows is greatly improved and yields result similar to using cascades without the
|
||||
* extra cost. LiSPSM comes with some drawbacks however, in particular it is incompatible
|
||||
* with blurring because it effectively affects the blur kernel size.
|
||||
*
|
||||
* Blurring is only an issue when using ShadowType.VSM with a large blur or with
|
||||
* ShadowType.PCSS however.
|
||||
*
|
||||
* If these blurring artifacts become problematic, this flag can be used to disable LiSPSM.
|
||||
*/
|
||||
public boolean lispsm = false;
|
||||
|
||||
/**
|
||||
* Constant bias in depth-resolution units by which shadows are moved away from the
|
||||
* light. The default value of 0.5 is used to round depth values up.
|
||||
@@ -346,6 +362,15 @@ public class LightManager {
|
||||
@IntRange(from = 1)
|
||||
public int vsmMsaaSamples = 1;
|
||||
|
||||
|
||||
/**
|
||||
* When elvsm is set to true, "Exponential Layered VSM without Layers" are used. It is
|
||||
* an improvement to the default EVSM which suffers important light leaks. Enabling
|
||||
* ELVSM for a single shadowmap doubles the memory usage of all shadow maps.
|
||||
* ELVSM is mostly useful when large blurs are used.
|
||||
*/
|
||||
public boolean elvsm = false;
|
||||
|
||||
/**
|
||||
* Blur width for the VSM blur. Zero do disable.
|
||||
* The maximum value is 125.
|
||||
@@ -470,11 +495,6 @@ public class LightManager {
|
||||
/**
|
||||
* Whether this Light casts shadows (disabled by default)
|
||||
*
|
||||
* <p>
|
||||
* <b>warning:</b>
|
||||
* {@link Type#POINT} lights cannot cast shadows.
|
||||
* </p>
|
||||
*
|
||||
* @param enable Enables or disables casting shadows from this Light.
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
@@ -496,11 +516,11 @@ public class LightManager {
|
||||
nBuilderShadowOptions(mNativeBuilder,
|
||||
options.mapSize, options.shadowCascades, options.cascadeSplitPositions,
|
||||
options.constantBias, options.normalBias, options.shadowFar, options.shadowNearHint,
|
||||
options.shadowFarHint, options.stable,
|
||||
options.shadowFarHint, options.stable, options.lispsm,
|
||||
options.polygonOffsetConstant, options.polygonOffsetSlope,
|
||||
options.screenSpaceContactShadows,
|
||||
options.stepCount, options.maxShadowDistance, options.vsmMsaaSamples,
|
||||
options.blurWidth, options.shadowBulbRadius);
|
||||
options.elvsm, options.blurWidth, options.shadowBulbRadius);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1158,7 +1178,14 @@ public class LightManager {
|
||||
private static native void nDestroyBuilder(long nativeBuilder);
|
||||
private static native boolean nBuilderBuild(long nativeBuilder, long nativeEngine, int entity);
|
||||
private static native void nBuilderCastShadows(long nativeBuilder, boolean enable);
|
||||
private static native void nBuilderShadowOptions(long nativeBuilder, int mapSize, int cascades, float[] splitPositions, float constantBias, float normalBias, float shadowFar, float shadowNearHint, float shadowFarhint, boolean stable, float polygonOffsetConstant, float polygonOffsetSlope, boolean screenSpaceContactShadows, int stepCount, float maxShadowDistance, int vsmMsaaSamples, float blurWidth, float shadowBulbRadius);
|
||||
private static native void nBuilderShadowOptions(long nativeBuilder, int mapSize,
|
||||
int cascades, float[] splitPositions,
|
||||
float constantBias, float normalBias,
|
||||
float shadowFar, float shadowNearHint, float shadowFarhint,
|
||||
boolean stable, boolean lispsm,
|
||||
float polygonOffsetConstant, float polygonOffsetSlope,
|
||||
boolean screenSpaceContactShadows, int stepCount, float maxShadowDistance,
|
||||
int vsmMsaaSamples, boolean elvsm, float blurWidth, float shadowBulbRadius);
|
||||
private static native void nBuilderCastLight(long nativeBuilder, boolean enabled);
|
||||
private static native void nBuilderPosition(long nativeBuilder, float x, float y, float z);
|
||||
private static native void nBuilderDirection(long nativeBuilder, float x, float y, float z);
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.util.Set;
|
||||
*
|
||||
* @see <a href="https://google.github.io/filament/Materials.html">Filament Materials Guide</a>
|
||||
*/
|
||||
@UsedByNative("AssetLoader.cpp")
|
||||
public class Material {
|
||||
static final class EnumCache {
|
||||
private EnumCache() { }
|
||||
|
||||
+382
-5
@@ -20,7 +20,11 @@ import androidx.annotation.IntRange;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Size;
|
||||
|
||||
import com.google.android.filament.proguard.UsedByNative;
|
||||
|
||||
@UsedByNative("AssetLoader.cpp")
|
||||
public class MaterialInstance {
|
||||
private static final Material.CullingMode[] sCullingModeValues = Material.CullingMode.values();
|
||||
private Material mMaterial;
|
||||
private String mName;
|
||||
private long mNativeObject;
|
||||
@@ -49,6 +53,54 @@ public class MaterialInstance {
|
||||
MAT4
|
||||
}
|
||||
|
||||
/**
|
||||
* Operations that control how the stencil buffer is updated.
|
||||
*/
|
||||
public enum StencilOperation {
|
||||
/**
|
||||
* Keeps the current value.
|
||||
*/
|
||||
KEEP,
|
||||
/**
|
||||
* Sets the value to 0.
|
||||
*/
|
||||
ZERO,
|
||||
/**
|
||||
* Sets the value to the stencil reference value.
|
||||
*/
|
||||
REPLACE,
|
||||
/**
|
||||
* Increments the current value. Clamps to the maximum representable unsigned value.
|
||||
*/
|
||||
INCR_CLAMP,
|
||||
/**
|
||||
* Increments the current value. Wraps value to zero when incrementing the maximum
|
||||
* representable unsigned value.
|
||||
*/
|
||||
INCR_WRAP,
|
||||
/**
|
||||
* Decrements the current value. Clamps to 0.
|
||||
*/
|
||||
DECR_CLAMP,
|
||||
/**
|
||||
* Decrements the current value. Wraps value to the maximum representable unsigned value
|
||||
* when decrementing a value of zero.
|
||||
*/
|
||||
DECR_WRAP,
|
||||
/**
|
||||
* Bitwise inverts the current value.
|
||||
*/
|
||||
INVERT,
|
||||
}
|
||||
|
||||
public enum StencilFace {
|
||||
FRONT,
|
||||
BACK,
|
||||
FRONT_AND_BACK
|
||||
}
|
||||
// Converts the StencilFace enum ordinal to Filament's equivalent bit field.
|
||||
static final int[] sStencilFaceMapping = {0x1, 0x2, 0x3};
|
||||
|
||||
public MaterialInstance(Engine engine, long nativeMaterialInstance) {
|
||||
mNativeObject = nativeMaterialInstance;
|
||||
mNativeMaterial = nGetMaterial(mNativeObject);
|
||||
@@ -351,19 +403,40 @@ public class MaterialInstance {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a custom scissor rectangle; by default this encompasses the View.
|
||||
* Set-up a custom scissor rectangle; by default it is disabled.
|
||||
*
|
||||
* @param left left coordinate of the scissor box
|
||||
* @param bottom bottom coordinate of the scissor box
|
||||
* <p>
|
||||
* The scissor rectangle gets clipped by the View's viewport, in other words, the scissor
|
||||
* cannot affect fragments outside of the View's Viewport.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Currently the scissor is not compatible with dynamic resolution and should always be
|
||||
* disabled when dynamic resolution is used.
|
||||
* </p>
|
||||
*
|
||||
* @param left left coordinate of the scissor box relative to the viewport
|
||||
* @param bottom bottom coordinate of the scissor box relative to the viewport
|
||||
* @param width width of the scissor box
|
||||
* @param height height of the scissor box
|
||||
*
|
||||
* @see #unsetScissor
|
||||
* @see View#setViewport
|
||||
* @see View#setDynamicResolutionOptions
|
||||
*/
|
||||
public void setScissor(@IntRange(from = 0) int left, @IntRange(from = 0) int bottom,
|
||||
@IntRange(from = 0) int width, @IntRange(from = 0) int height) {
|
||||
nSetScissor(getNativeObject(), left, bottom, width, height);
|
||||
}
|
||||
|
||||
/** Returns the scissor rectangle to its default setting, which encompasses the View. */
|
||||
/**
|
||||
* Returns the scissor rectangle to its default disabled setting.
|
||||
* <p>
|
||||
* Currently the scissor is not compatible with dynamic resolution and should always be
|
||||
* disabled when dynamic resolution is used.
|
||||
* </p>
|
||||
* @see View#setDynamicResolutionOptions
|
||||
*/
|
||||
public void unsetScissor() {
|
||||
nUnsetScissor(getNativeObject());
|
||||
}
|
||||
@@ -401,6 +474,14 @@ public class MaterialInstance {
|
||||
nSetMaskThreshold(getNativeObject(), threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum alpha value a fragment must have to not be discarded when the blend
|
||||
* mode is MASKED
|
||||
*/
|
||||
public float getMaskThreshold() {
|
||||
return nGetMaskThreshold(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the screen space variance of the filter kernel used when applying specular
|
||||
* anti-aliasing. The default value is set to 0.15. The specified value should be between
|
||||
@@ -414,6 +495,14 @@ public class MaterialInstance {
|
||||
nSetSpecularAntiAliasingVariance(getNativeObject(), variance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the screen space variance of the filter kernel used when applying specular
|
||||
* anti-aliasing.
|
||||
*/
|
||||
public float getSpecularAntiAliasingVariance() {
|
||||
return nGetSpecularAntiAliasingVariance(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the clamping threshold used to suppress estimation errors when applying specular
|
||||
* anti-aliasing. The default value is set to 0.2. The specified value should be between 0
|
||||
@@ -427,6 +516,14 @@ public class MaterialInstance {
|
||||
nSetSpecularAntiAliasingThreshold(getNativeObject(), threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clamping threshold used to suppress estimation errors when applying specular
|
||||
* anti-aliasing.
|
||||
*/
|
||||
public float getSpecularAntiAliasingThreshold() {
|
||||
return nGetSpecularAntiAliasingThreshold(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables double-sided lighting if the parent Material has double-sided capability,
|
||||
* otherwise prints a warning. If double-sided lighting is enabled, backface culling is
|
||||
@@ -440,6 +537,14 @@ public class MaterialInstance {
|
||||
nSetDoubleSided(getNativeObject(), doubleSided);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether double-sided lighting is enabled when the parent Material has double-sided
|
||||
* capability.
|
||||
*/
|
||||
public boolean isDoubleSided() {
|
||||
return nIsDoubleSided(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default triangle culling state that was set on the material.
|
||||
*
|
||||
@@ -447,10 +552,18 @@ public class MaterialInstance {
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:culling">
|
||||
* Rasterization: culling</a>
|
||||
*/
|
||||
public void setCullingMode(Material.CullingMode mode) {
|
||||
public void setCullingMode(@NonNull Material.CullingMode mode) {
|
||||
nSetCullingMode(getNativeObject(), mode.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the face culling mode.
|
||||
*/
|
||||
@NonNull
|
||||
public Material.CullingMode getCullingMode() {
|
||||
return sCullingModeValues[nGetCullingMode(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default color-buffer write state that was set on the material.
|
||||
*
|
||||
@@ -462,6 +575,13 @@ public class MaterialInstance {
|
||||
nSetColorWrite(getNativeObject(), enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether color write is enabled.
|
||||
*/
|
||||
public boolean isColorWriteEnabled() {
|
||||
return nIsColorWriteEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default depth-buffer write state that was set on the material.
|
||||
*
|
||||
@@ -473,6 +593,27 @@ public class MaterialInstance {
|
||||
nSetDepthWrite(getNativeObject(), enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether depth write is enabled.
|
||||
*/
|
||||
public boolean isDepthWriteEnabled() {
|
||||
return nIsDepthWriteEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or Disable stencil writes
|
||||
*/
|
||||
public void setStencilWrite(boolean enable) {
|
||||
nSetStencilWrite(getNativeObject(), enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether stencil write is enabled.
|
||||
*/
|
||||
public boolean isStencilWriteEnabled() {
|
||||
return nIsStencilWriteEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default depth testing state that was set on the material.
|
||||
*
|
||||
@@ -484,6 +625,215 @@ public class MaterialInstance {
|
||||
nSetDepthCulling(getNativeObject(), enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether depth culling is enabled.
|
||||
*/
|
||||
public boolean isDepthCullingEnabled() {
|
||||
return nIsDepthCullingEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stencil comparison function (default is {@link TextureSampler.CompareFunction#ALWAYS}).
|
||||
*
|
||||
* <p>
|
||||
* It's possible to set separate stencil comparison functions; one for front-facing polygons,
|
||||
* and one for back-facing polygons. The face parameter determines the comparison function(s)
|
||||
* updated by this call.
|
||||
* </p>
|
||||
*
|
||||
* @param func the stencil comparison function
|
||||
* @param face the faces to update the comparison function for
|
||||
*/
|
||||
public void setStencilCompareFunction(TextureSampler.CompareFunction func, StencilFace face) {
|
||||
nSetStencilCompareFunction(getNativeObject(), func.ordinal(),
|
||||
sStencilFaceMapping[face.ordinal()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stencil comparison function for both front and back-facing polygons.
|
||||
* @see #setStencilCompareFunction(TextureSampler.CompareFunction, StencilFace)
|
||||
*/
|
||||
public void setStencilCompareFunction(TextureSampler.CompareFunction func) {
|
||||
setStencilCompareFunction(func, StencilFace.FRONT_AND_BACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stencil fail operation (default is {@link StencilOperation#KEEP}).
|
||||
*
|
||||
* <p>
|
||||
* The stencil fail operation is performed to update values in the stencil buffer when the
|
||||
* stencil test fails.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It's possible to set separate stencil fail operations; one for front-facing polygons, and one
|
||||
* for back-facing polygons. The face parameter determines the stencil fail operation(s) updated
|
||||
* by this call.
|
||||
* </p>
|
||||
*
|
||||
* @param op the stencil fail operation
|
||||
* @param face the faces to update the stencil fail operation for
|
||||
*/
|
||||
public void setStencilOpStencilFail(StencilOperation op, StencilFace face) {
|
||||
nSetStencilOpStencilFail(getNativeObject(), op.ordinal(),
|
||||
sStencilFaceMapping[face.ordinal()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stencil fail operation for both front and back-facing polygons.
|
||||
* @see #setStencilOpStencilFail(StencilOperation, StencilFace)
|
||||
*/
|
||||
public void setStencilOpStencilFail(StencilOperation op) {
|
||||
setStencilOpStencilFail(op, StencilFace.FRONT_AND_BACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the depth fail operation (default is {@link StencilOperation#KEEP}).
|
||||
*
|
||||
* <p>
|
||||
* The depth fail operation is performed to update values in the stencil buffer when the depth
|
||||
* test fails.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It's possible to set separate depth fail operations; one for front-facing polygons, and one
|
||||
* for back-facing polygons. The face parameter determines the depth fail operation(s) updated
|
||||
* by this call.
|
||||
* </p>
|
||||
*
|
||||
* @param op the depth fail operation
|
||||
* @param face the faces to update the depth fail operation for
|
||||
*/
|
||||
public void setStencilOpDepthFail(StencilOperation op, StencilFace face) {
|
||||
nSetStencilOpDepthFail(getNativeObject(), op.ordinal(),
|
||||
sStencilFaceMapping[face.ordinal()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the depth fail operation for both front and back-facing polygons.
|
||||
* @see #setStencilOpDepthFail(StencilOperation, StencilFace)
|
||||
*/
|
||||
public void setStencilOpDepthFail(StencilOperation op) {
|
||||
setStencilOpDepthFail(op, StencilFace.FRONT_AND_BACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the depth-stencil pass operation (default is {@link StencilOperation#KEEP}).
|
||||
*
|
||||
* <p>
|
||||
* The depth-stencil pass operation is performed to update values in the stencil buffer when
|
||||
* both the stencil test and depth test pass.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It's possible to set separate depth-stencil pass operations; one for front-facing polygons,
|
||||
* and one for back-facing polygons. The face parameter determines the depth-stencil pass
|
||||
* operation(s) updated by this call.
|
||||
* </p>
|
||||
*
|
||||
* @param op the depth-stencil pass operation
|
||||
* @param face the faces to update the depth-stencil operation for
|
||||
*/
|
||||
public void setStencilOpDepthStencilPass(StencilOperation op, StencilFace face) {
|
||||
nSetStencilOpDepthStencilPass(getNativeObject(), op.ordinal(),
|
||||
sStencilFaceMapping[face.ordinal()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the depth-stencil pass operation for both front and back-facing polygons.
|
||||
* @see #setStencilOpDepthStencilPass(StencilOperation, StencilFace)
|
||||
*/
|
||||
public void setStencilOpDepthStencilPass(StencilOperation op) {
|
||||
setStencilOpDepthStencilPass(op, StencilFace.FRONT_AND_BACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stencil reference value (default is 0).
|
||||
*
|
||||
* <p>
|
||||
* The stencil reference value is the left-hand side for stencil comparison tests. It's also
|
||||
* used as the replacement stencil value when {@link StencilOperation} is
|
||||
* {@link StencilOperation#REPLACE}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It's possible to set separate stencil reference values; one for front-facing polygons, and
|
||||
* one for back-facing polygons. The face parameter determines the reference value(s) updated by
|
||||
* this call.
|
||||
* </p>
|
||||
*
|
||||
* @param value the stencil reference value (only the least significant 8 bits are used)
|
||||
* @param face the faces to update the reference value for
|
||||
*/
|
||||
public void setStencilReferenceValue(@IntRange(from = 0, to = 255) int value, StencilFace face) {
|
||||
nSetStencilReferenceValue(getNativeObject(), value, sStencilFaceMapping[face.ordinal()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stencil reference value for both front and back-facing polygons.
|
||||
* @see #setStencilReferenceValue(int, StencilFace)
|
||||
*/
|
||||
public void setStencilReferenceValue(@IntRange(from = 0, to = 255) int value) {
|
||||
setStencilReferenceValue(value, StencilFace.FRONT_AND_BACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stencil read mask (default is 0xFF).
|
||||
*
|
||||
* <p>
|
||||
* The stencil read mask masks the bits of the values participating in the stencil comparison
|
||||
* test- both the value read from the stencil buffer and the reference value.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It's possible to set separate stencil read masks; one for front-facing polygons, and one for
|
||||
* back-facing polygons. The face parameter determines the stencil read mask(s) updated by this
|
||||
* call.
|
||||
* </p>
|
||||
*
|
||||
* @param readMask the read mask (only the least significant 8 bits are used)
|
||||
* @param face the faces to update the read mask for
|
||||
*/
|
||||
public void setStencilReadMask(@IntRange(from = 0, to = 255) int readMask, StencilFace face) {
|
||||
nSetStencilReadMask(getNativeObject(), readMask, sStencilFaceMapping[face.ordinal()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stencil read mask for both front and back-facing polygons.
|
||||
* @see #setStencilReadMask(int, StencilFace)
|
||||
*/
|
||||
public void setStencilReadMask(@IntRange(from = 0, to = 255) int readMask) {
|
||||
setStencilReadMask(readMask, StencilFace.FRONT_AND_BACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stencil write mask (default is 0xFF).
|
||||
*
|
||||
* <p>
|
||||
* The stencil write mask masks the bits in the stencil buffer updated by stencil operations.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It's possible to set separate stencil write masks; one for front-facing polygons, and one for
|
||||
* back-facing polygons. The face parameter determines the stencil write mask(s) updated by this
|
||||
* call.
|
||||
* </p>
|
||||
*
|
||||
* @param writeMask the write mask (only the least significant 8 bits are used)
|
||||
* @param face the faces to update the read mask for
|
||||
*/
|
||||
public void setStencilWriteMask(@IntRange(from = 0, to = 255) int writeMask, StencilFace face) {
|
||||
nSetStencilWriteMask(getNativeObject(), writeMask, sStencilFaceMapping[face.ordinal()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stencil write mask for both front and back-facing polygons.
|
||||
* @see #setStencilWriteMask(int, StencilFace)
|
||||
*/
|
||||
public void setStencilWriteMask(int writeMask) {
|
||||
setStencilWriteMask(writeMask, StencilFace.FRONT_AND_BACK);
|
||||
}
|
||||
|
||||
public long getNativeObject() {
|
||||
if (mNativeObject == 0) {
|
||||
throw new IllegalStateException("Calling method on destroyed MaterialInstance");
|
||||
@@ -556,10 +906,37 @@ public class MaterialInstance {
|
||||
private static native void nSetCullingMode(long nativeMaterialInstance, long mode);
|
||||
private static native void nSetColorWrite(long nativeMaterialInstance, boolean enable);
|
||||
private static native void nSetDepthWrite(long nativeMaterialInstance, boolean enable);
|
||||
private static native void nSetStencilWrite(long nativeMaterialInstance, boolean enable);
|
||||
private static native void nSetDepthCulling(long nativeMaterialInstance, boolean enable);
|
||||
|
||||
private static native void nSetStencilCompareFunction(long nativeMaterialInstance,
|
||||
long function, long face);
|
||||
private static native void nSetStencilOpStencilFail(long nativeMaterialInstance, long op,
|
||||
long face);
|
||||
private static native void nSetStencilOpDepthFail(long nativeMaterialInstance, long op,
|
||||
long face);
|
||||
private static native void nSetStencilOpDepthStencilPass(long nativeMaterialInstance, long op,
|
||||
long face);
|
||||
private static native void nSetStencilReferenceValue(long nativeMaterialInstance, int value,
|
||||
long face);
|
||||
private static native void nSetStencilReadMask(long nativeMaterialInstance, int readMask,
|
||||
long face);
|
||||
private static native void nSetStencilWriteMask(long nativeMaterialInstance, int writeMask,
|
||||
long face);
|
||||
|
||||
private static native String nGetName(long nativeMaterialInstance);
|
||||
private static native long nGetMaterial(long nativeMaterialInstance);
|
||||
|
||||
private static native long nDuplicate(long otherNativeMaterialInstance, String name);
|
||||
|
||||
|
||||
private static native float nGetMaskThreshold(long nativeMaterialInstance);
|
||||
private static native float nGetSpecularAntiAliasingVariance(long nativeMaterialInstance);
|
||||
private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterialInstance);
|
||||
private static native boolean nIsDoubleSided(long nativeMaterialInstance);
|
||||
private static native int nGetCullingMode(long nativeMaterialInstance);
|
||||
private static native boolean nIsColorWriteEnabled(long nativeMaterialInstance);
|
||||
private static native boolean nIsDepthWriteEnabled(long nativeMaterialInstance);
|
||||
private static native boolean nIsStencilWriteEnabled(long nativeMaterialInstance);
|
||||
private static native boolean nIsDepthCullingEnabled(long nativeMaterialInstance);
|
||||
}
|
||||
|
||||
@@ -163,6 +163,15 @@ public class Scene {
|
||||
return nGetLightCount(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given entity is in the Scene.
|
||||
*
|
||||
* @return Whether the given entity is in the Scene.
|
||||
*/
|
||||
public boolean hasEntity(@Entity int entity) {
|
||||
return nHasEntity(getNativeObject(), entity);
|
||||
}
|
||||
|
||||
public long getNativeObject() {
|
||||
if (mNativeObject == 0) {
|
||||
throw new IllegalStateException("Calling method on destroyed Scene");
|
||||
@@ -182,4 +191,5 @@ public class Scene {
|
||||
private static native void nRemoveEntities(long nativeScene, int[] entities);
|
||||
private static native int nGetRenderableCount(long nativeScene);
|
||||
private static native int nGetLightCount(long nativeScene);
|
||||
private static native boolean nHasEntity(long nativeScene, int entity);
|
||||
}
|
||||
|
||||
@@ -884,7 +884,7 @@ public class Texture {
|
||||
// TODO: add a setImage() version that takes an android Bitmap
|
||||
|
||||
/**
|
||||
* <code>setImage</code> is used to modify the whole content of the texure from a CPU-buffer.
|
||||
* <code>setImage</code> is used to modify the whole content of the texture from a CPU-buffer.
|
||||
*
|
||||
* <p>This <code>Texture</code> instance must use {@link Sampler#SAMPLER_2D SAMPLER_2D} or
|
||||
* {@link Sampler#SAMPLER_EXTERNAL SAMPLER_EXTERNAL}. If the later is specified
|
||||
@@ -951,11 +951,11 @@ public class Texture {
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>setImage</code> is used to modify a sub-region of the 3D texture or 2D texture array
|
||||
* from a CPU-buffer.
|
||||
* <code>setImage</code> is used to modify a sub-region of a 3D texture, 2D texture array or
|
||||
* cubemap from a CPU-buffer. Cubemaps are treated like a 2D array of six layers.
|
||||
*
|
||||
* <p>This <code>Texture</code> instance must use {@link Sampler#SAMPLER_2D_ARRAY SAMPLER_2D_ARRAY} or
|
||||
* {@link Sampler#SAMPLER_3D SAMPLER_3D}.</p>
|
||||
* <p>This <code>Texture</code> instance must use {@link Sampler#SAMPLER_2D_ARRAY SAMPLER_2D_ARRAY},
|
||||
* {@link Sampler#SAMPLER_3D SAMPLER_3D} or {@link Sampler#SAMPLER_CUBEMAP SAMPLER_CUBEMAP}.</p>
|
||||
*
|
||||
* @param engine {@link Engine} this texture is associated to. Must be the
|
||||
* instance passed to {@link Builder#build Builder.build()}.
|
||||
|
||||
+33
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.google.android.filament;
|
||||
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.Size;
|
||||
@@ -199,6 +200,36 @@ import androidx.annotation.Size;
|
||||
return nGetParent(mNativeObject, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of children of an {@link EntityInstance}.
|
||||
*
|
||||
* @param i the {@link EntityInstance} of the transform component to query.
|
||||
* @return The number of children of the queried component.
|
||||
*/
|
||||
public int getChildCount(@EntityInstance int i) {
|
||||
return nGetChildCount(mNativeObject, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of children for a transform component.
|
||||
*
|
||||
* @param i the {@link EntityInstance} of the transform component to get the children
|
||||
* from.
|
||||
* @param outEntities array to receive the result sized to the maximum number of children to
|
||||
* retrieve. If <code>null</code> is given, a new suitable array sized to
|
||||
* {@link #getChildCount(int)} is allocated.
|
||||
* @return Array of retrieved children {@link Entity}.
|
||||
*/
|
||||
public @Entity @NonNull int[] getChildren(@EntityInstance int i, @Nullable int[] outEntities) {
|
||||
if (outEntities == null) {
|
||||
outEntities = new int[getChildCount(i)];
|
||||
}
|
||||
if (outEntities.length > 0) {
|
||||
nGetChildren(mNativeObject, i, outEntities, outEntities.length);
|
||||
}
|
||||
return outEntities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a local transform of a transform component.
|
||||
* <p>This operation can be slow if the hierarchy of transform is too deep, and this
|
||||
@@ -360,6 +391,8 @@ import androidx.annotation.Size;
|
||||
private static native void nDestroy(long nativeTransformManager, int entity);
|
||||
private static native void nSetParent(long nativeTransformManager, int i, int newParent);
|
||||
private static native int nGetParent(long nativeTransformManager, int i);
|
||||
private static native int nGetChildCount(long nativeTransformManager, int i);
|
||||
private static native void nGetChildren(long nativeEntityManager, int i, int[] outEntities, int count);
|
||||
private static native void nSetTransform(long nativeTransformManager, int i, float[] localTransform);
|
||||
private static native void nSetTransformFp64(long nativeTransformManager, int i, double[] localTransform);
|
||||
private static native void nGetTransform(long nativeTransformManager, int i, float[] outLocalTransform);
|
||||
|
||||
@@ -793,7 +793,7 @@ public class View {
|
||||
public void setVsmShadowOptions(@NonNull VsmShadowOptions options) {
|
||||
mVsmShadowOptions = options;
|
||||
nSetVsmShadowOptions(getNativeObject(), options.anisotropy, options.mipmapping,
|
||||
options.minVarianceScale, options.lightBleedReduction);
|
||||
options.highPrecision, options.minVarianceScale, options.lightBleedReduction);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1011,6 +1011,45 @@ public class View {
|
||||
return mDepthOfFieldOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables use of the stencil buffer.
|
||||
*
|
||||
* <p>
|
||||
* The stencil buffer is an 8-bit, per-fragment unsigned integer stored alongside the depth
|
||||
* buffer. The stencil buffer is cleared at the beginning of a frame and discarded after the
|
||||
* color pass.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Each fragment's stencil value is set during rasterization by specifying stencil operations on
|
||||
* a {@link Material}. The stencil buffer can be used as a mask for later rendering by setting a
|
||||
* {@link Material}'s stencil comparison function and reference value. Fragments that don't pass
|
||||
* the stencil test are then discarded.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Post-processing must be enabled in order to use the stencil buffer.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A renderable's priority (see {@link RenderableManager#setPriority(int, int)}) is useful to
|
||||
* control the order in which primitives are drawn.
|
||||
* </p>
|
||||
*
|
||||
* @param enabled True to enable the stencil buffer, false disables it (default)
|
||||
*/
|
||||
public void setStencilBufferEnabled(boolean enabled) {
|
||||
nSetStencilBufferEnabled(getNativeObject(), enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the stencil buffer is enabled.
|
||||
* @see View#setStencilBufferEnabled(boolean)
|
||||
*/
|
||||
public boolean isStencilBufferEnabled() {
|
||||
return nIsStencilBufferEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* A class containing the result of a picking query
|
||||
*/
|
||||
@@ -1105,7 +1144,7 @@ public class View {
|
||||
private static native void nSetRenderQuality(long nativeView, int hdrColorBufferQuality);
|
||||
private static native void nSetDynamicLightingOptions(long nativeView, float zLightNear, float zLightFar);
|
||||
private static native void nSetShadowType(long nativeView, int type);
|
||||
private static native void nSetVsmShadowOptions(long nativeView, int anisotropy, boolean mipmapping, float minVarianceScale, float lightBleedReduction);
|
||||
private static native void nSetVsmShadowOptions(long nativeView, int anisotropy, boolean mipmapping, boolean highPrecision, float minVarianceScale, float lightBleedReduction);
|
||||
private static native void nSetSoftShadowOptions(long nativeView, float penumbraScale, float penumbraRatioScale);
|
||||
private static native void nSetColorGrading(long nativeView, long nativeColorGrading);
|
||||
private static native void nSetPostProcessingEnabled(long nativeView, boolean enabled);
|
||||
@@ -1131,6 +1170,8 @@ public class View {
|
||||
private static native void nSetGuardBandOptions(long nativeView, boolean enabled);
|
||||
private static native boolean nIsScreenSpaceRefractionEnabled(long nativeView);
|
||||
private static native void nPick(long nativeView, int x, int y, Object handler, InternalOnPickCallback internalCallback);
|
||||
private static native void nSetStencilBufferEnabled(long nativeView, boolean enabled);
|
||||
private static native boolean nIsStencilBufferEnabled(long nativeView);
|
||||
|
||||
/**
|
||||
* List of available ambient occlusion techniques.
|
||||
@@ -1776,6 +1817,13 @@ public class View {
|
||||
* Whether to generate mipmaps for all VSM shadow maps.
|
||||
*/
|
||||
public boolean mipmapping = false;
|
||||
/**
|
||||
* Whether to use a 32-bits or 16-bits texture format for VSM shadow maps. 32-bits
|
||||
* precision is rarely needed, but it does reduces light leaks as well as "fading"
|
||||
* of the shadows in some situations. Setting highPrecision to true for a single
|
||||
* shadow map will double the memory usage of all shadow maps.
|
||||
*/
|
||||
public boolean highPrecision = false;
|
||||
/**
|
||||
* VSM minimum variance scale, must be positive.
|
||||
*/
|
||||
|
||||
@@ -70,7 +70,8 @@ Java_com_google_android_filament_utils_AutomationEngine_nStartBatchMode(JNIEnv*
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_utils_AutomationEngine_nTick(JNIEnv* env, jclass klass,
|
||||
jlong nativeAutomation, jlong view, jlongArray materials, jlong renderer, jfloat deltaTime) {
|
||||
jlong nativeAutomation, jlong nativeEngine,
|
||||
jlong view, jlongArray materials, jlong renderer, jfloat deltaTime) {
|
||||
using MaterialPointer = MaterialInstance*;
|
||||
jsize materialCount = 0;
|
||||
jlong* longMaterials = nullptr;
|
||||
@@ -90,7 +91,8 @@ Java_com_google_android_filament_utils_AutomationEngine_nTick(JNIEnv* env, jclas
|
||||
.materials = ptrMaterials,
|
||||
.materialCount = (size_t) materialCount,
|
||||
};
|
||||
automation->tick(content, deltaTime);
|
||||
Engine* engine = (Engine*)nativeEngine;
|
||||
automation->tick(engine, content, deltaTime);
|
||||
if (longMaterials) {
|
||||
env->ReleaseLongArrayElements(materials, longMaterials, 0);
|
||||
delete[] ptrMaterials;
|
||||
@@ -99,7 +101,8 @@ Java_com_google_android_filament_utils_AutomationEngine_nTick(JNIEnv* env, jclas
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_utils_AutomationEngine_nApplySettings(JNIEnv* env, jclass klass,
|
||||
jlong nativeAutomation, jstring json, jlong view, jlongArray materials, jlong nativeIbl,
|
||||
jlong nativeAutomation, jlong nativeEngine,
|
||||
jstring json, jlong view, jlongArray materials, jlong nativeIbl,
|
||||
jint sunlightEntity, jintArray assetLights, jlong nativeLm, jlong scene, jlong renderer) {
|
||||
using MaterialPointer = MaterialInstance*;
|
||||
|
||||
@@ -140,8 +143,8 @@ Java_com_google_android_filament_utils_AutomationEngine_nApplySettings(JNIEnv* e
|
||||
.assetLights = (Entity*) intLights,
|
||||
.assetLightCount = (size_t) lightCount,
|
||||
};
|
||||
|
||||
automation->applySettings(nativeJson, jsonLength, content);
|
||||
Engine* engine = (Engine*)nativeEngine;
|
||||
automation->applySettings(engine, nativeJson, jsonLength, content);
|
||||
env->ReleaseStringUTFChars(json, nativeJson);
|
||||
if (longMaterials) {
|
||||
env->ReleaseLongArrayElements(materials, longMaterials, 0);
|
||||
|
||||
+12
-7
@@ -156,10 +156,11 @@ public class AutomationEngine {
|
||||
* This is when settings get applied, screenshots are (optionally) exported, and the internal
|
||||
* test counter is potentially incremented.
|
||||
*
|
||||
* @param engine The filament Engine of interest.
|
||||
* @param content Contains the Filament View, Materials, and Renderer that get modified.
|
||||
* @param deltaTime The amount of time that has passed since the previous tick in seconds.
|
||||
*/
|
||||
public void tick(@NonNull ViewerContent content, float deltaTime) {
|
||||
public void tick(@NonNull Engine engine, @NonNull ViewerContent content, float deltaTime) {
|
||||
if (content.view == null || content.renderer == null) {
|
||||
throw new IllegalStateException("Must provide a View and Renderer");
|
||||
}
|
||||
@@ -172,7 +173,7 @@ public class AutomationEngine {
|
||||
}
|
||||
long nativeView = content.view.getNativeObject();
|
||||
long nativeRenderer = content.renderer.getNativeObject();
|
||||
nTick(mNativeObject, nativeView, nativeMaterialInstances, nativeRenderer, deltaTime);
|
||||
nTick(mNativeObject, engine.getNativeObject(), nativeView, nativeMaterialInstances, nativeRenderer, deltaTime);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,10 +185,12 @@ public class AutomationEngine {
|
||||
* This updates the stashed Settings object, then pushes those settings to the given
|
||||
* Filament objects. Clients can optionally call getColorGrading() after calling this method.
|
||||
*
|
||||
* @param engine Filament Engine to use.
|
||||
* @param settingsJson Contains the JSON string with a set of changes that need to be pushed.
|
||||
* @param content Contains a set of Filament objects that you want to mutate.
|
||||
*/
|
||||
public void applySettings(@NonNull String settingsJson, @NonNull ViewerContent content) {
|
||||
public void applySettings(@NonNull Engine engine, @NonNull String settingsJson,
|
||||
@NonNull ViewerContent content) {
|
||||
if (content.view == null || content.renderer == null) {
|
||||
throw new IllegalStateException("Must provide a View and Renderer");
|
||||
}
|
||||
@@ -206,7 +209,8 @@ public class AutomationEngine {
|
||||
long nativeLm = content.lightManager.getNativeObject();
|
||||
long nativeScene = content.scene.getNativeObject();
|
||||
long nativeRenderer = content.renderer.getNativeObject();
|
||||
nApplySettings(mNativeObject, settingsJson, nativeView, nativeMaterialInstances,
|
||||
nApplySettings(mNativeObject, engine.getNativeObject(),
|
||||
settingsJson, nativeView, nativeMaterialInstances,
|
||||
nativeIbl, content.sunlight, content.assetLights, nativeLm, nativeScene,
|
||||
nativeRenderer);
|
||||
}
|
||||
@@ -267,9 +271,10 @@ public class AutomationEngine {
|
||||
int minFrameCount, boolean verbose);
|
||||
private static native void nStartRunning(long nativeObject);
|
||||
private static native void nStartBatchMode(long nativeObject);
|
||||
private static native void nTick(long nativeObject, long view, long[] materials, long renderer,
|
||||
float deltaTime);
|
||||
private static native void nApplySettings(long nativeObject, String jsonSettings, long view,
|
||||
private static native void nTick(long nativeObject, long nativeEngine,
|
||||
long view, long[] materials, long renderer, float deltaTime);
|
||||
private static native void nApplySettings(long nativeObject, long nativeEngine,
|
||||
String jsonSettings, long view,
|
||||
long[] materials, long ibl, int sunlight, int[] assetLights, long lightManager,
|
||||
long scene, long renderer);
|
||||
private static native void nGetViewerOptions(long nativeObject, Object result);
|
||||
|
||||
+9
-11
@@ -73,8 +73,6 @@ class ModelViewer(
|
||||
get() = resourceLoader.asyncGetLoadProgress()
|
||||
|
||||
var normalizeSkinningWeights = true
|
||||
var recomputeBoundingBoxes = false
|
||||
var ignoreBindTransform = false
|
||||
|
||||
var cameraFocalLength = 28f
|
||||
set(value) {
|
||||
@@ -116,7 +114,7 @@ class ModelViewer(
|
||||
|
||||
materialProvider = UbershaderProvider(engine)
|
||||
assetLoader = AssetLoader(engine, materialProvider, EntityManager.get())
|
||||
resourceLoader = ResourceLoader(engine, normalizeSkinningWeights, recomputeBoundingBoxes, ignoreBindTransform)
|
||||
resourceLoader = ResourceLoader(engine, normalizeSkinningWeights)
|
||||
|
||||
// Always add a direct light source since it is required for shadowing.
|
||||
// We highly recommend adding an indirect light as well.
|
||||
@@ -178,10 +176,10 @@ class ModelViewer(
|
||||
*/
|
||||
fun loadModelGlb(buffer: Buffer) {
|
||||
destroyModel()
|
||||
asset = assetLoader.createAssetFromBinary(buffer)
|
||||
asset = assetLoader.createAsset(buffer)
|
||||
asset?.let { asset ->
|
||||
resourceLoader.asyncBeginLoad(asset)
|
||||
animator = asset.animator
|
||||
animator = asset.getInstance().animator
|
||||
asset.releaseSourceData()
|
||||
}
|
||||
}
|
||||
@@ -193,7 +191,7 @@ class ModelViewer(
|
||||
*/
|
||||
fun loadModelGltf(buffer: Buffer, callback: (String) -> Buffer?) {
|
||||
destroyModel()
|
||||
asset = assetLoader.createAssetFromJson(buffer)
|
||||
asset = assetLoader.createAsset(buffer)
|
||||
asset?.let { asset ->
|
||||
for (uri in asset.resourceUris) {
|
||||
val resourceBuffer = callback(uri)
|
||||
@@ -204,7 +202,7 @@ class ModelViewer(
|
||||
resourceLoader.addResourceData(uri, resourceBuffer)
|
||||
}
|
||||
resourceLoader.asyncBeginLoad(asset)
|
||||
animator = asset.animator
|
||||
animator = asset.getInstance().animator
|
||||
asset.releaseSourceData()
|
||||
}
|
||||
}
|
||||
@@ -216,7 +214,7 @@ class ModelViewer(
|
||||
*/
|
||||
fun loadModelGltfAsync(buffer: Buffer, callback: (String) -> Buffer) {
|
||||
destroyModel()
|
||||
asset = assetLoader.createAssetFromJson(buffer)
|
||||
asset = assetLoader.createAsset(buffer)
|
||||
fetchResourcesJob = CoroutineScope(Dispatchers.IO).launch {
|
||||
fetchResources(asset!!, callback)
|
||||
}
|
||||
@@ -312,8 +310,8 @@ class ModelViewer(
|
||||
|
||||
private fun addDetachListener(view: android.view.View) {
|
||||
view.addOnAttachStateChangeListener(object : android.view.View.OnAttachStateChangeListener {
|
||||
override fun onViewAttachedToWindow(v: android.view.View?) {}
|
||||
override fun onViewDetachedFromWindow(v: android.view.View?) {
|
||||
override fun onViewAttachedToWindow(v: android.view.View) {}
|
||||
override fun onViewDetachedFromWindow(v: android.view.View) {
|
||||
uiHelper.detach()
|
||||
|
||||
destroyModel()
|
||||
@@ -361,7 +359,7 @@ class ModelViewer(
|
||||
resourceLoader.addResourceData(uri, buffer)
|
||||
}
|
||||
resourceLoader.asyncBeginLoad(asset)
|
||||
animator = asset.animator
|
||||
animator = asset.getInstance().animator
|
||||
asset.releaseSourceData()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ add_library(dracodec STATIC IMPORTED)
|
||||
set_target_properties(dracodec PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libdracodec.a)
|
||||
|
||||
add_library(meshoptimizer STATIC IMPORTED)
|
||||
set_target_properties(meshoptimizer PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libmeshoptimizer.a)
|
||||
|
||||
add_library(ktxreader STATIC IMPORTED)
|
||||
set_target_properties(ktxreader PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libktxreader.a)
|
||||
@@ -76,7 +80,7 @@ set(GLTFIO_SRCS
|
||||
${GLTFIO_DIR}/src/UbershaderProvider.cpp
|
||||
${GLTFIO_DIR}/src/Wireframe.cpp
|
||||
${GLTFIO_DIR}/src/Wireframe.h
|
||||
${GLTFIO_DIR}/src/upcast.h
|
||||
${GLTFIO_DIR}/src/downcast.h
|
||||
|
||||
src/main/cpp/Animator.cpp
|
||||
src/main/cpp/AssetLoader.cpp
|
||||
@@ -99,6 +103,7 @@ set(GLTFIO_INCLUDE_DIRS
|
||||
../../libs/gltfio/include
|
||||
../../third_party/basisu/zstd
|
||||
../../third_party/cgltf
|
||||
../../third_party/meshoptimizer/src
|
||||
../../third_party/robin-map
|
||||
../../third_party/hat-trie
|
||||
../../third_party/stb
|
||||
@@ -111,7 +116,7 @@ target_include_directories(gltfio-jni PRIVATE ${GLTFIO_INCLUDE_DIRS})
|
||||
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.symbols)
|
||||
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.map)
|
||||
target_link_libraries(gltfio-jni filament-jni utils uberzlib log stb ktxreader basis_transcoder zstd uberarchive)
|
||||
target_link_libraries(gltfio-jni dracodec)
|
||||
target_link_libraries(gltfio-jni dracodec meshoptimizer)
|
||||
target_compile_definitions(gltfio-jni PUBLIC GLTFIO_DRACO_SUPPORTED=1)
|
||||
target_include_directories(gltfio-jni PRIVATE ${DRACO_DIR}/src)
|
||||
target_include_directories(gltfio-jni PRIVATE ${DRACO_DIR}/tnt)
|
||||
|
||||
@@ -14,5 +14,4 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.gltfio" />
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
||||
|
||||
@@ -42,6 +42,7 @@ class JavaMaterialProvider : public MaterialProvider {
|
||||
|
||||
jmethodID mMaterialKeyConstructor;
|
||||
jmethodID mCreateMaterialInstance;
|
||||
jmethodID mGetMaterial;
|
||||
jmethodID mGetMaterials;
|
||||
jmethodID mNeedsDummyData;
|
||||
jmethodID mDestroyMaterials;
|
||||
@@ -72,6 +73,10 @@ public:
|
||||
"(L" JAVA_MATERIAL_KEY ";[ILjava/lang/String;Ljava/lang/String;)Lcom/google/android/filament/MaterialInstance;");
|
||||
assert_invariant(mCreateMaterialInstance);
|
||||
|
||||
mGetMaterial = env->GetMethodID(providerClass, "getMaterial",
|
||||
"(L" JAVA_MATERIAL_KEY ";[ILjava/lang/String;)Lcom/google/android/filament/Material;");
|
||||
assert_invariant(mGetMaterial);
|
||||
|
||||
mGetMaterials = env->GetMethodID(providerClass, "getMaterials",
|
||||
"()[Lcom/google/android/filament/Material;");
|
||||
assert_invariant(mGetMaterials);
|
||||
@@ -103,7 +108,7 @@ public:
|
||||
jstring stringExtras = extras ? mEnv->NewStringUTF(extras) : nullptr;
|
||||
|
||||
// Allocate space for the output argument.
|
||||
jintArray uvMapArray = mEnv->NewIntArray(8);
|
||||
jintArray uvMapArray = mEnv->NewIntArray(uvmap->size());
|
||||
|
||||
// Call the Java-based material provider.
|
||||
jobject materialInstance = mEnv->CallObjectMethod(mJavaProvider, mCreateMaterialInstance,
|
||||
@@ -139,6 +144,49 @@ public:
|
||||
return (MaterialInstance*) mEnv->CallLongMethod(materialInstance, mMaterialInstanceGetNativeObject);
|
||||
}
|
||||
|
||||
Material* getMaterial(MaterialKey* config, UvMap* uvmap, const char* label) override {
|
||||
// Create a Java object for the material key and copy the native fields into it.
|
||||
jobject javaKey = mEnv->NewObject(mMaterialKeyClass, mMaterialKeyConstructor);
|
||||
|
||||
auto& helper = MaterialKeyHelper::get();
|
||||
helper.copy(mEnv, javaKey, *config);
|
||||
|
||||
// Convert the optional label into a Java string.
|
||||
jstring stringLabel = label ? mEnv->NewStringUTF(label) : nullptr;
|
||||
|
||||
// Allocate space for the output argument.
|
||||
jintArray uvMapArray = mEnv->NewIntArray(uvmap->size());
|
||||
|
||||
// Call the Java-based material provider.
|
||||
jobject material = mEnv->CallObjectMethod(mJavaProvider, mGetMaterial,
|
||||
javaKey, uvMapArray, stringLabel);
|
||||
|
||||
// Copy the UvMap results from the JVM array into the native array.
|
||||
if (uvmap) {
|
||||
jint* elements = mEnv->GetIntArrayElements(uvMapArray, nullptr);
|
||||
for (size_t i = 0; i < uvmap->size(); i++) {
|
||||
(*uvmap)[i] = (UvSet) elements[i];
|
||||
}
|
||||
mEnv->ReleaseIntArrayElements(uvMapArray, elements, JNI_ABORT);
|
||||
}
|
||||
|
||||
// The config parameter is an in-out parameter so we need to copy the results from Java.
|
||||
helper.copy(mEnv, *config, javaKey);
|
||||
|
||||
mEnv->DeleteLocalRef(javaKey);
|
||||
mEnv->DeleteLocalRef(uvMapArray);
|
||||
|
||||
if (stringLabel) {
|
||||
mEnv->DeleteLocalRef(stringLabel);
|
||||
}
|
||||
|
||||
if (material == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (Material*) mEnv->CallLongMethod(material, mMaterialGetNativeObject);
|
||||
}
|
||||
|
||||
const Material* const* getMaterials() const noexcept override {
|
||||
jobjectArray javaMaterials = (jobjectArray) mEnv->CallObjectMethod(mJavaProvider, mGetMaterials);
|
||||
|
||||
@@ -207,20 +255,11 @@ Java_com_google_android_filament_gltfio_AssetLoader_nDestroyAssetLoader(JNIEnv*,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_gltfio_AssetLoader_nCreateAssetFromBinary(JNIEnv* env, jclass,
|
||||
Java_com_google_android_filament_gltfio_AssetLoader_nCreateAsset(JNIEnv* env, jclass,
|
||||
jlong nativeLoader, jobject javaBuffer, jint remaining) {
|
||||
AssetLoader* loader = (AssetLoader*) nativeLoader;
|
||||
AutoBuffer buffer(env, javaBuffer, remaining);
|
||||
return (jlong) loader->createAssetFromBinary((const uint8_t *) buffer.getData(),
|
||||
buffer.getSize());
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_gltfio_AssetLoader_nCreateAssetFromJson(JNIEnv* env, jclass,
|
||||
jlong nativeLoader, jobject javaBuffer, jint remaining) {
|
||||
AssetLoader* loader = (AssetLoader*) nativeLoader;
|
||||
AutoBuffer buffer(env, javaBuffer, remaining);
|
||||
return (jlong) loader->createAssetFromJson((const uint8_t *) buffer.getData(),
|
||||
return (jlong) loader->createAsset((const uint8_t *) buffer.getData(),
|
||||
buffer.getSize());
|
||||
}
|
||||
|
||||
|
||||
@@ -172,27 +172,6 @@ Java_com_google_android_filament_gltfio_FilamentAsset_nGetCameraEntityCount(JNIE
|
||||
return asset->getCameraEntityCount();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nGetMaterialInstanceCount(JNIEnv*, jclass,
|
||||
jlong nativeAsset) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
return asset->getMaterialInstanceCount();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nGetMaterialInstances(JNIEnv* env, jclass,
|
||||
jlong nativeAsset, jlongArray result) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
jsize available = env->GetArrayLength(result);
|
||||
jsize count = std::min(available, (jsize) asset->getMaterialInstanceCount());
|
||||
jlong* dst = env->GetLongArrayElements(result, nullptr);
|
||||
const MaterialInstance * const* src = asset->getMaterialInstances();
|
||||
for (jsize i = 0; i < count; i++) {
|
||||
dst[i] = (jlong) src[i];
|
||||
}
|
||||
env->ReleaseLongArrayElements(result, dst, 0);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nGetBoundingBox(JNIEnv* env, jclass,
|
||||
jlong nativeAsset, jfloatArray result) {
|
||||
@@ -228,49 +207,11 @@ Java_com_google_android_filament_gltfio_FilamentAsset_nGetExtras(JNIEnv* env, jc
|
||||
return val ? env->NewStringUTF(val) : nullptr;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nGetSkinCount(JNIEnv* , jclass,
|
||||
jlong nativeAsset) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
return (jint) asset->getSkinCount();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nGetSkinNames(JNIEnv* env, jclass,
|
||||
jlong nativeAsset, jobjectArray result) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
jsize available = env->GetArrayLength(result);
|
||||
for (int i = 0; i < available; ++i) {
|
||||
const char* name = asset->getSkinNameAt(i);
|
||||
if (name) {
|
||||
env->SetObjectArrayElement(result, (jsize) i, env->NewStringUTF(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nGetJointCountAt(JNIEnv* , jclass,
|
||||
jlong nativeAsset, jint skinIndex) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
return (jint) asset->getJointCountAt(skinIndex);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nGetJointsAt(JNIEnv* env, jclass,
|
||||
jlong nativeAsset, jint skinIndex, jintArray result) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
jsize available = env->GetArrayLength(result);
|
||||
Entity* entities = (Entity*) env->GetIntArrayElements(result, nullptr);
|
||||
std::copy_n(asset->getJointsAt(skinIndex),
|
||||
std::min(available, (jsize) asset->getJointCountAt(skinIndex)), entities);
|
||||
env->ReleaseIntArrayElements(result, (jint*) entities, 0);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nGetAnimator(JNIEnv* , jclass,
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nGetInstance(JNIEnv* , jclass,
|
||||
jlong nativeAsset) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
return (jlong) asset->getAnimator();
|
||||
return (jlong) asset->getInstance();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -310,49 +251,9 @@ Java_com_google_android_filament_gltfio_FilamentAsset_nGetMorphTargetNames(JNIEn
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nGetMaterialVariantCount(JNIEnv*, jclass,
|
||||
jlong nativeAsset) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
return (jint) asset->getMaterialVariantCount();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nGetMaterialVariantNames(JNIEnv* env, jclass,
|
||||
jlong nativeAsset, jobjectArray result) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
for (int i = 0; i < asset->getMaterialVariantCount(); ++i) {
|
||||
const char* name = asset->getMaterialVariantName(i);
|
||||
env->SetObjectArrayElement(result, (jsize) i, env->NewStringUTF(name));
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nApplyMaterialVariant(JNIEnv* env, jclass,
|
||||
jlong nativeAsset, jint variantIndex) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
asset->applyMaterialVariant(variantIndex);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nReleaseSourceData(JNIEnv* env, jclass,
|
||||
jlong nativeAsset) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
asset->releaseSourceData();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nAttachSkin(JNIEnv* env, jclass,
|
||||
jlong nativeAsset, jint skinIndex, jint targetEntity) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
Entity target = Entity::import(targetEntity);
|
||||
asset->attachSkin(skinIndex, target);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nDetachSkin(JNIEnv* env, jclass,
|
||||
jlong nativeAsset, jint skinIndex, jint targetEntity) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
Entity target = Entity::import(targetEntity);
|
||||
asset->detachSkin(skinIndex, target);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::gltfio;
|
||||
using namespace utils;
|
||||
|
||||
@@ -61,3 +62,95 @@ Java_com_google_android_filament_gltfio_FilamentInstance_nApplyMaterialVariant(J
|
||||
FilamentInstance* instance = (FilamentInstance*) nativeInstance;
|
||||
instance->applyMaterialVariant(variantIndex);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentInstance_nGetMaterialVariantCount(JNIEnv*, jclass,
|
||||
jlong nativeInstance) {
|
||||
FilamentInstance* instance = (FilamentInstance*) nativeInstance;
|
||||
return (jint) instance->getMaterialVariantCount();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentInstance_nGetMaterialVariantNames(JNIEnv* env, jclass,
|
||||
jlong nativeInstance, jobjectArray result) {
|
||||
FilamentInstance* instance = (FilamentInstance*) nativeInstance;
|
||||
for (int i = 0; i < instance->getMaterialVariantCount(); ++i) {
|
||||
const char* name = instance->getMaterialVariantName(i);
|
||||
env->SetObjectArrayElement(result, (jsize) i, env->NewStringUTF(name));
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentInstance_nGetMaterialInstanceCount(JNIEnv*, jclass,
|
||||
jlong nativeInstance) {
|
||||
FilamentInstance* instance = (FilamentInstance*) nativeInstance;
|
||||
return instance->getMaterialInstanceCount();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentInstance_nGetMaterialInstances(JNIEnv* env, jclass,
|
||||
jlong nativeInstance, jlongArray result) {
|
||||
FilamentInstance* instance = (FilamentInstance*) nativeInstance;
|
||||
jsize available = env->GetArrayLength(result);
|
||||
jsize count = std::min(available, (jsize) instance->getMaterialInstanceCount());
|
||||
jlong* dst = env->GetLongArrayElements(result, nullptr);
|
||||
const MaterialInstance * const* src = instance->getMaterialInstances();
|
||||
for (jsize i = 0; i < count; i++) {
|
||||
dst[i] = (jlong) src[i];
|
||||
}
|
||||
env->ReleaseLongArrayElements(result, dst, 0);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentInstance_nAttachSkin(JNIEnv* env, jclass,
|
||||
jlong nativeInstance, jint skinIndex, jint targetEntity) {
|
||||
FilamentInstance* instance = (FilamentInstance*) nativeInstance;
|
||||
Entity target = Entity::import(targetEntity);
|
||||
instance->attachSkin(skinIndex, target);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentInstance_nDetachSkin(JNIEnv* env, jclass,
|
||||
jlong nativeInstance, jint skinIndex, jint targetEntity) {
|
||||
FilamentInstance* instance = (FilamentInstance*) nativeInstance;
|
||||
Entity target = Entity::import(targetEntity);
|
||||
instance->detachSkin(skinIndex, target);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentInstance_nGetSkinCount(JNIEnv* , jclass,
|
||||
jlong nativeInstance) {
|
||||
FilamentInstance* instance = (FilamentInstance*) nativeInstance;
|
||||
return (jint) instance->getSkinCount();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentInstance_nGetSkinNames(JNIEnv* env, jclass,
|
||||
jlong nativeInstance, jobjectArray result) {
|
||||
FilamentInstance* instance = (FilamentInstance*) nativeInstance;
|
||||
jsize available = env->GetArrayLength(result);
|
||||
for (int i = 0; i < available; ++i) {
|
||||
const char* name = instance->getSkinNameAt(i);
|
||||
if (name) {
|
||||
env->SetObjectArrayElement(result, (jsize) i, env->NewStringUTF(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentInstance_nGetJointCountAt(JNIEnv* , jclass,
|
||||
jlong nativeInstance, jint skinIndex) {
|
||||
FilamentInstance* instance = (FilamentInstance*) nativeInstance;
|
||||
return (jint) instance->getJointCountAt(skinIndex);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentInstance_nGetJointsAt(JNIEnv* env, jclass,
|
||||
jlong nativeInstance, jint skinIndex, jintArray result) {
|
||||
FilamentInstance* instance = (FilamentInstance*) nativeInstance;
|
||||
jsize available = env->GetArrayLength(result);
|
||||
Entity* entities = (Entity*) env->GetIntArrayElements(result, nullptr);
|
||||
std::copy_n(instance->getJointsAt(skinIndex),
|
||||
std::min(available, (jsize) instance->getJointCountAt(skinIndex)), entities);
|
||||
env->ReleaseIntArrayElements(result, (jint*) entities, 0);
|
||||
}
|
||||
|
||||
@@ -36,11 +36,9 @@ static void destroy(void*, size_t, void *userData) {
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_gltfio_ResourceLoader_nCreateResourceLoader(JNIEnv*, jclass,
|
||||
jlong nativeEngine, jboolean normalizeSkinningWeights, jboolean recomputeBoundingBoxes,
|
||||
jboolean ignoreBindTransform) {
|
||||
jlong nativeEngine, jboolean normalizeSkinningWeights) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return (jlong) new ResourceLoader({ engine, {}, (bool) normalizeSkinningWeights,
|
||||
(bool) recomputeBoundingBoxes, (bool) ignoreBindTransform});
|
||||
return (jlong) new ResourceLoader({ engine, {}, (bool) normalizeSkinningWeights});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
|
||||
@@ -49,16 +49,19 @@ Java_com_google_android_filament_gltfio_UbershaderProvider_nDestroyMaterials(JNI
|
||||
|
||||
extern "C" JNIEXPORT long JNICALL
|
||||
Java_com_google_android_filament_gltfio_UbershaderProvider_nCreateMaterialInstance(JNIEnv* env, jclass,
|
||||
jlong nativeProvider, jobject materialKey, jintArray uvmap, jstring label) {
|
||||
jlong nativeProvider, jobject materialKey, jintArray uvmap, jstring label, jstring extras) {
|
||||
MaterialKey nativeKey = {};
|
||||
|
||||
auto& helper = MaterialKeyHelper::get();
|
||||
helper.copy(env, nativeKey, materialKey);
|
||||
|
||||
const char* nativeLabel = label ? env->GetStringUTFChars(label, nullptr) : nullptr;
|
||||
const char* nativeExtras = extras ? env->GetStringUTFChars(extras, nullptr) : nullptr;
|
||||
|
||||
UvMap nativeUvMap = {};
|
||||
auto provider = (MaterialProvider*) nativeProvider;
|
||||
MaterialInstance* instance = provider->createMaterialInstance(&nativeKey, &nativeUvMap, nativeLabel);
|
||||
MaterialInstance* instance = provider->createMaterialInstance(&nativeKey, &nativeUvMap,
|
||||
nativeLabel, nativeExtras);
|
||||
|
||||
// Copy the UvMap results from the native array into the JVM array.
|
||||
jint* elements = env->GetIntArrayElements(uvmap, nullptr);
|
||||
@@ -77,9 +80,47 @@ Java_com_google_android_filament_gltfio_UbershaderProvider_nCreateMaterialInstan
|
||||
env->ReleaseStringUTFChars(label, nativeLabel);
|
||||
}
|
||||
|
||||
if (extras) {
|
||||
env->ReleaseStringUTFChars(extras, nativeExtras);
|
||||
}
|
||||
|
||||
return (long) instance;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT long JNICALL
|
||||
Java_com_google_android_filament_gltfio_UbershaderProvider_nGetMaterial(JNIEnv* env, jclass,
|
||||
jlong nativeProvider, jobject materialKey, jintArray uvmap, jstring label) {
|
||||
MaterialKey nativeKey = {};
|
||||
|
||||
auto& helper = MaterialKeyHelper::get();
|
||||
helper.copy(env, nativeKey, materialKey);
|
||||
|
||||
const char* nativeLabel = label ? env->GetStringUTFChars(label, nullptr) : nullptr;
|
||||
|
||||
UvMap nativeUvMap = {};
|
||||
auto provider = (MaterialProvider*) nativeProvider;
|
||||
Material* material = provider->getMaterial(&nativeKey, &nativeUvMap, nativeLabel);
|
||||
|
||||
// Copy the UvMap results from the native array into the JVM array.
|
||||
jint* elements = env->GetIntArrayElements(uvmap, nullptr);
|
||||
if (elements) {
|
||||
const size_t javaSize = env->GetArrayLength(uvmap);
|
||||
for (int i = 0, n = std::min(javaSize, nativeUvMap.size()); i < n; ++i) {
|
||||
elements[i] = nativeUvMap[i];
|
||||
}
|
||||
env->ReleaseIntArrayElements(uvmap, elements, 0);
|
||||
}
|
||||
|
||||
// The config parameter is an in-out parameter so we need to copy the results back to Java.
|
||||
helper.copy(env, materialKey, nativeKey);
|
||||
|
||||
if (label) {
|
||||
env->ReleaseStringUTFChars(label, nativeLabel);
|
||||
}
|
||||
|
||||
return (long) material;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int JNICALL
|
||||
Java_com_google_android_filament_gltfio_UbershaderProvider_nGetMaterialCount(JNIEnv*, jclass,
|
||||
jlong nativeProvider) {
|
||||
|
||||
+8
-20
@@ -26,8 +26,8 @@ import java.nio.Buffer;
|
||||
|
||||
/**
|
||||
* Consumes a blob of glTF 2.0 content (either JSON or GLB) and produces a {@link FilamentAsset}
|
||||
* object, which is a bundle of Filament entities, material instances, textures, vertex buffers,
|
||||
* and index buffers.
|
||||
* object, which is a bundle of Filament textures, vertex buffers, index buffers, etc. An asset is
|
||||
* composed of 1 or more FilamentInstance objects which contain entities and components.
|
||||
*
|
||||
* <p>AssetLoader does not fetch external buffer data or create textures on its own. Clients can use
|
||||
* the provided {@link ResourceLoader} class for this, which obtains the URI list from the asset.
|
||||
@@ -51,7 +51,7 @@ import java.nio.Buffer;
|
||||
* filamentAsset = assets.open("models/lucy.gltf").use { input ->
|
||||
* val bytes = ByteArray(input.available())
|
||||
* input.read(bytes)
|
||||
* assetLoader.createAssetFromJson(ByteBuffer.wrap(bytes))!!
|
||||
* assetLoader.createAsset(ByteBuffer.wrap(bytes))!!
|
||||
* }
|
||||
*
|
||||
* val resourceLoader = ResourceLoader(engine)
|
||||
@@ -115,20 +115,11 @@ public class AssetLoader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FilamentAsset} from the contents of a GLB file.
|
||||
* Creates a {@link FilamentAsset} from the contents of a GLB or GLTF file.
|
||||
*/
|
||||
@Nullable
|
||||
public FilamentAsset createAssetFromBinary(@NonNull Buffer buffer) {
|
||||
long nativeAsset = nCreateAssetFromBinary(mNativeObject, buffer, buffer.remaining());
|
||||
return nativeAsset != 0 ? new FilamentAsset(mEngine, nativeAsset) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FilamentAsset} from the contents of a GLTF file.
|
||||
*/
|
||||
@Nullable
|
||||
public FilamentAsset createAssetFromJson(@NonNull Buffer buffer) {
|
||||
long nativeAsset = nCreateAssetFromJson(mNativeObject, buffer, buffer.remaining());
|
||||
public FilamentAsset createAsset(@NonNull Buffer buffer) {
|
||||
long nativeAsset = nCreateAsset(mNativeObject, buffer, buffer.remaining());
|
||||
return nativeAsset != 0 ? new FilamentAsset(mEngine, nativeAsset) : null;
|
||||
}
|
||||
|
||||
@@ -158,7 +149,7 @@ public class AssetLoader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new instance to an instanced asset.
|
||||
* Adds a new instance to the asset.
|
||||
*
|
||||
* Use this with caution. It is more efficient to pre-allocate a max number of instances, and
|
||||
* gradually add them to the scene as needed. Instances can also be "recycled" by removing and
|
||||
@@ -169,8 +160,6 @@ public class AssetLoader {
|
||||
* create/destroy churn, as noted above.
|
||||
*
|
||||
* This cannot be called after FilamentAsset#releaseSourceData().
|
||||
* This cannot be called on a non-instanced asset.
|
||||
* Animation is not supported in new instances.
|
||||
* See also AssetLoader#createInstancedAsset().
|
||||
*/
|
||||
@Nullable
|
||||
@@ -202,8 +191,7 @@ public class AssetLoader {
|
||||
private static native long nCreateAssetLoader(long nativeEngine, Object provider,
|
||||
long nativeEntities);
|
||||
private static native void nDestroyAssetLoader(long nativeLoader);
|
||||
private static native long nCreateAssetFromBinary(long nativeLoader, Buffer buffer, int remaining);
|
||||
private static native long nCreateAssetFromJson(long nativeLoader, Buffer buffer, int remaining);
|
||||
private static native long nCreateAsset(long nativeLoader, Buffer buffer, int remaining);
|
||||
private static native long nCreateInstancedAsset(long nativeLoader, Buffer buffer, int remaining,
|
||||
long[] nativeInstances);
|
||||
private static native long nCreateInstance(long nativeLoader, long nativeAsset);
|
||||
|
||||
+22
-129
@@ -23,7 +23,6 @@ import androidx.annotation.Nullable;
|
||||
import com.google.android.filament.Box;
|
||||
import com.google.android.filament.Engine;
|
||||
import com.google.android.filament.Entity;
|
||||
import com.google.android.filament.MaterialInstance;
|
||||
|
||||
/**
|
||||
* Owns a bundle of Filament objects that have been created by <code>AssetLoader</code>.
|
||||
@@ -35,25 +34,32 @@ import com.google.android.filament.MaterialInstance;
|
||||
* <code>NameComponentManager</code>, <code>RenderableManager</code>, and others.</p>
|
||||
*
|
||||
* <p>In addition to the aforementioned entities, an asset has strong ownership over a list of
|
||||
* <code>VertexBuffer</code>, <code>IndexBuffer</code>, <code>MaterialInstance</code>, and
|
||||
* <code>Texture</code>.</p>
|
||||
* <code>VertexBuffer</code>, <code>IndexBuffer</code>, and <code>Texture</code>.</p>
|
||||
*
|
||||
* <p>Clients can use {@link ResourceLoader} to create textures, compute tangent quaternions, and
|
||||
* upload data into vertex buffers and index buffers.</p>
|
||||
*
|
||||
* @see ResourceLoader
|
||||
* @see Animator
|
||||
* @see FilamentInstance
|
||||
* @see AssetLoader
|
||||
*/
|
||||
public class FilamentAsset {
|
||||
private long mNativeObject;
|
||||
private Animator mAnimator;
|
||||
private FilamentInstance mPrimaryInstance;
|
||||
private Engine mEngine;
|
||||
|
||||
FilamentAsset(Engine engine, long nativeObject) {
|
||||
mEngine = engine;
|
||||
mNativeObject = nativeObject;
|
||||
mAnimator = null;
|
||||
}
|
||||
|
||||
public FilamentInstance getInstance() {
|
||||
if (mPrimaryInstance != null) {
|
||||
return mPrimaryInstance;
|
||||
}
|
||||
long nativeInstance = nGetInstance(getNativeObject());
|
||||
mPrimaryInstance = new FilamentInstance(this, nativeInstance);
|
||||
return mPrimaryInstance;
|
||||
}
|
||||
|
||||
long getNativeObject() {
|
||||
@@ -169,19 +175,11 @@ public class FilamentAsset {
|
||||
return result;
|
||||
}
|
||||
|
||||
public @NonNull MaterialInstance[] getMaterialInstances() {
|
||||
final int count = nGetMaterialInstanceCount(mNativeObject);
|
||||
MaterialInstance[] result = new MaterialInstance[count];
|
||||
long[] natives = new long[count];
|
||||
nGetMaterialInstances(mNativeObject, natives);
|
||||
for (int i = 0; i < count; i++) {
|
||||
result[i] = new MaterialInstance(mEngine, natives[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bounding box computed from the supplied min / max values in glTF accessors.
|
||||
*
|
||||
* This does not return a bounding box over all FilamentInstance, it's just a straightforward
|
||||
* AAAB that can be determined at load time from the asset data.
|
||||
*/
|
||||
public @NonNull Box getBoundingBox() {
|
||||
float[] box = new float[6];
|
||||
@@ -206,77 +204,6 @@ public class FilamentAsset {
|
||||
return nGetExtras(mNativeObject, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the <code>Animator</code> interface for this asset.
|
||||
*
|
||||
* <p>When calling this for the first time, this must be called after
|
||||
* {@link ResourceLoader#loadResources} or {@link ResourceLoader#asyncBeginLoad}. When the asset
|
||||
* is destroyed, its animator becomes invalid.</p>
|
||||
*/
|
||||
public @NonNull Animator getAnimator() {
|
||||
if (mAnimator != null) {
|
||||
return mAnimator;
|
||||
}
|
||||
long nativeAnimator = nGetAnimator(getNativeObject());
|
||||
if (nativeAnimator == 0) {
|
||||
throw new IllegalStateException("Unable to create animator");
|
||||
}
|
||||
mAnimator = new Animator(nativeAnimator);
|
||||
return mAnimator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the skin count of this asset.
|
||||
*/
|
||||
public int getSkinCount() {
|
||||
return nGetSkinCount(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the skin name at skin index in this asset.
|
||||
*/
|
||||
public @NonNull String[] getSkinNames() {
|
||||
String[] result = new String[getSkinCount()];
|
||||
nGetSkinNames(getNativeObject(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the given skin to the given node, which must have an associated mesh with
|
||||
* BONE_INDICES and BONE_WEIGHTS attributes.
|
||||
*
|
||||
* This is a no-op if the given skin index or target is invalid.
|
||||
*/
|
||||
public void attachSkin(@IntRange(from = 0) int skinIndex, @Entity int target) {
|
||||
nAttachSkin(getNativeObject(), skinIndex, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the given skin to the given node, which must have an associated mesh with
|
||||
* BONE_INDICES and BONE_WEIGHTS attributes.
|
||||
*
|
||||
* This is a no-op if the given skin index or target is invalid.
|
||||
*/
|
||||
public void detachSkin(@IntRange(from = 0) int skinIndex, @Entity int target) {
|
||||
nDetachSkin(getNativeObject(), skinIndex, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the joint count at skin index in this asset.
|
||||
*/
|
||||
public int getJointCountAt(@IntRange(from = 0) int skinIndex) {
|
||||
return nGetJointCountAt(getNativeObject(), skinIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets joints at skin index in this asset.
|
||||
*/
|
||||
public @NonNull @Entity int[] getJointsAt(@IntRange(from = 0) int skinIndex) {
|
||||
int[] result = new int[getJointCountAt(skinIndex)];
|
||||
nGetJointsAt(getNativeObject(), skinIndex, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the names of all morph targets in the given entity.
|
||||
*/
|
||||
@@ -295,31 +222,6 @@ public class FilamentAsset {
|
||||
return uris;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of all material variants.
|
||||
*/
|
||||
public @NonNull String[] getMaterialVariantNames() {
|
||||
String[] names = new String[nGetMaterialVariantCount(mNativeObject)];
|
||||
nGetMaterialVariantNames(mNativeObject, names);
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given material variant to all primitives that it affects.
|
||||
*
|
||||
* This is efficient because it merely swaps around persistent MaterialInstances. If you change
|
||||
* a material parameter while a certain variant is active, the updated value will be remembered
|
||||
* after you re-apply that variant.
|
||||
*
|
||||
* If the asset is instanced, this affects all instances in the same way.
|
||||
* To set the variant on an individual instance, use FilamentInstance#applyMaterialVariant.
|
||||
*
|
||||
* Ignored if variantIndex is out of bounds.
|
||||
*/
|
||||
public void applyMaterialVariant(@IntRange(from = 0) int variantIndex) {
|
||||
nApplyMaterialVariant(getNativeObject(), variantIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reclaims CPU-side memory for URI strings, binding lists, and raw animation data.
|
||||
*
|
||||
@@ -331,8 +233,10 @@ public class FilamentAsset {
|
||||
nReleaseSourceData(mNativeObject);
|
||||
}
|
||||
|
||||
public Engine getEngine() { return mEngine; }
|
||||
|
||||
void clearNativeObject() {
|
||||
if (mAnimator != null) mAnimator.clearNativeObject();
|
||||
mPrimaryInstance = null;
|
||||
mNativeObject = 0;
|
||||
}
|
||||
|
||||
@@ -356,28 +260,17 @@ public class FilamentAsset {
|
||||
private static native int nGetCameraEntityCount(long nativeAsset);
|
||||
private static native void nGetCameraEntities(long nativeAsset, int[] result);
|
||||
|
||||
private static native int nGetMaterialInstanceCount(long nativeAsset);
|
||||
private static native void nGetMaterialInstances(long nativeAsset, long[] nativeResults);
|
||||
|
||||
private static native int nGetMaterialVariantCount(long nativeAsset);
|
||||
private static native void nGetMaterialVariantNames(long nativeAsset, String[] result);
|
||||
|
||||
private static native int nGetMorphTargetCount(long nativeAsset, int entity);
|
||||
private static native void nGetMorphTargetNames(long nativeAsset, int entity, String[] result);
|
||||
|
||||
private static native void nAttachSkin(long nativeAsset, int skinIndex, int entity);
|
||||
private static native void nDetachSkin(long nativeAsset, int skinIndex, int entity);
|
||||
|
||||
private static native void nGetBoundingBox(long nativeAsset, float[] box);
|
||||
private static native String nGetName(long nativeAsset, int entity);
|
||||
private static native String nGetExtras(long nativeAsset, int entity);
|
||||
private static native long nGetAnimator(long nativeAsset);
|
||||
private static native void nApplyMaterialVariant(long nativeAsset, int variantIndex);
|
||||
private static native int nGetSkinCount(long nativeAsset);
|
||||
private static native void nGetSkinNames(long nativeAsset, String[] result);
|
||||
private static native int nGetJointCountAt(long nativeAsset, int skinIndex);
|
||||
private static native void nGetJointsAt(long nativeAsset, int skinIndex, int[] result);
|
||||
|
||||
private static native long nGetInstance(long nativeAsset);
|
||||
|
||||
private static native int nGetResourceUriCount(long nativeAsset);
|
||||
private static native void nGetResourceUris(long nativeAsset, String[] result);
|
||||
|
||||
private static native void nReleaseSourceData(long nativeAsset);
|
||||
}
|
||||
|
||||
+93
-5
@@ -19,7 +19,9 @@ package com.google.android.filament.gltfio;
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.filament.Engine;
|
||||
import com.google.android.filament.Entity;
|
||||
import com.google.android.filament.MaterialInstance;
|
||||
|
||||
/**
|
||||
* Provides access to a hierarchy of entities that have been instanced from a glTF asset.
|
||||
@@ -85,6 +87,58 @@ public class FilamentInstance {
|
||||
return mAnimator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the skin count of this instance.
|
||||
*/
|
||||
public int getSkinCount() {
|
||||
return nGetSkinCount(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the skin name at skin index in this instance.
|
||||
*/
|
||||
public @NonNull String[] getSkinNames() {
|
||||
String[] result = new String[getSkinCount()];
|
||||
nGetSkinNames(getNativeObject(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the given skin to the given node, which must have an associated mesh with
|
||||
* BONE_INDICES and BONE_WEIGHTS attributes.
|
||||
*
|
||||
* This is a no-op if the given skin index or target is invalid.
|
||||
*/
|
||||
public void attachSkin(@IntRange(from = 0) int skinIndex, @Entity int target) {
|
||||
nAttachSkin(getNativeObject(), skinIndex, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the given skin to the given node, which must have an associated mesh with
|
||||
* BONE_INDICES and BONE_WEIGHTS attributes.
|
||||
*
|
||||
* This is a no-op if the given skin index or target is invalid.
|
||||
*/
|
||||
public void detachSkin(@IntRange(from = 0) int skinIndex, @Entity int target) {
|
||||
nDetachSkin(getNativeObject(), skinIndex, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the joint count at skin index in this instance.
|
||||
*/
|
||||
public int getJointCountAt(@IntRange(from = 0) int skinIndex) {
|
||||
return nGetJointCountAt(getNativeObject(), skinIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets joints at skin index in this instance.
|
||||
*/
|
||||
public @NonNull @Entity int[] getJointsAt(@IntRange(from = 0) int skinIndex) {
|
||||
int[] result = new int[getJointCountAt(skinIndex)];
|
||||
nGetJointsAt(getNativeObject(), skinIndex, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given material variant to all primitives in this instance.
|
||||
*
|
||||
@@ -94,9 +148,43 @@ public class FilamentInstance {
|
||||
nApplyMaterialVariant(mNativeObject, variantIndex);
|
||||
}
|
||||
|
||||
private static native int nGetRoot(long nativeAsset);
|
||||
private static native int nGetEntityCount(long nativeAsset);
|
||||
private static native void nGetEntities(long nativeAsset, int[] result);
|
||||
private static native long nGetAnimator(long nativeAsset);
|
||||
private static native void nApplyMaterialVariant(long nativeAsset, int variantIndex);
|
||||
public @NonNull MaterialInstance[] getMaterialInstances() {
|
||||
final int count = nGetMaterialInstanceCount(mNativeObject);
|
||||
MaterialInstance[] result = new MaterialInstance[count];
|
||||
long[] natives = new long[count];
|
||||
nGetMaterialInstances(mNativeObject, natives);
|
||||
Engine engine = mAsset.getEngine();
|
||||
for (int i = 0; i < count; i++) {
|
||||
result[i] = new MaterialInstance(engine, natives[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of all material variants.
|
||||
*/
|
||||
public @NonNull String[] getMaterialVariantNames() {
|
||||
String[] names = new String[nGetMaterialVariantCount(mNativeObject)];
|
||||
nGetMaterialVariantNames(mNativeObject, names);
|
||||
return names;
|
||||
}
|
||||
|
||||
private static native int nGetRoot(long nativeInstance);
|
||||
private static native int nGetEntityCount(long nativeInstance);
|
||||
private static native void nGetEntities(long nativeInstance, int[] result);
|
||||
private static native long nGetAnimator(long nativeInstance);
|
||||
|
||||
private static native int nGetMaterialInstanceCount(long nativeAsset);
|
||||
private static native void nGetMaterialInstances(long nativeAsset, long[] nativeResults);
|
||||
|
||||
private static native void nApplyMaterialVariant(long nativeInstance, int variantIndex);
|
||||
private static native int nGetMaterialVariantCount(long nativeAsset);
|
||||
private static native void nGetMaterialVariantNames(long nativeAsset, String[] result);
|
||||
|
||||
private static native void nGetJointsAt(long nativeInstance, int skinIndex, int[] result);
|
||||
private static native int nGetSkinCount(long nativeInstance);
|
||||
private static native void nGetSkinNames(long nativeInstance, String[] result);
|
||||
private static native int nGetJointCountAt(long nativeInstance, int skinIndex);
|
||||
private static native void nAttachSkin(long nativeInstance, int skinIndex, int entity);
|
||||
private static native void nDetachSkin(long nativeInstance, int skinIndex, int entity);
|
||||
}
|
||||
|
||||
+10
@@ -24,12 +24,16 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.Size;
|
||||
|
||||
import com.google.android.filament.proguard.UsedByNative;
|
||||
|
||||
@UsedByNative("AssetLoader.cpp")
|
||||
public interface MaterialProvider {
|
||||
|
||||
/**
|
||||
* MaterialKey specifies the requirements for a requested glTF material.
|
||||
* The provider creates Filament materials that fulfill these requirements.
|
||||
*/
|
||||
@UsedByNative("MaterialKey.cpp")
|
||||
public static class MaterialKey {
|
||||
public boolean doubleSided;
|
||||
public boolean unlit;
|
||||
@@ -104,6 +108,12 @@ public interface MaterialProvider {
|
||||
public @Nullable MaterialInstance createMaterialInstance(MaterialKey config,
|
||||
@NonNull @Size(min = 8) int[] uvmap, @Nullable String label, @Nullable String extras);
|
||||
|
||||
/**
|
||||
* Creates or fetches a compiled Filament material corresponding to the given config.
|
||||
*/
|
||||
public @Nullable Material getMaterial(MaterialKey config, @NonNull @Size(min = 8) int[] uvmap,
|
||||
@Nullable String label);
|
||||
|
||||
/**
|
||||
* Creates and returns an array containing all cached materials.
|
||||
*/
|
||||
|
||||
+4
-8
@@ -47,7 +47,7 @@ public class ResourceLoader {
|
||||
*/
|
||||
public ResourceLoader(@NonNull Engine engine) {
|
||||
long nativeEngine = engine.getNativeObject();
|
||||
mNativeObject = nCreateResourceLoader(nativeEngine, false, false, false);
|
||||
mNativeObject = nCreateResourceLoader(nativeEngine, false);
|
||||
mNativeStbProvider = nCreateStbProvider(nativeEngine);
|
||||
mNativeKtx2Provider = nCreateKtx2Provider(nativeEngine);
|
||||
nAddTextureProvider(mNativeObject, "image/jpeg", mNativeStbProvider);
|
||||
@@ -60,16 +60,12 @@ public class ResourceLoader {
|
||||
*
|
||||
* @param engine the engine that gets passed to all builder methods
|
||||
* @param normalizeSkinningWeights scale non-conformant skinning weights so they sum to 1
|
||||
* @param recomputeBoundingBoxes use computed bounding boxes rather than the ones in the asset
|
||||
* @param ignoreBindTransform ignore skinned primitives bind transform when compute bounding boxes
|
||||
* @throws IllegalAccessException
|
||||
* @throws InvocationTargetException
|
||||
*/
|
||||
public ResourceLoader(@NonNull Engine engine, boolean normalizeSkinningWeights,
|
||||
boolean recomputeBoundingBoxes, boolean ignoreBindTransform) {
|
||||
public ResourceLoader(@NonNull Engine engine, boolean normalizeSkinningWeights) {
|
||||
long nativeEngine = engine.getNativeObject();
|
||||
mNativeObject = nCreateResourceLoader(nativeEngine, normalizeSkinningWeights,
|
||||
recomputeBoundingBoxes, ignoreBindTransform);
|
||||
mNativeObject = nCreateResourceLoader(nativeEngine, normalizeSkinningWeights);
|
||||
mNativeStbProvider = nCreateStbProvider(nativeEngine);
|
||||
mNativeKtx2Provider = nCreateKtx2Provider(nativeEngine);
|
||||
nAddTextureProvider(mNativeObject, "image/jpeg", mNativeStbProvider);
|
||||
@@ -181,7 +177,7 @@ public class ResourceLoader {
|
||||
}
|
||||
|
||||
private static native long nCreateResourceLoader(long nativeEngine,
|
||||
boolean normalizeSkinningWeights, boolean recomputeBoundingBoxes, boolean ignoreBindTransform);
|
||||
boolean normalizeSkinningWeights);
|
||||
private static native void nDestroyResourceLoader(long nativeLoader);
|
||||
private static native void nAddResourceData(long nativeLoader, String url, Buffer buffer,
|
||||
int remaining);
|
||||
|
||||
+9
-1
@@ -57,10 +57,16 @@ public class UbershaderProvider implements MaterialProvider {
|
||||
|
||||
public @Nullable MaterialInstance createMaterialInstance(MaterialKey config,
|
||||
@NonNull @Size(min = 8) int[] uvmap, @Nullable String label, @Nullable String extras) {
|
||||
long nativeMaterialInstance = nCreateMaterialInstance(mNativeObject, config, uvmap, label);
|
||||
long nativeMaterialInstance = nCreateMaterialInstance(mNativeObject, config, uvmap, label, extras);
|
||||
return nativeMaterialInstance == 0 ? null : new MaterialInstance(null, nativeMaterialInstance);
|
||||
}
|
||||
|
||||
public @Nullable Material getMaterial(MaterialKey config, @NonNull @Size(min = 8) int[] uvmap,
|
||||
@Nullable String label) {
|
||||
long nativeMaterial = nGetMaterial(mNativeObject, config, uvmap, label);
|
||||
return nativeMaterial == 0 ? null : new Material(nativeMaterial);
|
||||
}
|
||||
|
||||
public @NonNull Material[] getMaterials() {
|
||||
final int count = nGetMaterialCount(mNativeObject);
|
||||
Material[] result = new Material[count];
|
||||
@@ -96,6 +102,8 @@ public class UbershaderProvider implements MaterialProvider {
|
||||
private static native void nDestroyUbershaderProvider(long nativeProvider);
|
||||
private static native void nDestroyMaterials(long nativeProvider);
|
||||
private static native long nCreateMaterialInstance(long nativeProvider,
|
||||
MaterialKey config, int[] uvmap, String label, String extras);
|
||||
private static native long nGetMaterial(long nativeProvider,
|
||||
MaterialKey config, int[] uvmap, String label);
|
||||
private static native int nGetMaterialCount(long nativeProvider);
|
||||
private static native void nGetMaterials(long nativeProvider, long[] result);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.25.5
|
||||
VERSION_NAME=1.28.2
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
@@ -19,10 +19,6 @@ org.gradle.jvmargs=-Xmx1536m
|
||||
|
||||
android.useAndroidX=true
|
||||
|
||||
org.gradle.unsafe.configuration-cache=true
|
||||
# TODO: Remove this when we switch to Gradle 7.4
|
||||
org.gradle.unsafe.configuration-cache.max-problems=3
|
||||
|
||||
com.google.android.filament.tools-dir=../../../out/release/filament
|
||||
com.google.android.filament.dist-dir=../out/android-release/filament
|
||||
com.google.android.filament.abis=all
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#Wed Nov 17 10:40:18 PST 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -112,9 +112,9 @@ the Android SDK.
|
||||
|
||||
## Android Studio
|
||||
|
||||
You must use Android Studio 3.6 RC 1 or higher. To open the project, point Studio to the `android`
|
||||
folder. After opening the project and syncing to gradle, select the sample of your choice using the
|
||||
drop-down widget in the toolbar.
|
||||
You must use the latest stable release of Android Studio. To open the project, point Studio to the
|
||||
`android` folder. After opening the project and syncing to gradle, select the sample of your choice
|
||||
using the drop-down widget in the toolbar.
|
||||
|
||||
## Compiling
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.gltf">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
|
||||
+2
-2
@@ -353,7 +353,7 @@ class MainActivity : Activity() {
|
||||
fun loadSettings(message: RemoteServer.ReceivedMessage) {
|
||||
val json = StandardCharsets.UTF_8.decode(message.buffer).toString()
|
||||
viewerContent.assetLights = modelViewer.asset?.lightEntities
|
||||
automation.applySettings(json, viewerContent)
|
||||
automation.applySettings(modelViewer.engine, json, viewerContent)
|
||||
modelViewer.view.colorGrading = automation.getColorGrading(modelViewer.engine)
|
||||
modelViewer.cameraFocalLength = automation.viewerOptions.cameraFocalLength
|
||||
updateRootTransform()
|
||||
@@ -417,7 +417,7 @@ class MainActivity : Activity() {
|
||||
|
||||
// Just for testing purposes, this releases the current model and reloads the default model.
|
||||
inner class DoubleTapListener : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onDoubleTap(e: MotionEvent?): Boolean {
|
||||
override fun onDoubleTap(e: MotionEvent): Boolean {
|
||||
modelViewer.destroyModel()
|
||||
createDefaultRenderables()
|
||||
return super.onDoubleTap(e)
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.hellocam">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.hellotriangle">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.ibl">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.litcube">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.livewallpaper">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-feature android:name="android.software.live_wallpaper" />
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.material_builder">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.multiview">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.pagecurl">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.streamtest">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.textureview">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.textured">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.transparentrendering">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -1 +1 @@
|
||||
25.0.8775105
|
||||
25.1.8937393
|
||||
Executable
+99
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
function print_help {
|
||||
local self_name=$(basename "$0")
|
||||
echo "This tool verifies that every Metal shader in the given Filament material file(s) successfully compiles."
|
||||
echo "Requires the matinfo tool and xcrun to be on the system PATH."
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " $self_name [options] [<material> ...]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -h"
|
||||
echo " Print this help message."
|
||||
echo " -w"
|
||||
echo " Pass the -w flag to the Metal compiler, to disable warnings."
|
||||
echo ""
|
||||
}
|
||||
|
||||
COMP_FLAGS=""
|
||||
while getopts ":hw" opt; do
|
||||
case ${opt} in
|
||||
h)
|
||||
print_help
|
||||
exit 1
|
||||
;;
|
||||
w)
|
||||
COMP_FLAGS="${COMP_FLAGS} -w"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
if [[ "$#" == "0" ]]; then
|
||||
print_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure matinfo and xcrun are available.
|
||||
if [[ ! $(command -v matinfo) ]]; then
|
||||
echo "Error: matinfo not on PATH."
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! $(command -v xcrun) ]]; then
|
||||
echo "Error: xcrun not on PATH."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function check_material {
|
||||
local material="$1"
|
||||
|
||||
tmpdir="$(mktemp -d /tmp/check_metal_shaders.XXXXX)"
|
||||
|
||||
# First check that the material is valid.
|
||||
if [[ ! $(matinfo "${material}") ]]; then
|
||||
echo "Invalid material file: ${material}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Checking that Metal shaders compile: ${material}"
|
||||
|
||||
set +e
|
||||
local i=0
|
||||
while true; do
|
||||
# The file must have a .metal extension.
|
||||
metalFile="${tmpdir}/${i}.metal"
|
||||
|
||||
# Extract shader i. matinfo will return a non-zero exit code if the shader doesn't exist,
|
||||
# which means we're finished with this material.
|
||||
matinfo --print-metal=${i} "${material}" > "${metalFile}" 2> /dev/null
|
||||
|
||||
if [[ "$?" -ne 0 ]]; then
|
||||
break
|
||||
fi
|
||||
|
||||
echo "Testing Metal shader ${i}"
|
||||
|
||||
# Attempt to compile the Metal shader.
|
||||
xcrun -sdk macosx metal ${COMP_FLAGS} -c "${metalFile}" -o /dev/null
|
||||
|
||||
if [[ "$?" -ne 0 ]]; then
|
||||
echo "Error compiling Metal shader: ${metalFile}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
((i++))
|
||||
done
|
||||
set -e
|
||||
|
||||
rm -r "${tmpdir}"
|
||||
}
|
||||
|
||||
for material in "$@"
|
||||
do
|
||||
check_material "${material}"
|
||||
done
|
||||
|
||||
+8
-12
File diff suppressed because one or more lines are too long
@@ -1143,7 +1143,7 @@ Where $F(v,h)$ is the Fresnel term of the cloth specular BRDF in equation $\ref{
|
||||
Subsurface scattering is implemented using the wrapped diffuse lighting technique, in its energy conservative form:
|
||||
|
||||
$$\begin{equation}
|
||||
f_{d}(v,h) = \frac{c_{diff}}{\pi}(1 - F(v,h)) \left< \NoL + \frac{w}{(1 + w)^2} \right> \left< c_{subsurface} + \NoL \right>
|
||||
f_{d}(v,h) = \frac{c_{diff}}{\pi}(1 - F(v,h)) \left< \frac{\NoL + w}{(1 + w)^2} \right> \left< c_{subsurface} + \NoL \right>
|
||||
\end{equation}$$
|
||||
|
||||
Where $w$ is a value between 0 and 1 defining by how much the diffuse light should wrap around the terminator. To avoid introducing another parameter, we fix $w = 0.5$. Note that with wrap diffuse lighting, the diffuse term must not be multiplied by $\NoL$. The effect of this cheap
|
||||
@@ -1435,7 +1435,7 @@ The term $ \lambda(l) $ in equations $ \ref{spotAbsorber} $ and $ \ref{spotRefle
|
||||
$ \ref{spotAngleAtt} $ below.
|
||||
|
||||
$$\begin{equation}\label{spotAngleAtt}
|
||||
\lambda(l) = \frac{l \times spotDirection - cos\theta_{outer}}{cos\theta_{inner} - cos\theta_{outer}}
|
||||
\lambda(l) = \frac{l \cdot spotDirection - cos\theta_{outer}}{cos\theta_{inner} - cos\theta_{outer}}
|
||||
\end{equation}$$
|
||||
|
||||
#### Attenuation function
|
||||
|
||||
+145
-78
@@ -86,36 +86,39 @@ counter-increment: h6;margin-right:10px}
|
||||
<a href="#materialdefinitions/format/example" class="level3"><span class="tocNumber">4.1.2 </span>Example</a><br>
|
||||
<a href="#materialdefinitions/materialblock" class="level2"><span class="tocNumber">4.2 </span>Material block</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:name" class="level3"><span class="tocNumber">4.2.1 </span>General: name</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:shadingmodel" class="level3"><span class="tocNumber">4.2.2 </span>General: shadingModel</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:parameters" class="level3"><span class="tocNumber">4.2.3 </span>General: parameters</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:variantfilter" class="level3"><span class="tocNumber">4.2.4 </span>General: variantFilter</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:flipuv" class="level3"><span class="tocNumber">4.2.5 </span>General: flipUV</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:quality" class="level3"><span class="tocNumber">4.2.6 </span>General: quality</a><br>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:requires" class="level3"><span class="tocNumber">4.2.7 </span>Vertex and attributes: requires</a><br>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:variables" class="level3"><span class="tocNumber">4.2.8 </span>Vertex and attributes: variables</a><br>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:vertexdomain" class="level3"><span class="tocNumber">4.2.9 </span>Vertex and attributes: vertexDomain</a><br>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:interpolation" class="level3"><span class="tocNumber">4.2.10 </span>Vertex and attributes: interpolation</a><br>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:blending" class="level3"><span class="tocNumber">4.2.11 </span>Blending and transparency: blending</a><br>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:postlightingblending" class="level3"><span class="tocNumber">4.2.12 </span>Blending and transparency: postLightingBlending</a><br>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:transparency" class="level3"><span class="tocNumber">4.2.13 </span>Blending and transparency: transparency</a><br>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:maskthreshold" class="level3"><span class="tocNumber">4.2.14 </span>Blending and transparency: maskThreshold</a><br>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:refractionmode" class="level3"><span class="tocNumber">4.2.15 </span>Blending and transparency: refractionMode</a><br>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:refractiontype" class="level3"><span class="tocNumber">4.2.16 </span>Blending and transparency: refractionType</a><br>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:culling" class="level3"><span class="tocNumber">4.2.17 </span>Rasterization: culling</a><br>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:colorwrite" class="level3"><span class="tocNumber">4.2.18 </span>Rasterization: colorWrite</a><br>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:depthwrite" class="level3"><span class="tocNumber">4.2.19 </span>Rasterization: depthWrite</a><br>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:depthculling" class="level3"><span class="tocNumber">4.2.20 </span>Rasterization: depthCulling</a><br>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:doublesided" class="level3"><span class="tocNumber">4.2.21 </span>Rasterization: doubleSided</a><br>
|
||||
<a href="#materialdefinitions/materialblock/lighting:reflections" class="level3"><span class="tocNumber">4.2.22 </span>Lighting: reflections</a><br>
|
||||
<a href="#materialdefinitions/materialblock/lighting:shadowmultiplier" class="level3"><span class="tocNumber">4.2.23 </span>Lighting: shadowMultiplier</a><br>
|
||||
<a href="#materialdefinitions/materialblock/lighting:transparentshadow" class="level3"><span class="tocNumber">4.2.24 </span>Lighting: transparentShadow</a><br>
|
||||
<a href="#materialdefinitions/materialblock/lighting:clearcoatiorchange" class="level3"><span class="tocNumber">4.2.25 </span>Lighting: clearCoatIorChange</a><br>
|
||||
<a href="#materialdefinitions/materialblock/lighting:multibounceambientocclusion" class="level3"><span class="tocNumber">4.2.26 </span>Lighting: multiBounceAmbientOcclusion</a><br>
|
||||
<a href="#materialdefinitions/materialblock/lighting:specularambientocclusion" class="level3"><span class="tocNumber">4.2.27 </span>Lighting: specularAmbientOcclusion</a><br>
|
||||
<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasing" class="level3"><span class="tocNumber">4.2.28 </span>Anti-aliasing: specularAntiAliasing</a><br>
|
||||
<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasingvariance" class="level3"><span class="tocNumber">4.2.29 </span>Anti-aliasing: specularAntiAliasingVariance</a><br>
|
||||
<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasingthreshold" class="level3"><span class="tocNumber">4.2.30 </span>Anti-aliasing: specularAntiAliasingThreshold</a><br>
|
||||
<a href="#materialdefinitions/materialblock/shading:customsurfaceshading" class="level3"><span class="tocNumber">4.2.31 </span>Shading: customSurfaceShading</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:featurelevel" class="level3"><span class="tocNumber">4.2.2 </span>General: featureLevel</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:shadingmodel" class="level3"><span class="tocNumber">4.2.3 </span>General: shadingModel</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:parameters" class="level3"><span class="tocNumber">4.2.4 </span>General: parameters</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:variantfilter" class="level3"><span class="tocNumber">4.2.5 </span>General: variantFilter</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:flipuv" class="level3"><span class="tocNumber">4.2.6 </span>General: flipUV</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:quality" class="level3"><span class="tocNumber">4.2.7 </span>General: quality</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:instanced" class="level3"><span class="tocNumber">4.2.8 </span>General: instanced</a><br>
|
||||
<a href="#materialdefinitions/materialblock/general:vertexdomaindevicejittered" class="level3"><span class="tocNumber">4.2.9 </span>General: vertexDomainDeviceJittered</a><br>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:requires" class="level3"><span class="tocNumber">4.2.10 </span>Vertex and attributes: requires</a><br>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:variables" class="level3"><span class="tocNumber">4.2.11 </span>Vertex and attributes: variables</a><br>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:vertexdomain" class="level3"><span class="tocNumber">4.2.12 </span>Vertex and attributes: vertexDomain</a><br>
|
||||
<a href="#materialdefinitions/materialblock/vertexandattributes:interpolation" class="level3"><span class="tocNumber">4.2.13 </span>Vertex and attributes: interpolation</a><br>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:blending" class="level3"><span class="tocNumber">4.2.14 </span>Blending and transparency: blending</a><br>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:postlightingblending" class="level3"><span class="tocNumber">4.2.15 </span>Blending and transparency: postLightingBlending</a><br>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:transparency" class="level3"><span class="tocNumber">4.2.16 </span>Blending and transparency: transparency</a><br>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:maskthreshold" class="level3"><span class="tocNumber">4.2.17 </span>Blending and transparency: maskThreshold</a><br>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:refractionmode" class="level3"><span class="tocNumber">4.2.18 </span>Blending and transparency: refractionMode</a><br>
|
||||
<a href="#materialdefinitions/materialblock/blendingandtransparency:refractiontype" class="level3"><span class="tocNumber">4.2.19 </span>Blending and transparency: refractionType</a><br>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:culling" class="level3"><span class="tocNumber">4.2.20 </span>Rasterization: culling</a><br>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:colorwrite" class="level3"><span class="tocNumber">4.2.21 </span>Rasterization: colorWrite</a><br>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:depthwrite" class="level3"><span class="tocNumber">4.2.22 </span>Rasterization: depthWrite</a><br>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:depthculling" class="level3"><span class="tocNumber">4.2.23 </span>Rasterization: depthCulling</a><br>
|
||||
<a href="#materialdefinitions/materialblock/rasterization:doublesided" class="level3"><span class="tocNumber">4.2.24 </span>Rasterization: doubleSided</a><br>
|
||||
<a href="#materialdefinitions/materialblock/lighting:reflections" class="level3"><span class="tocNumber">4.2.25 </span>Lighting: reflections</a><br>
|
||||
<a href="#materialdefinitions/materialblock/lighting:shadowmultiplier" class="level3"><span class="tocNumber">4.2.26 </span>Lighting: shadowMultiplier</a><br>
|
||||
<a href="#materialdefinitions/materialblock/lighting:transparentshadow" class="level3"><span class="tocNumber">4.2.27 </span>Lighting: transparentShadow</a><br>
|
||||
<a href="#materialdefinitions/materialblock/lighting:clearcoatiorchange" class="level3"><span class="tocNumber">4.2.28 </span>Lighting: clearCoatIorChange</a><br>
|
||||
<a href="#materialdefinitions/materialblock/lighting:multibounceambientocclusion" class="level3"><span class="tocNumber">4.2.29 </span>Lighting: multiBounceAmbientOcclusion</a><br>
|
||||
<a href="#materialdefinitions/materialblock/lighting:specularambientocclusion" class="level3"><span class="tocNumber">4.2.30 </span>Lighting: specularAmbientOcclusion</a><br>
|
||||
<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasing" class="level3"><span class="tocNumber">4.2.31 </span>Anti-aliasing: specularAntiAliasing</a><br>
|
||||
<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasingvariance" class="level3"><span class="tocNumber">4.2.32 </span>Anti-aliasing: specularAntiAliasingVariance</a><br>
|
||||
<a href="#materialdefinitions/materialblock/anti-aliasing:specularantialiasingthreshold" class="level3"><span class="tocNumber">4.2.33 </span>Anti-aliasing: specularAntiAliasingThreshold</a><br>
|
||||
<a href="#materialdefinitions/materialblock/shading:customsurfaceshading" class="level3"><span class="tocNumber">4.2.34 </span>Shading: customSurfaceShading</a><br>
|
||||
<a href="#materialdefinitions/vertexblock" class="level2"><span class="tocNumber">4.3 </span>Vertex block</a><br>
|
||||
<a href="#materialdefinitions/vertexblock/materialvertexinputs" class="level3"><span class="tocNumber">4.3.1 </span>Material vertex inputs</a><br>
|
||||
<a href="#materialdefinitions/vertexblock/customvertexattributes" class="level3"><span class="tocNumber">4.3.2 </span>Custom vertex attributes</a><br>
|
||||
@@ -775,7 +778,7 @@ and with (right)</span></center></div></center>
|
||||
|
||||
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.27">4.2.27</a> about
|
||||
specular ambient occlusion (see section <a href="#toc4.2.30">4.2.30</a> about
|
||||
<code>specularAmbientOcclusion</code>).
|
||||
|
||||
</p><p>
|
||||
@@ -890,7 +893,7 @@ light to bend further away from the initial path.
|
||||
<p></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.16">4.2.16</a> and section <a href="#toc4.2.15">4.2.15</a>
|
||||
<code>refractionMode</code> settings of the material. Refer to section <a href="#toc4.2.19">4.2.19</a> and section <a href="#toc4.2.18">4.2.18</a>
|
||||
for more information.
|
||||
|
||||
</p><p>
|
||||
@@ -1423,7 +1426,36 @@ non-shader data.
|
||||
<span class="line">material {</span>
|
||||
<span class="line"> name : <span class="hljs-string">"Wet pavement"</span></span>
|
||||
<span class="line">}</span></code></pre>
|
||||
<a class="target" name="general:shadingmodel"> </a><a class="target" name="materialdefinitions/materialblock/general:shadingmodel"> </a><a class="target" name="toc4.2.2"> </a><h3>General: shadingModel</h3>
|
||||
<a class="target" name="general:featurelevel"> </a><a class="target" name="materialdefinitions/materialblock/general:featurelevel"> </a><a class="target" name="toc4.2.2"> </a><h3>General: featureLevel</h3>
|
||||
<p>
|
||||
|
||||
|
||||
</p><dl><table><tbody><tr valign="top"><td><dt>Type</dt></td><td><dd><p> <code>number</code>
|
||||
|
||||
</p></dd></td></tr><tr valign="top"><td><dt>Value</dt></td><td><dd><p> An integer value, either 1, 2 or 3. Defaults to 1.
|
||||
|
||||
</p></dd></td></tr></tbody></table></dl><div class="table">
|
||||
<table class="table"><tbody><tr><th style="text-align:left"> Feature Level </th><th style="text-align:left"> Guaranteed features </th></tr>
|
||||
<tr><td style="text-align:left"> 1 </td><td style="text-align:left"> 9 textures per material </td></tr>
|
||||
<tr><td style="text-align:left"> 2 </td><td style="text-align:left"> 9 textures per material, cubemap arrays, ESSL 3.10 </td></tr>
|
||||
<tr><td style="text-align:left"> 3 </td><td style="text-align:left"> 12 textures per material, cubemap arrays, ESSL 3.10 </td></tr>
|
||||
</tbody></table><center><div class="tablecaption"><a class="target" name="table_featurelevels"> </a><b style="font-style:normal;">Table 13:</b> Feature levels</div></center></div>
|
||||
|
||||
<p></p><p>
|
||||
|
||||
</p><dl><dt>Description</dt><dd><p> Sets the feature level of the material. Each feature level defines a set of features the
|
||||
material can use. If the material uses a feature not supported by the selected level, <code>matc</code>
|
||||
will generate an error during compilation. A given feature level is guaranteed to support
|
||||
all features of lower feature levels.
|
||||
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> featureLevel : <span class="hljs-number">2</span></span>
|
||||
<span class="line">}</span></code></pre><p>
|
||||
|
||||
</p><dl><table><tbody><tr valign="top"><td><dt>Bugs</dt></td><td><dd><p> <code>matc</code> doesn't verify that a material is not using features above its selected feature level.
|
||||
|
||||
</p></dd></td></tr></tbody></table></dl><p></p>
|
||||
<a class="target" name="general:shadingmodel"> </a><a class="target" name="materialdefinitions/materialblock/general:shadingmodel"> </a><a class="target" name="toc4.2.3"> </a><h3>General: shadingModel</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1440,7 +1472,7 @@ non-shader data.
|
||||
<span class="line">material {</span>
|
||||
<span class="line"> shadingModel : <span class="hljs-string">"subsurface"</span></span>
|
||||
<span class="line">}</span></code></pre>
|
||||
<a class="target" name="general:parameters"> </a><a class="target" name="materialdefinitions/materialblock/general:parameters"> </a><a class="target" name="toc4.2.3"> </a><h3>General: parameters</h3>
|
||||
<a class="target" name="general:parameters"> </a><a class="target" name="materialdefinitions/materialblock/general:parameters"> </a><a class="target" name="toc4.2.4"> </a><h3>General: parameters</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1450,7 +1482,7 @@ non-shader data.
|
||||
name must be a valid GLSL identifier. Entries also have an optional <code>precision</code>, which can be
|
||||
one of <code>default</code> (best precision for the platform, typically <code>high</code> on desktop, <code>medium</code> on
|
||||
mobile), <code>low</code>, <code>medium</code>, <code>high</code>. The type must be one of the types described in
|
||||
<a href="#table_materialparamstypes">table 13</a>.
|
||||
<a href="#table_materialparamstypes">table 14</a>.
|
||||
|
||||
</p></dd></dl><div class="table">
|
||||
<table class="table"><tbody><tr><th style="text-align:left"> Type </th><th style="text-align:left"> Description </th></tr>
|
||||
@@ -1473,9 +1505,10 @@ non-shader data.
|
||||
<tr><td style="text-align:left"> float3×3 </td><td style="text-align:left"> Matrix of 3×3 floats </td></tr>
|
||||
<tr><td style="text-align:left"> float4×4 </td><td style="text-align:left"> Matrix of 4×4 floats </td></tr>
|
||||
<tr><td style="text-align:left"> sampler2d </td><td style="text-align:left"> 2D texture </td></tr>
|
||||
<tr><td style="text-align:left"> sampler2dArray </td><td style="text-align:left"> Array of 2D textures </td></tr>
|
||||
<tr><td style="text-align:left"> samplerExternal </td><td style="text-align:left"> External texture (platform-specific) </td></tr>
|
||||
<tr><td style="text-align:left"> samplerCubemap </td><td style="text-align:left"> Cubemap texture </td></tr>
|
||||
</tbody></table><center><div class="tablecaption"><a class="target" name="table_materialparamstypes"> </a><b style="font-style:normal;">Table 13:</b> Material parameter types</div></center></div>
|
||||
</tbody></table><center><div class="tablecaption"><a class="target" name="table_materialparamstypes"> </a><b style="font-style:normal;">Table 14:</b> Material parameter types</div></center></div>
|
||||
|
||||
<p></p><p>
|
||||
|
||||
@@ -1484,7 +1517,7 @@ non-shader data.
|
||||
|
||||
</p></dd><dt>Arrays</dt><dd><p> A parameter can define an array of values by appending <code>[size]</code> after the type name, where
|
||||
<code>size</code> is a positive integer. For instance: <code>float[9]</code> declares an array of nine <code>float</code>
|
||||
values. Arrays of samplers are <em class="underscore">not</em> supported at the moment.
|
||||
values. This syntax does not apply to samplers as arrays are treated as separate types.
|
||||
|
||||
</p></dd><dt>Description</dt><dd><p> Lists the parameters required by your material. These parameters can be set at runtime using
|
||||
Filament's material API. Accessing parameters from the shaders varies depending on the type of
|
||||
@@ -1531,7 +1564,7 @@ non-shader data.
|
||||
<span class="line"> material.reflectance = materialParams.metallicReflectance.y;</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line">}</span></code></pre>
|
||||
<a class="target" name="general:variantfilter"> </a><a class="target" name="materialdefinitions/materialblock/general:variantfilter"> </a><a class="target" name="toc4.2.4"> </a><h3>General: variantFilter</h3>
|
||||
<a class="target" name="general:variantfilter"> </a><a class="target" name="materialdefinitions/materialblock/general:variantfilter"> </a><a class="target" name="toc4.2.5"> </a><h3>General: variantFilter</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1573,7 +1606,7 @@ non-shader data.
|
||||
<span class="line"> blending : transparent,</span>
|
||||
<span class="line"> variantFilter : [ skinning ]</span>
|
||||
<span class="line">}</span></code></pre>
|
||||
<a class="target" name="general:flipuv"> </a><a class="target" name="materialdefinitions/materialblock/general:flipuv"> </a><a class="target" name="toc4.2.5"> </a><h3>General: flipUV</h3>
|
||||
<a class="target" name="general:flipuv"> </a><a class="target" name="materialdefinitions/materialblock/general:flipuv"> </a><a class="target" name="toc4.2.6"> </a><h3>General: flipUV</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1588,7 +1621,7 @@ non-shader data.
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> flipUV : <span class="hljs-literal">false</span></span>
|
||||
<span class="line">}</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.6"> </a><h3>General: quality</h3>
|
||||
<a class="target" name="general:quality"> </a><a class="target" name="materialdefinitions/materialblock/general:quality"> </a><a class="target" name="toc4.2.7"> </a><h3>General: quality</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1604,7 +1637,43 @@ non-shader data.
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> quality : default</span>
|
||||
<span class="line">}</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.7"> </a><h3>Vertex and attributes: requires</h3>
|
||||
<a class="target" name="general:instanced"> </a><a class="target" name="materialdefinitions/materialblock/general:instanced"> </a><a class="target" name="toc4.2.8"> </a><h3>General: instanced</h3>
|
||||
<p>
|
||||
|
||||
|
||||
</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> Allows a material to access the instance index (i.e.: <strong class="asterisk"><code>gl_InstanceIndex</code></strong>) of instanced
|
||||
primitives using <code>getInstanceIndex()</code> in the material's shader code. Never use
|
||||
<strong class="asterisk"><code>gl_InstanceIndex</code></strong> directly. This is typically used with
|
||||
<code>RenderableManager::Builder::instances()</code>. <code>getInstanceIndex()</code> is available in both the
|
||||
vertex and fragment shader.
|
||||
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> instanced : <span class="hljs-literal">true</span></span>
|
||||
<span class="line">}</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.9"> </a><h3>General: vertexDomainDeviceJittered</h3>
|
||||
<p>
|
||||
|
||||
|
||||
</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> Only meaningful for <code>vertexDomain:Device</code> materials, this parameter specifies whether the
|
||||
filament clip-space transforms need to be applied or not, which affects TAA and guard bands.
|
||||
Generally it needs to be applied because by definition <code>vertexDomain:Device</code> materials
|
||||
vertices are not transformed and used <em class="asterisk">as is</em>.
|
||||
However, if the vertex shader uses for instance <code>getViewFromClipMatrix()</code> (or other
|
||||
matrices based on the projection), the clip-space transform is already applied.
|
||||
Setting this parameter incorrectly can prevent TAA or the guard bands to work correctly.
|
||||
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> vertexDomainDeviceJittered : <span class="hljs-literal">true</span></span>
|
||||
<span class="line">}</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.10"> </a><h3>Vertex and attributes: requires</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1639,7 +1708,7 @@ non-shader data.
|
||||
<span class="line"> material.baseColor.rgb *= getCustom0().rgb;</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line">}</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.8"> </a><h3>Vertex and attributes: variables</h3>
|
||||
<a class="target" name="vertexandattributes:variables"> </a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:variables"> </a><a class="target" name="toc4.2.11"> </a><h3>Vertex and attributes: variables</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1686,7 +1755,7 @@ non-shader data.
|
||||
<span class="line"> material.eyeDirection.xyz = mulMat3x3Float3(getWorldFromViewMatrix(), u);</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line">}</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.9"> </a><h3>Vertex and attributes: vertexDomain</h3>
|
||||
<a class="target" name="vertexandattributes:vertexdomain"> </a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:vertexdomain"> </a><a class="target" name="toc4.2.12"> </a><h3>Vertex and attributes: vertexDomain</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1715,7 +1784,7 @@ non-shader data.
|
||||
<p></p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> vertexDomain : device</span>
|
||||
<span class="line">}</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.10"> </a><h3>Vertex and attributes: interpolation</h3>
|
||||
<a class="target" name="vertexandattributes:interpolation"> </a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:interpolation"> </a><a class="target" name="toc4.2.13"> </a><h3>Vertex and attributes: interpolation</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1731,7 +1800,7 @@ non-shader data.
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> interpolation : flat</span>
|
||||
<span class="line">}</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.11"> </a><h3>Blending and transparency: blending</h3>
|
||||
<a class="target" name="blendingandtransparency:blending"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:blending"> </a><a class="target" name="toc4.2.14"> </a><h3>Blending and transparency: blending</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1772,7 +1841,7 @@ non-shader data.
|
||||
<p></p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> blending : transparent</span>
|
||||
<span class="line">}</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.12"> </a><h3>Blending and transparency: postLightingBlending</h3>
|
||||
<a class="target" name="blendingandtransparency:postlightingblending"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:postlightingblending"> </a><a class="target" name="toc4.2.15"> </a><h3>Blending and transparency: postLightingBlending</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1802,7 +1871,7 @@ non-shader data.
|
||||
<p></p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> postLightingBlending : add</span>
|
||||
<span class="line">}</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.13"> </a><h3>Blending and transparency: transparency</h3>
|
||||
<a class="target" name="blendingandtransparency:transparency"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:transparency"> </a><a class="target" name="toc4.2.16"> </a><h3>Blending and transparency: transparency</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1849,7 +1918,7 @@ and correctly sorted</span></center></div></center>
|
||||
and sorting issues are minimized or eliminated</span></center></div></center>
|
||||
|
||||
<p></p>
|
||||
<a class="target" name="blendingandtransparency:maskthreshold"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:maskthreshold"> </a><a class="target" name="toc4.2.14"> </a><h3>Blending and transparency: maskThreshold</h3>
|
||||
<a class="target" name="blendingandtransparency:maskthreshold"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:maskthreshold"> </a><a class="target" name="toc4.2.17"> </a><h3>Blending and transparency: maskThreshold</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1866,7 +1935,7 @@ and sorting issues are minimized or eliminated</span></center></div></center>
|
||||
<span class="line"> blending : masked,</span>
|
||||
<span class="line"> maskThreshold : <span class="hljs-number">0.5</span></span>
|
||||
<span class="line">}</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.15"> </a><h3>Blending and transparency: refractionMode</h3>
|
||||
<a class="target" name="blendingandtransparency:refractionmode"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:refractionmode"> </a><a class="target" name="toc4.2.18"> </a><h3>Blending and transparency: refractionMode</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1887,7 +1956,7 @@ and sorting issues are minimized or eliminated</span></center></div></center>
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> refractionMode : cubemap,</span>
|
||||
<span class="line">}</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.16"> </a><h3>Blending and transparency: refractionType</h3>
|
||||
<a class="target" name="blendingandtransparency:refractiontype"> </a><a class="target" name="materialdefinitions/materialblock/blendingandtransparency:refractiontype"> </a><a class="target" name="toc4.2.19"> </a><h3>Blending and transparency: refractionType</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1906,7 +1975,7 @@ and sorting issues are minimized or eliminated</span></center></div></center>
|
||||
<span class="line"> refractionMode : cubemap,</span>
|
||||
<span class="line"> refractionType : thin,</span>
|
||||
<span class="line">}</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.17"> </a><h3>Rasterization: culling</h3>
|
||||
<a class="target" name="rasterization:culling"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:culling"> </a><a class="target" name="toc4.2.20"> </a><h3>Rasterization: culling</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1920,7 +1989,7 @@ and sorting issues are minimized or eliminated</span></center></div></center>
|
||||
</p></dd></td></tr></tbody></table></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> culling : none</span>
|
||||
<span class="line">}</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.18"> </a><h3>Rasterization: colorWrite</h3>
|
||||
<a class="target" name="rasterization:colorwrite"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:colorwrite"> </a><a class="target" name="toc4.2.21"> </a><h3>Rasterization: colorWrite</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1933,7 +2002,7 @@ and sorting issues are minimized or eliminated</span></center></div></center>
|
||||
</p></dd></td></tr></tbody></table></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> colorWrite : <span class="hljs-literal">false</span></span>
|
||||
<span class="line">}</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.19"> </a><h3>Rasterization: depthWrite</h3>
|
||||
<a class="target" name="rasterization:depthwrite"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:depthwrite"> </a><a class="target" name="toc4.2.22"> </a><h3>Rasterization: depthWrite</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1946,7 +2015,7 @@ and sorting issues are minimized or eliminated</span></center></div></center>
|
||||
</p></dd></td></tr></tbody></table></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> depthWrite : <span class="hljs-literal">false</span></span>
|
||||
<span class="line">}</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.20"> </a><h3>Rasterization: depthCulling</h3>
|
||||
<a class="target" name="rasterization:depthculling"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:depthculling"> </a><a class="target" name="toc4.2.23"> </a><h3>Rasterization: depthCulling</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1960,7 +2029,7 @@ and sorting issues are minimized or eliminated</span></center></div></center>
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> depthCulling : <span class="hljs-literal">false</span></span>
|
||||
<span class="line">}</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.21"> </a><h3>Rasterization: doubleSided</h3>
|
||||
<a class="target" name="rasterization:doublesided"> </a><a class="target" name="materialdefinitions/materialblock/rasterization:doublesided"> </a><a class="target" name="toc4.2.24"> </a><h3>Rasterization: doubleSided</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -1968,26 +2037,24 @@ and sorting issues are minimized or eliminated</span></center></div></center>
|
||||
|
||||
</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> Only available in the <code>unlit</code> shading model. If this property is enabled, the final color
|
||||
computed by the material is multiplied by the shadowing factor (or visibility). This allows to
|
||||
create transparent shadow-receiving objects (for instance an invisible ground plane in AR).
|
||||
This is only supported with shadows from directional lights.
|
||||
</p></dd><dt>Description</dt><dd><p> Enables two-sided rendering and its capability to be toggled at run time. When set to <code>true</code>,
|
||||
<code>culling</code> is automatically set to <code>none</code>; if the triangle is back-facing, the triangle's
|
||||
normal is flipped to become front-facing. When explicitly set to <code>false</code>, this allows the
|
||||
double-sidedness to be toggled at run time.
|
||||
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> name : <span class="hljs-string">"Invisible shadow plane"</span>,</span>
|
||||
<span class="line"> shadingModel : unlit,</span>
|
||||
<span class="line"> shadowMultiplier : <span class="hljs-literal">true</span>,</span>
|
||||
<span class="line"> blending : transparent</span>
|
||||
<span class="line"> name : <span class="hljs-string">"Double sided material"</span>,</span>
|
||||
<span class="line"> shadingModel : lit,</span>
|
||||
<span class="line"> doubleSided : <span class="hljs-literal">true</span></span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line">fragment {</span>
|
||||
<span class="line"> void material(inout MaterialInputs material) {</span>
|
||||
<span class="line"> prepareMaterial(material);</span>
|
||||
<span class="line"> <span class="hljs-comment">// baseColor defines the color and opacity of the final shadow</span></span>
|
||||
<span class="line"> material.baseColor = vec4(0.0, 0.0, 0.0, 0.7);</span>
|
||||
<span class="line"> material.baseColor = materialParams.albedo;</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line">}</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.22"> </a><h3>Lighting: reflections</h3>
|
||||
<a class="target" name="lighting:reflections"> </a><a class="target" name="materialdefinitions/materialblock/lighting:reflections"> </a><a class="target" name="toc4.2.25"> </a><h3>Lighting: reflections</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -2004,7 +2071,7 @@ and sorting issues are minimized or eliminated</span></center></div></center>
|
||||
<span class="line"> name : <span class="hljs-string">"Glossy metal"</span>,</span>
|
||||
<span class="line"> reflections : screenspace</span>
|
||||
<span class="line">}</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.23"> </a><h3>Lighting: shadowMultiplier</h3>
|
||||
<a class="target" name="lighting:shadowmultiplier"> </a><a class="target" name="materialdefinitions/materialblock/lighting:shadowmultiplier"> </a><a class="target" name="toc4.2.26"> </a><h3>Lighting: shadowMultiplier</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -2031,7 +2098,7 @@ and sorting issues are minimized or eliminated</span></center></div></center>
|
||||
<span class="line"> material.baseColor = vec4(0.0, 0.0, 0.0, 0.7);</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line">}</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.24"> </a><h3>Lighting: transparentShadow</h3>
|
||||
<a class="target" name="lighting:transparentshadow"> </a><a class="target" name="materialdefinitions/materialblock/lighting:transparentshadow"> </a><a class="target" name="toc4.2.27"> </a><h3>Lighting: transparentShadow</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -2065,7 +2132,7 @@ radius of 4. Model <a href="https://sketchfab.com/3d-models/bottle-of-water-48fd
|
||||
by <a href="https://sketchfab.com/person-x">T-Art</a>.</span></center></div></center>
|
||||
|
||||
<p></p>
|
||||
<a class="target" name="lighting:clearcoatiorchange"> </a><a class="target" name="materialdefinitions/materialblock/lighting:clearcoatiorchange"> </a><a class="target" name="toc4.2.25"> </a><h3>Lighting: clearCoatIorChange</h3>
|
||||
<a class="target" name="lighting:clearcoatiorchange"> </a><a class="target" name="materialdefinitions/materialblock/lighting:clearcoatiorchange"> </a><a class="target" name="toc4.2.28"> </a><h3>Lighting: clearCoatIorChange</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -2087,7 +2154,7 @@ with <code>clearCoatIorChange</code> enabled (left) and disabled
|
||||
(right).</span></center></div></center>
|
||||
|
||||
<p></p>
|
||||
<a class="target" name="lighting:multibounceambientocclusion"> </a><a class="target" name="materialdefinitions/materialblock/lighting:multibounceambientocclusion"> </a><a class="target" name="toc4.2.26"> </a><h3>Lighting: multiBounceAmbientOcclusion</h3>
|
||||
<a class="target" name="lighting:multibounceambientocclusion"> </a><a class="target" name="materialdefinitions/materialblock/lighting:multibounceambientocclusion"> </a><a class="target" name="toc4.2.29"> </a><h3>Lighting: multiBounceAmbientOcclusion</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -2116,7 +2183,7 @@ occclusion enabled (left) and disabled (right).</span></center></div></center>
|
||||
occclusion enabled and disabled.</span></center></div></center>
|
||||
|
||||
<p></p>
|
||||
<a class="target" name="lighting:specularambientocclusion"> </a><a class="target" name="materialdefinitions/materialblock/lighting:specularambientocclusion"> </a><a class="target" name="toc4.2.27"> </a><h3>Lighting: specularAmbientOcclusion</h3>
|
||||
<a class="target" name="lighting:specularambientocclusion"> </a><a class="target" name="materialdefinitions/materialblock/lighting:specularambientocclusion"> </a><a class="target" name="toc4.2.30"> </a><h3>Lighting: specularAmbientOcclusion</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -2142,7 +2209,7 @@ occclusion enabled and disabled.</span></center></div></center>
|
||||
particularly visible under the hose.</span></center></div></center>
|
||||
|
||||
<p></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.28"> </a><h3>Anti-aliasing: specularAntiAliasing</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.31"> </a><h3>Anti-aliasing: specularAntiAliasing</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -2159,7 +2226,7 @@ particularly visible under the hose.</span></center></div></center>
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> specularAntiAliasing : <span class="hljs-literal">true</span></span>
|
||||
<span class="line">}</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.29"> </a><h3>Anti-aliasing: specularAntiAliasingVariance</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.32"> </a><h3>Anti-aliasing: specularAntiAliasingVariance</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -2174,7 +2241,7 @@ particularly visible under the hose.</span></center></div></center>
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> specularAntiAliasingVariance : <span class="hljs-number">0.2</span></span>
|
||||
<span class="line">}</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.30"> </a><h3>Anti-aliasing: specularAntiAliasingThreshold</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.33"> </a><h3>Anti-aliasing: specularAntiAliasingThreshold</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -2188,7 +2255,7 @@ particularly visible under the hose.</span></center></div></center>
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> specularAntiAliasingThreshold : <span class="hljs-number">0.1</span></span>
|
||||
<span class="line">}</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.31"> </a><h3>Shading: customSurfaceShading</h3>
|
||||
<a class="target" name="shading:customsurfaceshading"> </a><a class="target" name="materialdefinitions/materialblock/shading:customsurfaceshading"> </a><a class="target" name="toc4.2.34"> </a><h3>Shading: customSurfaceShading</h3>
|
||||
<p>
|
||||
|
||||
|
||||
@@ -2252,7 +2319,7 @@ APIs listed in the <a href="#shaderpublicapis">Shader public APIs</a> section.
|
||||
<span class="line"> float3 worldNormal; <span class="hljs-comment">// only if the shading model is not unlit</span></span>
|
||||
<span class="line"> float4 worldPosition; <span class="hljs-comment">// always available (see note below about world-space)</span></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-type">mat4</span> clipSpaceTransform; <span class="hljs-comment">// default: identity, transforms the clip-space position</span></span>
|
||||
<span class="line"> <span class="hljs-type">mat4</span> clipSpaceTransform; <span class="hljs-comment">// default: identity, transforms the clip-space position, only available for `vertexDomain:device`</span></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-comment">// variable* names are replaced with actual names</span></span>
|
||||
<span class="line"> float4 variable0; <span class="hljs-comment">// if 1 or more variables is defined</span></span>
|
||||
@@ -2747,7 +2814,7 @@ source material definition file.
|
||||
<p>
|
||||
|
||||
|
||||
The command line flags relevant to application development are described in <a href="#table_matcflags">table 14</a>.
|
||||
The command line flags relevant to application development are described in <a href="#table_matcflags">table 15</a>.
|
||||
</p><div class="table">
|
||||
<table class="table"><tbody><tr><th style="text-align:right"> Flag </th><th style="text-align:center"> Value </th><th style="text-align:left"> Usage </th></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">-o</strong>, <strong class="asterisk">—output</strong> </td><td style="text-align:center"> [path] </td><td style="text-align:left"> Specify the output file path </td></tr>
|
||||
@@ -2756,7 +2823,7 @@ The command line flags relevant to application development are described in <a h
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">-S</strong>, <strong class="asterisk">—optimize-size</strong> </td><td style="text-align:center"> N/A </td><td style="text-align:left"> Optimize compiled material for size instead of just performance </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">-r</strong>, <strong class="asterisk">—reflect</strong> </td><td style="text-align:center"> parameters </td><td style="text-align:left"> Outputs the specified metadata as JSON </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">-v</strong>, <strong class="asterisk">—variant-filter</strong> </td><td style="text-align:center"> [variant] </td><td style="text-align:left"> Filters out the specified, comma-separated variants </td></tr>
|
||||
</tbody></table><center><div class="tablecaption"><a class="target" name="table_matcflags"> </a><b style="font-style:normal;">Table 14:</b> List of <code>matc</code> flags</div></center></div>
|
||||
</tbody></table><center><div class="tablecaption"><a class="target" name="table_matcflags"> </a><b style="font-style:normal;">Table 15:</b> List of <code>matc</code> flags</div></center></div>
|
||||
|
||||
<p></p><p>
|
||||
|
||||
|
||||
+65
-12
@@ -932,6 +932,37 @@ material {
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### General: featureLevel
|
||||
|
||||
Type
|
||||
: `number`
|
||||
|
||||
Value
|
||||
: An integer value, either 1, 2 or 3. Defaults to 1.
|
||||
|
||||
Feature Level | Guaranteed features
|
||||
:----------------------|:---------------------------------
|
||||
1 | 9 textures per material
|
||||
2 | 9 textures per material, cubemap arrays, ESSL 3.10
|
||||
3 | 12 textures per material, cubemap arrays, ESSL 3.10
|
||||
[Table [featureLevels]: Feature levels]
|
||||
|
||||
Description
|
||||
: Sets the feature level of the material. Each feature level defines a set of features the
|
||||
material can use. If the material uses a feature not supported by the selected level, `matc`
|
||||
will generate an error during compilation. A given feature level is guaranteed to support
|
||||
all features of lower feature levels.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
||||
material {
|
||||
featureLevel : 2
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Bugs
|
||||
: `matc` doesn't verify that a material is not using features above its selected feature level.
|
||||
|
||||
|
||||
### General: shadingModel
|
||||
|
||||
Type
|
||||
@@ -986,6 +1017,7 @@ uint4 | Vector of 4 unsigned integers
|
||||
float3x3 | Matrix of 3x3 floats
|
||||
float4x4 | Matrix of 4x4 floats
|
||||
sampler2d | 2D texture
|
||||
sampler2dArray | Array of 2D textures
|
||||
samplerExternal | External texture (platform-specific)
|
||||
samplerCubemap | Cubemap texture
|
||||
[Table [materialParamsTypes]: Material parameter types]
|
||||
@@ -997,7 +1029,7 @@ Samplers
|
||||
Arrays
|
||||
: A parameter can define an array of values by appending `[size]` after the type name, where
|
||||
`size` is a positive integer. For instance: `float[9]` declares an array of nine `float`
|
||||
values. Arrays of samplers are _not_ supported at the moment.
|
||||
values. This syntax does not apply to samplers as arrays are treated as separate types.
|
||||
|
||||
Description
|
||||
: Lists the parameters required by your material. These parameters can be set at runtime using
|
||||
@@ -1140,6 +1172,29 @@ material {
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### General: vertexDomainDeviceJittered
|
||||
|
||||
Type
|
||||
: `boolean`
|
||||
|
||||
Value
|
||||
: `true` or `false`. Defaults to `false`.
|
||||
|
||||
Description
|
||||
: Only meaningful for `vertexDomain:Device` materials, this parameter specifies whether the
|
||||
filament clip-space transforms need to be applied or not, which affects TAA and guard bands.
|
||||
Generally it needs to be applied because by definition `vertexDomain:Device` materials
|
||||
vertices are not transformed and used *as is*.
|
||||
However, if the vertex shader uses for instance `getViewFromClipMatrix()` (or other
|
||||
matrices based on the projection), the clip-space transform is already applied.
|
||||
Setting this parameter incorrectly can prevent TAA or the guard bands to work correctly.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
||||
material {
|
||||
vertexDomainDeviceJittered : true
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### Vertex and attributes: requires
|
||||
|
||||
Type
|
||||
@@ -1527,24 +1582,22 @@ Value
|
||||
: `true` or `false`. Defaults to `false`.
|
||||
|
||||
Description
|
||||
: Only available in the `unlit` shading model. If this property is enabled, the final color
|
||||
computed by the material is multiplied by the shadowing factor (or visibility). This allows to
|
||||
create transparent shadow-receiving objects (for instance an invisible ground plane in AR).
|
||||
This is only supported with shadows from directional lights.
|
||||
: Enables two-sided rendering and its capability to be toggled at run time. When set to `true`,
|
||||
`culling` is automatically set to `none`; if the triangle is back-facing, the triangle's
|
||||
normal is flipped to become front-facing. When explicitly set to `false`, this allows the
|
||||
double-sidedness to be toggled at run time.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
||||
material {
|
||||
name : "Invisible shadow plane",
|
||||
shadingModel : unlit,
|
||||
shadowMultiplier : true,
|
||||
blending : transparent
|
||||
name : "Double sided material",
|
||||
shadingModel : lit,
|
||||
doubleSided : true
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
// baseColor defines the color and opacity of the final shadow
|
||||
material.baseColor = vec4(0.0, 0.0, 0.0, 0.7);
|
||||
material.baseColor = materialParams.albedo;
|
||||
}
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -1845,7 +1898,7 @@ struct MaterialVertexInputs {
|
||||
float3 worldNormal; // only if the shading model is not unlit
|
||||
float4 worldPosition; // always available (see note below about world-space)
|
||||
|
||||
mat4 clipSpaceTransform; // default: identity, transforms the clip-space position
|
||||
mat4 clipSpaceTransform; // default: identity, transforms the clip-space position, only available for `vertexDomain:device`
|
||||
|
||||
// variable* names are replaced with actual names
|
||||
float4 variable0; // if 1 or more variables is defined
|
||||
|
||||
@@ -48,6 +48,7 @@ set(PUBLIC_HDRS
|
||||
)
|
||||
|
||||
set(SRCS
|
||||
src/AtlasAllocator.cpp
|
||||
src/Box.cpp
|
||||
src/BufferObject.cpp
|
||||
src/Camera.cpp
|
||||
@@ -72,6 +73,7 @@ set(SRCS
|
||||
src/MaterialParser.cpp
|
||||
src/MorphTargetBuffer.cpp
|
||||
src/PerViewUniforms.cpp
|
||||
src/PerShadowMapUniforms.cpp
|
||||
src/PostProcessManager.cpp
|
||||
src/RenderPass.cpp
|
||||
src/RenderPrimitive.cpp
|
||||
@@ -145,6 +147,7 @@ set(PRIVATE_HDRS
|
||||
src/Intersections.h
|
||||
src/MaterialParser.h
|
||||
src/PerViewUniforms.h
|
||||
src/PerShadowMapUniforms.h
|
||||
src/PIDController.h
|
||||
src/PostProcessManager.h
|
||||
src/RendererUtils.h
|
||||
@@ -198,7 +201,7 @@ set(PRIVATE_HDRS
|
||||
src/materials/fsr/ffx_a.h
|
||||
src/materials/fsr/ffx_fsr1.h
|
||||
src/materials/fsr/ffx_fsr1_mobile.fs
|
||||
src/upcast.h
|
||||
src/downcast.h
|
||||
)
|
||||
|
||||
set(MATERIAL_SRCS
|
||||
@@ -523,6 +526,9 @@ add_library(${TARGET} STATIC ${PRIVATE_HDRS} ${PUBLIC_HDRS} ${SRCS} ${DATA_BINS}
|
||||
# specify where the public headers of this library are
|
||||
target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
|
||||
# add this subproject to the Filament folder
|
||||
set_target_properties(${TARGET} PROPERTIES FOLDER Filament)
|
||||
|
||||
# ==================================================================================================
|
||||
# Dependencies
|
||||
# ==================================================================================================
|
||||
|
||||
@@ -11,11 +11,13 @@ set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(PUBLIC_HDRS
|
||||
include/backend/BufferDescriptor.h
|
||||
include/backend/CallbackHandler.h
|
||||
include/backend/DriverApiForward.h
|
||||
include/backend/DriverEnums.h
|
||||
include/backend/Handle.h
|
||||
include/backend/PipelineState.h
|
||||
include/backend/PixelBufferDescriptor.h
|
||||
include/backend/Platform.h
|
||||
include/backend/Program.h
|
||||
include/backend/SamplerDescriptor.h
|
||||
include/backend/TargetBufferInfo.h
|
||||
)
|
||||
@@ -47,9 +49,7 @@ set(PRIVATE_HDRS
|
||||
include/private/backend/Driver.h
|
||||
include/private/backend/DriverApi.h
|
||||
include/private/backend/DriverAPI.inc
|
||||
include/private/backend/DriverApiForward.h
|
||||
include/private/backend/HandleAllocator.h
|
||||
include/private/backend/Program.h
|
||||
include/private/backend/SamplerGroup.h
|
||||
src/CommandStreamDispatcher.h
|
||||
src/DataReshaper.h
|
||||
@@ -104,8 +104,6 @@ if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3 AND NOT FILAMEN
|
||||
endif()
|
||||
elseif (WIN32)
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformWGL.cpp)
|
||||
else()
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformDummyGL.cpp)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -224,6 +222,9 @@ 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})
|
||||
|
||||
# add this subproject to the Filament folder
|
||||
set_target_properties(${TARGET} PROPERTIES FOLDER Filament)
|
||||
|
||||
# ==================================================================================================
|
||||
# Expose a header-only target to minimize dependencies.
|
||||
# ==================================================================================================
|
||||
@@ -269,6 +270,7 @@ set(DUMMY_SRC "${VKSHADERS_DIR}/dummy.c")
|
||||
add_custom_command(OUTPUT ${DUMMY_SRC} COMMAND echo "//" > ${DUMMY_SRC})
|
||||
|
||||
add_library(vkshaders STATIC ${DUMMY_SRC} ${RESGEN_SOURCE})
|
||||
set_target_properties(vkshaders PROPERTIES FOLDER Filament/Generated)
|
||||
|
||||
# ==================================================================================================
|
||||
# Dependencies
|
||||
@@ -435,6 +437,8 @@ if (APPLE)
|
||||
install(FILES "${BACKEND_TEST_COMBINED_OUTPUT}" DESTINATION lib/${DIST_DIR} RENAME ${BACKEND_TEST_LIB_NAME})
|
||||
install(FILES test/PlatformRunner.h DESTINATION include/backend_test)
|
||||
endif()
|
||||
|
||||
set_target_properties(backend_test PROPERTIES FOLDER Tests)
|
||||
endif()
|
||||
|
||||
if (APPLE AND NOT IOS)
|
||||
@@ -443,5 +447,26 @@ if (APPLE AND NOT IOS)
|
||||
# Because each test case is a separate file, the -force_load flag is necessary to prevent the
|
||||
# linker from removing "unused" symbols.
|
||||
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
|
||||
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Compute tests
|
||||
|
||||
if (NOT IOS AND NOT WEBGL)
|
||||
|
||||
add_executable(compute_test
|
||||
test/ComputeTest.cpp
|
||||
test/Arguments.cpp
|
||||
test/test_ComputeBasic.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(compute_test PRIVATE
|
||||
backend
|
||||
getopt
|
||||
gtest
|
||||
)
|
||||
|
||||
set_target_properties(compute_test PROPERTIES FOLDER Tests)
|
||||
|
||||
endif()
|
||||
|
||||
@@ -48,16 +48,37 @@ static constexpr uint64_t SWAP_CHAIN_CONFIG_ENABLE_XCB = 0x4;
|
||||
static constexpr uint64_t SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER = 0x8;
|
||||
|
||||
static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES.
|
||||
static constexpr size_t MAX_VERTEX_SAMPLER_COUNT = 16; // This is guaranteed by OpenGL ES.
|
||||
static constexpr size_t MAX_FRAGMENT_SAMPLER_COUNT = 16; // This is guaranteed by OpenGL ES.
|
||||
static constexpr size_t MAX_SAMPLER_COUNT = 32; // This is guaranteed by OpenGL ES.
|
||||
static constexpr size_t MAX_SAMPLER_COUNT = 62; // Maximum needed at feature level 3.
|
||||
static constexpr size_t MAX_VERTEX_BUFFER_COUNT = 16; // Max number of bound buffer objects.
|
||||
static constexpr size_t MAX_SSBO_COUNT = 4; // This is guaranteed by OpenGL ES.
|
||||
|
||||
// Per feature level caps
|
||||
// Use (int)FeatureLevel to index this array
|
||||
static constexpr struct {
|
||||
const size_t MAX_VERTEX_SAMPLER_COUNT;
|
||||
const size_t MAX_FRAGMENT_SAMPLER_COUNT;
|
||||
} FEATURE_LEVEL_CAPS[4] = {
|
||||
{ 0, 0 }, // do not use
|
||||
{ 16, 16 }, // guaranteed by OpenGL ES, Vulkan and Metal
|
||||
{ 16, 16 }, // guaranteed by OpenGL ES, Vulkan and Metal
|
||||
{ 31, 31 }, // guaranteed by Metal
|
||||
};
|
||||
|
||||
static_assert(MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_ATTRIBUTE_COUNT,
|
||||
"The number of buffer objects that can be attached to a VertexBuffer must be "
|
||||
"less than or equal to the maximum number of vertex attributes.");
|
||||
|
||||
static constexpr size_t CONFIG_BINDING_COUNT = 12; // This is guaranteed by OpenGL ES.
|
||||
static constexpr size_t CONFIG_UNIFORM_BINDING_COUNT = 10; // This is guaranteed by OpenGL ES.
|
||||
static constexpr size_t CONFIG_SAMPLER_BINDING_COUNT = 4; // This is guaranteed by OpenGL ES.
|
||||
|
||||
/**
|
||||
* Defines the backend's feature levels.
|
||||
*/
|
||||
enum class FeatureLevel : uint8_t {
|
||||
FEATURE_LEVEL_1 = 1, //!< OpenGL ES 3.0 features (default)
|
||||
FEATURE_LEVEL_2, //!< OpenGL ES 3.1 features + 16 textures units + cubemap arrays
|
||||
FEATURE_LEVEL_3 //!< OpenGL ES 3.1 features + 31 textures units + cubemap arrays
|
||||
};
|
||||
|
||||
/**
|
||||
* Selects which driver a particular Engine should use.
|
||||
@@ -199,8 +220,7 @@ enum class PrimitiveType : uint8_t {
|
||||
LINES = 1, //!< lines
|
||||
LINE_STRIP = 3, //!< line strip
|
||||
TRIANGLES = 4, //!< triangles
|
||||
TRIANGLE_STRIP = 5, //!< triangle strip
|
||||
NONE = 0xFF
|
||||
TRIANGLE_STRIP = 5 //!< triangle strip
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -293,7 +313,8 @@ enum class ElementType : uint8_t {
|
||||
//! Buffer object binding type
|
||||
enum class BufferObjectBinding : uint8_t {
|
||||
VERTEX,
|
||||
UNIFORM
|
||||
UNIFORM,
|
||||
SHADER_STORAGE
|
||||
};
|
||||
|
||||
//! Face culling Mode
|
||||
@@ -630,6 +651,10 @@ static constexpr bool isS3TCSRGBCompression(TextureFormat format) noexcept {
|
||||
return format >= TextureFormat::DXT1_SRGB && format <= TextureFormat::DXT5_SRGBA;
|
||||
}
|
||||
|
||||
static constexpr bool isASTCCompression(TextureFormat format) noexcept {
|
||||
return format >= TextureFormat::RGBA_ASTC_4x4 && format <= TextureFormat::SRGB8_ALPHA8_ASTC_12x12;
|
||||
}
|
||||
|
||||
//! Texture Cubemap Face
|
||||
enum class TextureCubemapFace : uint8_t {
|
||||
// don't change the enums values
|
||||
@@ -641,10 +666,6 @@ enum class TextureCubemapFace : uint8_t {
|
||||
NEGATIVE_Z = 5, //!< -z face
|
||||
};
|
||||
|
||||
inline constexpr int operator +(TextureCubemapFace rhs) noexcept {
|
||||
return int(rhs);
|
||||
}
|
||||
|
||||
//! Sampler Wrap mode
|
||||
enum class SamplerWrapMode : uint8_t {
|
||||
CLAMP_TO_EDGE, //!< clamp-to-edge. The edge of the texture extends to infinity.
|
||||
@@ -755,6 +776,13 @@ enum class StencilOperation : uint8_t {
|
||||
INVERT, //!< Bitwise inverts the current value.
|
||||
};
|
||||
|
||||
//! stencil faces
|
||||
enum class StencilFace : uint8_t {
|
||||
FRONT = 0x1, //!< Update stencil state for front-facing polygons.
|
||||
BACK = 0x2, //!< Update stencil state for back-facing polygons.
|
||||
FRONT_AND_BACK = FRONT | BACK, //!< Update stencil state for all polygons.
|
||||
};
|
||||
|
||||
//! Stream for external textures
|
||||
enum class StreamType {
|
||||
NATIVE, //!< Not synchronized but copy-free. Good for video.
|
||||
@@ -787,11 +815,9 @@ struct RasterState {
|
||||
using DepthFunc = backend::SamplerCompareFunc;
|
||||
using BlendEquation = backend::BlendEquation;
|
||||
using BlendFunction = backend::BlendFunction;
|
||||
using StencilFunction = backend::SamplerCompareFunc;
|
||||
using StencilOperation = backend::StencilOperation;
|
||||
|
||||
RasterState() noexcept { // NOLINT
|
||||
static_assert(sizeof(RasterState) == sizeof(uint64_t),
|
||||
static_assert(sizeof(RasterState) == sizeof(uint32_t),
|
||||
"RasterState size not what was intended");
|
||||
culling = CullingMode::BACK;
|
||||
blendEquationRGB = BlendEquation::ADD;
|
||||
@@ -800,10 +826,6 @@ struct RasterState {
|
||||
blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||
blendFunctionDstRGB = BlendFunction::ZERO;
|
||||
blendFunctionDstAlpha = BlendFunction::ZERO;
|
||||
stencilFunc = StencilFunction::A;
|
||||
stencilOpStencilFail = StencilOperation::KEEP;
|
||||
stencilOpDepthFail = StencilOperation::KEEP;
|
||||
stencilOpDepthStencilPass = StencilOperation::KEEP;
|
||||
}
|
||||
|
||||
bool operator == (RasterState rhs) const noexcept { return u == rhs.u; }
|
||||
@@ -862,26 +884,10 @@ struct RasterState {
|
||||
//! whether front face winding direction must be inverted
|
||||
bool inverseFrontFaces : 1; // 31
|
||||
|
||||
//! Whether stencil-buffer writes are enabled
|
||||
bool stencilWrite : 1; // 32
|
||||
//! Stencil reference value
|
||||
uint8_t stencilRef : 8; // 40
|
||||
//! Stencil test function
|
||||
StencilFunction stencilFunc : 3; // 43
|
||||
//! Stencil operation when stencil test fails
|
||||
StencilOperation stencilOpStencilFail : 3; // 46
|
||||
//! padding, must be 0
|
||||
uint8_t padding0 : 2; // 48
|
||||
//! Stencil operation when stencil test passes but depth test fails
|
||||
StencilOperation stencilOpDepthFail : 3; // 51
|
||||
//! Stencil operation when both stencil and depth test pass
|
||||
StencilOperation stencilOpDepthStencilPass : 3; // 54
|
||||
//! padding, must be 0
|
||||
uint8_t padding1 : 2; // 56
|
||||
//! padding, must be 0
|
||||
uint8_t padding2 : 8; // 64
|
||||
uint8_t padding : 1; // 32
|
||||
};
|
||||
uint64_t u = 0;
|
||||
uint32_t u = 0;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -890,21 +896,31 @@ struct RasterState {
|
||||
* \privatesection
|
||||
*/
|
||||
|
||||
enum ShaderType : uint8_t {
|
||||
enum class ShaderStage : uint8_t {
|
||||
VERTEX = 0,
|
||||
FRAGMENT = 1
|
||||
FRAGMENT = 1,
|
||||
COMPUTE = 2
|
||||
};
|
||||
static constexpr size_t PIPELINE_STAGE_COUNT = 2;
|
||||
|
||||
struct ShaderStageFlags {
|
||||
bool vertex : 1;
|
||||
bool fragment : 1;
|
||||
bool hasShaderType(ShaderType type) const {
|
||||
return (vertex && type == ShaderType::VERTEX) ||
|
||||
(fragment && type == ShaderType::FRAGMENT);
|
||||
}
|
||||
static constexpr size_t PIPELINE_STAGE_COUNT = 2;
|
||||
enum class ShaderStageFlags : uint8_t {
|
||||
NONE = 0,
|
||||
VERTEX = 0x1,
|
||||
FRAGMENT = 0x2,
|
||||
COMPUTE = 0x4,
|
||||
ALL_SHADER_STAGE_FLAGS = VERTEX | FRAGMENT | COMPUTE
|
||||
};
|
||||
static constexpr ShaderStageFlags ALL_SHADER_STAGE_FLAGS = { true, true };
|
||||
|
||||
static inline constexpr bool hasShaderType(ShaderStageFlags flags, ShaderStage type) noexcept {
|
||||
switch (type) {
|
||||
case ShaderStage::VERTEX:
|
||||
return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::VERTEX));
|
||||
case ShaderStage::FRAGMENT:
|
||||
return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::FRAGMENT));
|
||||
case ShaderStage::COMPUTE:
|
||||
return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::COMPUTE));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects which buffers to clear at the beginning of the render pass, as well as which buffers
|
||||
@@ -975,6 +991,55 @@ struct PolygonOffset {
|
||||
float constant = 0; // units in GL-speak
|
||||
};
|
||||
|
||||
struct StencilState {
|
||||
using StencilFunction = SamplerCompareFunc;
|
||||
|
||||
struct StencilOperations {
|
||||
//! Stencil test function
|
||||
StencilFunction stencilFunc : 3; // 3
|
||||
|
||||
//! Stencil operation when stencil test fails
|
||||
StencilOperation stencilOpStencilFail : 3; // 6
|
||||
|
||||
uint8_t padding0 : 2; // 8
|
||||
|
||||
//! Stencil operation when stencil test passes but depth test fails
|
||||
StencilOperation stencilOpDepthFail : 3; // 11
|
||||
|
||||
//! Stencil operation when both stencil and depth test pass
|
||||
StencilOperation stencilOpDepthStencilPass : 3; // 14
|
||||
|
||||
uint8_t padding1 : 2; // 16
|
||||
|
||||
//! Reference value for stencil comparison tests and updates
|
||||
uint8_t ref; // 24
|
||||
|
||||
//! Masks the bits of the stencil values participating in the stencil comparison test.
|
||||
uint8_t readMask; // 32
|
||||
|
||||
//! Masks the bits of the stencil values updated by the stencil test.
|
||||
uint8_t writeMask; // 40
|
||||
};
|
||||
|
||||
//! Stencil operations for front-facing polygons
|
||||
StencilOperations front = {
|
||||
.stencilFunc = StencilFunction::A, .ref = 0, .readMask = 0xff, .writeMask = 0xff };
|
||||
|
||||
//! Stencil operations for back-facing polygons
|
||||
StencilOperations back = {
|
||||
.stencilFunc = StencilFunction::A, .ref = 0, .readMask = 0xff, .writeMask = 0xff };
|
||||
|
||||
//! Whether stencil-buffer writes are enabled
|
||||
bool stencilWrite = false;
|
||||
|
||||
uint8_t padding = 0;
|
||||
};
|
||||
|
||||
static_assert(sizeof(StencilState::StencilOperations) == 5u,
|
||||
"StencilOperations size not what was intended");
|
||||
|
||||
static_assert(sizeof(StencilState) == 12u,
|
||||
"StencilState size not what was intended");
|
||||
|
||||
using FrameScheduledCallback = void(*)(PresentCallable callable, void* user);
|
||||
|
||||
@@ -992,11 +1057,18 @@ enum class Workaround : uint16_t {
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
template<> struct utils::EnableBitMaskOperators<filament::backend::ShaderStageFlags>
|
||||
: public std::true_type {};
|
||||
template<> struct utils::EnableBitMaskOperators<filament::backend::TargetBufferFlags>
|
||||
: public std::true_type {};
|
||||
template<> struct utils::EnableBitMaskOperators<filament::backend::TextureUsage>
|
||||
: public std::true_type {};
|
||||
|
||||
template<> struct utils::EnableBitMaskOperators<filament::backend::StencilFace>
|
||||
: public std::true_type {};
|
||||
template<> struct utils::EnableIntegerOperators<filament::backend::TextureCubemapFace>
|
||||
: public std::true_type {};
|
||||
template<> struct utils::EnableIntegerOperators<filament::backend::FeatureLevel>
|
||||
: public std::true_type {};
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::BufferUsage usage);
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace filament::backend {
|
||||
struct PipelineState {
|
||||
Handle<HwProgram> program;
|
||||
RasterState rasterState;
|
||||
StencilState stencilState;
|
||||
PolygonOffset polygonOffset;
|
||||
Viewport scissor{ 0, 0,
|
||||
(uint32_t)std::numeric_limits<int32_t>::max(),
|
||||
|
||||
@@ -280,7 +280,7 @@ public:
|
||||
}
|
||||
|
||||
size_t bpr = bpp * stride;
|
||||
size_t bprAligned = (bpr + (alignment - 1)) & -alignment;
|
||||
size_t bprAligned = (bpr + (alignment - 1)) & (~alignment + 1);
|
||||
return bprAligned * height;
|
||||
}
|
||||
|
||||
|
||||
+34
-35
@@ -27,40 +27,40 @@
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class Program {
|
||||
public:
|
||||
|
||||
static constexpr size_t SHADER_TYPE_COUNT = 2;
|
||||
static constexpr size_t BINDING_COUNT = CONFIG_BINDING_COUNT;
|
||||
|
||||
enum class Shader : uint8_t {
|
||||
VERTEX = 0,
|
||||
FRAGMENT = 1
|
||||
};
|
||||
static constexpr size_t SHADER_TYPE_COUNT = 3;
|
||||
static constexpr size_t UNIFORM_BINDING_COUNT = CONFIG_UNIFORM_BINDING_COUNT;
|
||||
static constexpr size_t SAMPLER_BINDING_COUNT = CONFIG_SAMPLER_BINDING_COUNT;
|
||||
|
||||
struct Sampler {
|
||||
utils::CString name = {}; // name of the sampler in the shader
|
||||
uint16_t binding = 0; // binding point of the sampler in the shader
|
||||
bool strict = false; // if true, this sampler must always have a bound texture
|
||||
uint32_t binding = 0; // binding point of the sampler in the shader
|
||||
};
|
||||
|
||||
struct SamplerGroupData {
|
||||
utils::FixedCapacityVector<Sampler> samplers;
|
||||
ShaderStageFlags stageFlags = ALL_SHADER_STAGE_FLAGS;
|
||||
ShaderStageFlags stageFlags = ShaderStageFlags::ALL_SHADER_STAGE_FLAGS;
|
||||
};
|
||||
|
||||
using SamplerGroupInfo = std::array<SamplerGroupData, BINDING_COUNT>;
|
||||
using UniformBlockInfo = std::array<utils::CString, BINDING_COUNT>;
|
||||
using UniformBlockInfo = std::array<utils::CString, UNIFORM_BINDING_COUNT>;
|
||||
using SamplerGroupInfo = std::array<SamplerGroupData, SAMPLER_BINDING_COUNT>;
|
||||
using ShaderBlob = utils::FixedCapacityVector<uint8_t>;
|
||||
using ShaderSource = std::array<ShaderBlob, SHADER_TYPE_COUNT>;
|
||||
|
||||
Program() noexcept;
|
||||
|
||||
Program(const Program& rhs) = delete;
|
||||
Program& operator=(const Program& rhs) = delete;
|
||||
|
||||
Program(Program&& rhs) noexcept;
|
||||
Program& operator=(Program&& rhs) noexcept;
|
||||
|
||||
~Program() noexcept;
|
||||
|
||||
// sets the material name and variant for diagnostic purposes only
|
||||
@@ -70,15 +70,13 @@ public:
|
||||
// sets one of the program's shader (e.g. vertex, fragment)
|
||||
// string-based shaders are null terminated, consequently the size parameter must include the
|
||||
// null terminating character.
|
||||
Program& shader(Shader shader, void const* data, size_t size) noexcept;
|
||||
Program& shader(ShaderStage shader, void const* data, size_t size);
|
||||
|
||||
// sets the 'bindingPoint' uniform block's name for this program.
|
||||
//
|
||||
// Note: This is only needed for GLES3.0 backends, because the layout(binding=) syntax is
|
||||
// not permitted in glsl. The backend needs a way to associate a uniform block
|
||||
// to a binding point.
|
||||
//
|
||||
Program& setUniformBlock(size_t bindingPoint, std::string_view uniformBlockName) noexcept;
|
||||
Program& uniformBlockBindings(
|
||||
utils::FixedCapacityVector<std::pair<utils::CString, uint8_t>> const& uniformBlockBindings) noexcept;
|
||||
|
||||
// sets the 'bindingPoint' sampler group descriptor for this program.
|
||||
// 'samplers' can be destroyed after this call.
|
||||
@@ -87,32 +85,33 @@ public:
|
||||
Program& setSamplerGroup(size_t bindingPoint, ShaderStageFlags stageFlags,
|
||||
Sampler const* samplers, size_t count) noexcept;
|
||||
|
||||
// string-based shaders are null terminated, consequently the size parameter must include the
|
||||
// null terminating character.
|
||||
Program& withVertexShader(void const* data, size_t size) {
|
||||
return shader(Shader::VERTEX, data, size);
|
||||
}
|
||||
struct SpecializationConstant {
|
||||
uint32_t id; // id set in glsl
|
||||
std::variant<int32_t, float, bool> value; // value and type
|
||||
};
|
||||
|
||||
Program& specializationConstants(
|
||||
utils::FixedCapacityVector<SpecializationConstant> specConstants) noexcept;
|
||||
|
||||
// string-based shaders are null terminated, consequently the size parameter must include the
|
||||
// null terminating character.
|
||||
Program& withFragmentShader(void const* data, size_t size) {
|
||||
return shader(Shader::FRAGMENT, data, size);
|
||||
}
|
||||
|
||||
using ShaderBlob = utils::FixedCapacityVector<uint8_t>;
|
||||
using ShaderSource = std::array<ShaderBlob, SHADER_TYPE_COUNT>;
|
||||
ShaderSource const& getShadersSource() const noexcept { return mShadersSource; }
|
||||
ShaderSource& getShadersSource() noexcept { return mShadersSource; }
|
||||
|
||||
UniformBlockInfo const& getUniformBlockInfo() const noexcept { return mUniformBlocks; }
|
||||
UniformBlockInfo& getUniformBlockInfo() noexcept { return mUniformBlocks; }
|
||||
UniformBlockInfo const& getUniformBlockBindings() const noexcept { return mUniformBlocks; }
|
||||
UniformBlockInfo& getUniformBlockBindings() noexcept { return mUniformBlocks; }
|
||||
|
||||
SamplerGroupInfo const& getSamplerGroupInfo() const { return mSamplerGroups; }
|
||||
SamplerGroupInfo& getSamplerGroupInfo() { return mSamplerGroups; }
|
||||
|
||||
const utils::CString& getName() const noexcept { return mName; }
|
||||
utils::CString const& getName() const noexcept { return mName; }
|
||||
utils::CString& getName() noexcept { return mName; }
|
||||
|
||||
bool hasSamplers() const noexcept { return mHasSamplers; }
|
||||
utils::FixedCapacityVector<SpecializationConstant> const& getSpecializationConstants() const noexcept {
|
||||
return mSpecializationConstants;
|
||||
}
|
||||
utils::FixedCapacityVector<SpecializationConstant>& getSpecializationConstants() noexcept {
|
||||
return mSpecializationConstants;
|
||||
}
|
||||
|
||||
private:
|
||||
friend utils::io::ostream& operator<<(utils::io::ostream& out, const Program& builder);
|
||||
@@ -120,9 +119,9 @@ private:
|
||||
UniformBlockInfo mUniformBlocks = {};
|
||||
SamplerGroupInfo mSamplerGroups = {};
|
||||
ShaderSource mShadersSource;
|
||||
bool mHasSamplers = false;
|
||||
utils::CString mName;
|
||||
utils::Invocable<utils::io::ostream&(utils::io::ostream& out)> mLogger;
|
||||
utils::FixedCapacityVector<SpecializationConstant> mSpecializationConstants;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
@@ -21,15 +21,16 @@
|
||||
|
||||
#include <backend/PixelBufferDescriptor.h>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
namespace filament::backend {
|
||||
|
||||
/**
|
||||
* Returns true if the shader string requests the Google-style line directive extension.
|
||||
*/
|
||||
bool requestsGoogleLineDirectivesExtension(const char* shader, size_t length) noexcept;
|
||||
bool requestsGoogleLineDirectivesExtension(std::string_view source) noexcept;
|
||||
|
||||
/**
|
||||
* Edit a GLSL shader string in-place so any Google-style line directives are turned into regular
|
||||
@@ -48,6 +49,11 @@ void removeGoogleLineDirectives(char* shader, size_t length) noexcept;
|
||||
*/
|
||||
size_t getFormatSize(TextureFormat format) noexcept;
|
||||
|
||||
/**
|
||||
* Returns the number of component (1 to 4) for the given format.
|
||||
*/
|
||||
size_t getFormatComponentCount(TextureFormat format) noexcept;
|
||||
|
||||
/**
|
||||
* For compressed texture formats, returns the number of horizontal texels per block. Otherwise
|
||||
* returns 0.
|
||||
@@ -65,7 +71,6 @@ size_t getBlockHeight(TextureFormat format) noexcept;
|
||||
*/
|
||||
bool reshape(const PixelBufferDescriptor& data, PixelBufferDescriptor& reshaped);
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_PRIVATE_BACKENDUTILS_H
|
||||
|
||||
@@ -17,13 +17,12 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_CIRCULARBUFFER_H
|
||||
#define TNT_FILAMENT_BACKEND_PRIVATE_CIRCULARBUFFER_H
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
namespace filament::backend {
|
||||
|
||||
class CircularBuffer {
|
||||
public:
|
||||
@@ -85,7 +84,6 @@ private:
|
||||
void* mHead = nullptr;
|
||||
};
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
} // namespace filament::backend
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_PRIVATE_CIRCULARBUFFER_H
|
||||
|
||||
@@ -19,14 +19,13 @@
|
||||
|
||||
#include "private/backend/CircularBuffer.h"
|
||||
#include "private/backend/Dispatcher.h"
|
||||
#include "private/backend/Program.h"
|
||||
#include "private/backend/SamplerGroup.h"
|
||||
#include "private/backend/Driver.h"
|
||||
|
||||
#include <backend/BufferDescriptor.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Handle.h>
|
||||
#include <backend/PipelineState.h>
|
||||
#include <backend/Program.h>
|
||||
#include <backend/PixelBufferDescriptor.h>
|
||||
#include <backend/PresentCallable.h>
|
||||
#include <backend/TargetBufferInfo.h>
|
||||
@@ -37,9 +36,12 @@
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <thread>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -17,13 +17,12 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_DRIVER_H
|
||||
#define TNT_FILAMENT_BACKEND_PRIVATE_DRIVER_H
|
||||
|
||||
#include <backend/DriverApiForward.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Handle.h>
|
||||
#include <backend/PipelineState.h>
|
||||
#include <backend/TargetBufferInfo.h>
|
||||
|
||||
#include "private/backend/DriverApiForward.h"
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <functional>
|
||||
@@ -48,7 +47,6 @@ class BufferDescriptor;
|
||||
class CallbackHandler;
|
||||
class PixelBufferDescriptor;
|
||||
class Program;
|
||||
class SamplerGroup;
|
||||
|
||||
template<typename T>
|
||||
class ConcreteDispatcher;
|
||||
|
||||
@@ -158,6 +158,9 @@ DECL_DRIVER_API_0(flush)
|
||||
// flush and wait for the effects to be done
|
||||
DECL_DRIVER_API_0(finish)
|
||||
|
||||
// reset state tracking, if the driver does any state tracking (e.g. GL)
|
||||
DECL_DRIVER_API_0(resetState)
|
||||
|
||||
/*
|
||||
* Creating driver objects
|
||||
* -----------------------
|
||||
@@ -304,6 +307,7 @@ DECL_DRIVER_API_SYNCHRONOUS_N(void, cancelExternalImage, void*, image)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(bool, getTimerQueryValue, backend::TimerQueryHandle, query, uint64_t*, elapsedTime)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(backend::SyncStatus, getSyncStatus, backend::SyncHandle, sh)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isWorkaroundNeeded, backend::Workaround, workaround)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(backend::FeatureLevel, getFeatureLevel)
|
||||
|
||||
/*
|
||||
* Updating driver objects
|
||||
@@ -405,12 +409,17 @@ DECL_DRIVER_API_N(bindUniformBuffer,
|
||||
uint32_t, index,
|
||||
backend::BufferObjectHandle, ubh)
|
||||
|
||||
DECL_DRIVER_API_N(bindUniformBufferRange,
|
||||
DECL_DRIVER_API_N(bindBufferRange,
|
||||
BufferObjectBinding, bindingType,
|
||||
uint32_t, index,
|
||||
backend::BufferObjectHandle, ubh,
|
||||
uint32_t, offset,
|
||||
uint32_t, size)
|
||||
|
||||
DECL_DRIVER_API_N(unbindBuffer,
|
||||
BufferObjectBinding, bindingType,
|
||||
uint32_t, index)
|
||||
|
||||
DECL_DRIVER_API_N(bindSamplers,
|
||||
uint32_t, index,
|
||||
backend::SamplerGroupHandle, sbh)
|
||||
@@ -443,6 +452,12 @@ DECL_DRIVER_API_N(readPixels,
|
||||
uint32_t, height,
|
||||
backend::PixelBufferDescriptor&&, data)
|
||||
|
||||
DECL_DRIVER_API_N(readBufferSubData,
|
||||
backend::BufferObjectHandle, src,
|
||||
uint32_t, offset,
|
||||
uint32_t, size,
|
||||
backend::BufferDescriptor&&, data)
|
||||
|
||||
/*
|
||||
* Rendering operations
|
||||
* --------------------
|
||||
@@ -461,6 +476,11 @@ DECL_DRIVER_API_N(draw,
|
||||
backend::RenderPrimitiveHandle, rph,
|
||||
uint32_t, instanceCount)
|
||||
|
||||
DECL_DRIVER_API_N(dispatchCompute,
|
||||
backend::ProgramHandle, program,
|
||||
math::uint3, workGroupCount)
|
||||
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
#undef EXPAND
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPI_H
|
||||
#define TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPI_H
|
||||
|
||||
#include "private/backend/DriverApiForward.h"
|
||||
#include "backend/DriverApiForward.h"
|
||||
#include "private/backend/CommandStream.h"
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPI_H
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_SAMPLERGROUP_H
|
||||
#define TNT_FILAMENT_BACKEND_PRIVATE_SAMPLERGROUP_H
|
||||
|
||||
#include "private/backend/DriverApiForward.h"
|
||||
#include "backend/DriverApiForward.h"
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
|
||||
@@ -22,12 +22,10 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
namespace filament::backend {
|
||||
|
||||
bool requestsGoogleLineDirectivesExtension(const char* shader, size_t length) noexcept {
|
||||
std::string_view s(shader, length);
|
||||
return s.find("GL_GOOGLE_cpp_style_line_directive") != std::string_view::npos;
|
||||
bool requestsGoogleLineDirectivesExtension(std::string_view source) noexcept {
|
||||
return source.find("GL_GOOGLE_cpp_style_line_directive") != std::string_view::npos;
|
||||
}
|
||||
|
||||
void removeGoogleLineDirectives(char* shader, size_t length) noexcept {
|
||||
@@ -211,6 +209,129 @@ size_t getFormatSize(TextureFormat format) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
size_t getFormatComponentCount(TextureFormat format) noexcept {
|
||||
switch (format) {
|
||||
case TextureFormat::R8:
|
||||
case TextureFormat::R8_SNORM:
|
||||
case TextureFormat::R8UI:
|
||||
case TextureFormat::R8I:
|
||||
case TextureFormat::R16F:
|
||||
case TextureFormat::R16UI:
|
||||
case TextureFormat::R16I:
|
||||
case TextureFormat::R32F:
|
||||
case TextureFormat::R32I:
|
||||
case TextureFormat::R32UI:
|
||||
case TextureFormat::STENCIL8:
|
||||
case TextureFormat::DEPTH16:
|
||||
case TextureFormat::DEPTH24:
|
||||
case TextureFormat::DEPTH32F:
|
||||
return 1;
|
||||
|
||||
case TextureFormat::RG8:
|
||||
case TextureFormat::RG8_SNORM:
|
||||
case TextureFormat::RG8UI:
|
||||
case TextureFormat::RG8I:
|
||||
case TextureFormat::RG16F:
|
||||
case TextureFormat::RG16UI:
|
||||
case TextureFormat::RG16I:
|
||||
case TextureFormat::RG32F:
|
||||
case TextureFormat::RG32UI:
|
||||
case TextureFormat::RG32I:
|
||||
case TextureFormat::DEPTH24_STENCIL8:
|
||||
case TextureFormat::DEPTH32F_STENCIL8:
|
||||
return 2;
|
||||
|
||||
case TextureFormat::RGB565:
|
||||
case TextureFormat::RGB8:
|
||||
case TextureFormat::SRGB8:
|
||||
case TextureFormat::RGB8_SNORM:
|
||||
case TextureFormat::RGB8UI:
|
||||
case TextureFormat::RGB8I:
|
||||
case TextureFormat::R11F_G11F_B10F:
|
||||
case TextureFormat::RGB16F:
|
||||
case TextureFormat::RGB16UI:
|
||||
case TextureFormat::RGB16I:
|
||||
case TextureFormat::RGB32F:
|
||||
case TextureFormat::RGB32UI:
|
||||
case TextureFormat::RGB32I:
|
||||
return 3;
|
||||
|
||||
case TextureFormat::RGB5_A1:
|
||||
case TextureFormat::RGBA4:
|
||||
case TextureFormat::RGB9_E5:
|
||||
case TextureFormat::RGBA8:
|
||||
case TextureFormat::SRGB8_A8:
|
||||
case TextureFormat::RGBA8_SNORM:
|
||||
case TextureFormat::RGB10_A2:
|
||||
case TextureFormat::RGBA8UI:
|
||||
case TextureFormat::RGBA8I:
|
||||
case TextureFormat::RGBA16F:
|
||||
case TextureFormat::RGBA16UI:
|
||||
case TextureFormat::RGBA16I:
|
||||
case TextureFormat::RGBA32F:
|
||||
case TextureFormat::RGBA32UI:
|
||||
case TextureFormat::RGBA32I:
|
||||
return 4;
|
||||
|
||||
// Compressed formats ---------------------------------------------------------------------
|
||||
case TextureFormat::EAC_R11:
|
||||
case TextureFormat::EAC_R11_SIGNED:
|
||||
return 1;
|
||||
|
||||
case TextureFormat::EAC_RG11:
|
||||
case TextureFormat::EAC_RG11_SIGNED:
|
||||
return 2;
|
||||
|
||||
case TextureFormat::ETC2_RGB8:
|
||||
case TextureFormat::ETC2_SRGB8:
|
||||
case TextureFormat::DXT1_RGB:
|
||||
case TextureFormat::DXT1_SRGB:
|
||||
return 3;
|
||||
|
||||
case TextureFormat::ETC2_EAC_RGBA8:
|
||||
case TextureFormat::ETC2_EAC_SRGBA8:
|
||||
case TextureFormat::ETC2_RGB8_A1:
|
||||
case TextureFormat::ETC2_SRGB8_A1:
|
||||
case TextureFormat::DXT1_RGBA:
|
||||
case TextureFormat::DXT1_SRGBA:
|
||||
case TextureFormat::DXT3_RGBA:
|
||||
case TextureFormat::DXT3_SRGBA:
|
||||
case TextureFormat::DXT5_RGBA:
|
||||
case TextureFormat::DXT5_SRGBA:
|
||||
case TextureFormat::RGBA_ASTC_4x4:
|
||||
case TextureFormat::RGBA_ASTC_5x4:
|
||||
case TextureFormat::RGBA_ASTC_5x5:
|
||||
case TextureFormat::RGBA_ASTC_6x5:
|
||||
case TextureFormat::RGBA_ASTC_6x6:
|
||||
case TextureFormat::RGBA_ASTC_8x5:
|
||||
case TextureFormat::RGBA_ASTC_8x6:
|
||||
case TextureFormat::RGBA_ASTC_8x8:
|
||||
case TextureFormat::RGBA_ASTC_10x5:
|
||||
case TextureFormat::RGBA_ASTC_10x6:
|
||||
case TextureFormat::RGBA_ASTC_10x8:
|
||||
case TextureFormat::RGBA_ASTC_10x10:
|
||||
case TextureFormat::RGBA_ASTC_12x10:
|
||||
case TextureFormat::RGBA_ASTC_12x12:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_4x4:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_5x4:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_5x5:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_6x5:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_6x6:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_8x5:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_8x6:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_8x8:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_10x5:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_10x6:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_10x8:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_10x10:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_12x10:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_12x12:
|
||||
return 4;
|
||||
case TextureFormat::UNUSED:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t getBlockWidth(TextureFormat format) noexcept {
|
||||
switch (format) {
|
||||
case TextureFormat::EAC_RG11:
|
||||
@@ -380,60 +501,59 @@ bool reshape(const PixelBufferDescriptor& data, PixelBufferDescriptor& reshaped)
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
} // namespace backend::filament
|
||||
|
||||
|
||||
namespace utils {
|
||||
|
||||
template<>
|
||||
CString to_string<filament::backend::TextureUsage>(filament::backend::TextureUsage usage) noexcept {
|
||||
CString to_string<filament::backend::TextureUsage>(filament::backend::TextureUsage value) noexcept {
|
||||
using namespace filament::backend;
|
||||
char string[7] = {'-', '-', '-', '-', '-', '-', 0};
|
||||
if (any(usage & TextureUsage::UPLOADABLE)) {
|
||||
if (any(value & TextureUsage::UPLOADABLE)) {
|
||||
string[0]='U';
|
||||
}
|
||||
if (any(usage & TextureUsage::SAMPLEABLE)) {
|
||||
if (any(value & TextureUsage::SAMPLEABLE)) {
|
||||
string[1]='S';
|
||||
}
|
||||
if (any(usage & TextureUsage::COLOR_ATTACHMENT)) {
|
||||
if (any(value & TextureUsage::COLOR_ATTACHMENT)) {
|
||||
string[2]='c';
|
||||
}
|
||||
if (any(usage & TextureUsage::DEPTH_ATTACHMENT)) {
|
||||
if (any(value & TextureUsage::DEPTH_ATTACHMENT)) {
|
||||
string[3]='d';
|
||||
}
|
||||
if (any(usage & TextureUsage::STENCIL_ATTACHMENT)) {
|
||||
if (any(value & TextureUsage::STENCIL_ATTACHMENT)) {
|
||||
string[4] = 's';
|
||||
}
|
||||
if (any(usage & TextureUsage::SUBPASS_INPUT)) {
|
||||
if (any(value & TextureUsage::SUBPASS_INPUT)) {
|
||||
string[5]='f';
|
||||
}
|
||||
return CString(string, 6);
|
||||
return { string, 6 };
|
||||
}
|
||||
|
||||
template<>
|
||||
CString to_string<filament::backend::TargetBufferFlags>(filament::backend::TargetBufferFlags flags) noexcept {
|
||||
CString to_string<filament::backend::TargetBufferFlags>(filament::backend::TargetBufferFlags value) noexcept {
|
||||
using namespace filament::backend;
|
||||
char string[7] = {'-', '-', '-', '-', '-', '-', 0};
|
||||
if (any(flags & TargetBufferFlags::COLOR0)) {
|
||||
if (any(value & TargetBufferFlags::COLOR0)) {
|
||||
string[0]='0';
|
||||
}
|
||||
if (any(flags & TargetBufferFlags::COLOR1)) {
|
||||
if (any(value & TargetBufferFlags::COLOR1)) {
|
||||
string[1]='1';
|
||||
}
|
||||
if (any(flags & TargetBufferFlags::COLOR2)) {
|
||||
if (any(value & TargetBufferFlags::COLOR2)) {
|
||||
string[2]='2';
|
||||
}
|
||||
if (any(flags & TargetBufferFlags::COLOR3)) {
|
||||
if (any(value & TargetBufferFlags::COLOR3)) {
|
||||
string[3]='3';
|
||||
}
|
||||
if (any(flags & TargetBufferFlags::DEPTH)) {
|
||||
if (any(value & TargetBufferFlags::DEPTH)) {
|
||||
string[4]='D';
|
||||
}
|
||||
if (any(flags & TargetBufferFlags::STENCIL)) {
|
||||
if (any(value & TargetBufferFlags::STENCIL)) {
|
||||
string[5]='S';
|
||||
}
|
||||
return CString(string, 6);
|
||||
return { string, 6 };
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
@@ -59,6 +59,21 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static void copyImage(uint8_t* UTILS_RESTRICT dest,
|
||||
const uint8_t* UTILS_RESTRICT src,
|
||||
size_t srcBytesPerRow, size_t /*srcChannelCount*/,
|
||||
size_t dstBytesPerRow, size_t /*dstChannelCount*/,
|
||||
size_t /*width*/, size_t height, bool /*swizzle*/) {
|
||||
if (srcBytesPerRow == dstBytesPerRow) {
|
||||
std::memcpy(dest, src, height * srcBytesPerRow);
|
||||
return;
|
||||
}
|
||||
const size_t minBytesPerRow = std::min(srcBytesPerRow, dstBytesPerRow);
|
||||
for (size_t i = 0; i < height; ++i, src += srcBytesPerRow, dest += dstBytesPerRow) {
|
||||
std::memcpy(dest, src, minBytesPerRow);
|
||||
}
|
||||
}
|
||||
|
||||
// Converts a n-channel image of UBYTE, INT, UINT, or FLOAT to a different type.
|
||||
template<typename dstComponentType, typename srcComponentType>
|
||||
static void reshapeImage(uint8_t* UTILS_RESTRICT dest, const uint8_t* UTILS_RESTRICT src,
|
||||
@@ -119,7 +134,13 @@ public:
|
||||
switch (dst->type) {
|
||||
case UBYTE:
|
||||
switch (srcType) {
|
||||
case UBYTE: reshaper = reshapeImage<uint8_t, uint8_t>; break;
|
||||
case UBYTE:
|
||||
reshaper = reshapeImage<uint8_t, uint8_t>;
|
||||
if (dst->format == PixelDataFormat::RGBA &&
|
||||
dstChannelCount == srcChannelCount && !swizzle) {
|
||||
reshaper = copyImage;
|
||||
}
|
||||
break;
|
||||
case FLOAT: reshaper = reshapeImage<uint8_t, float>; break;
|
||||
case INT: reshaper = reshapeImage<uint8_t, int32_t>; break;
|
||||
case UINT: reshaper = reshapeImage<uint8_t, uint32_t>; break;
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
#include "private/backend/Dispatcher.h"
|
||||
#include "private/backend/Driver.h"
|
||||
#include "private/backend/SamplerGroup.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
#include "vulkan/PlatformVkCocoa.h"
|
||||
#endif
|
||||
#elif defined(__linux__)
|
||||
#if defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
#if defined(FILAMENT_SUPPORTS_GGP)
|
||||
#include "vulkan/PlatformVkLinuxGGP.h"
|
||||
#elif defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
#if defined (FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
#include "vulkan/PlatformVkLinuxWayland.h"
|
||||
#endif
|
||||
@@ -67,10 +69,6 @@
|
||||
#endif
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#include "opengl/platforms/PlatformWebGL.h"
|
||||
#else
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||
#include "opengl/platforms/PlatformDummyGL.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (FILAMENT_SUPPORTS_METAL)
|
||||
@@ -81,9 +79,7 @@ filament::backend::DefaultPlatform* createDefaultMetalPlatform();
|
||||
|
||||
#include "noop/PlatformNoop.h"
|
||||
|
||||
namespace filament {
|
||||
|
||||
namespace backend {
|
||||
namespace filament::backend {
|
||||
|
||||
// this generates the vtable in this translation unit
|
||||
Platform::~Platform() noexcept = default;
|
||||
@@ -126,7 +122,9 @@ DefaultPlatform* DefaultPlatform::create(Backend* backend) noexcept {
|
||||
#elif defined(IOS)
|
||||
return new PlatformVkCocoaTouch();
|
||||
#elif defined(__linux__)
|
||||
#if defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
#if defined(FILAMENT_SUPPORTS_GGP)
|
||||
return new PlatformVkLinuxGGP();
|
||||
#elif defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
return new PlatformVkLinuxWayland();
|
||||
#elif defined(FILAMENT_SUPPORTS_X11)
|
||||
return new PlatformVkLinuxX11();
|
||||
@@ -152,6 +150,7 @@ DefaultPlatform* DefaultPlatform::create(Backend* backend) noexcept {
|
||||
assert_invariant(*backend == Backend::OPENGL);
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL)
|
||||
#if defined(FILAMENT_USE_EXTERNAL_GLES3) || defined(FILAMENT_USE_SWIFTSHADER)
|
||||
// Swiftshader OpenGLES support is deprecated and incomplete
|
||||
return nullptr;
|
||||
#elif defined(__ANDROID__)
|
||||
return new PlatformEGLAndroid();
|
||||
@@ -170,14 +169,14 @@ DefaultPlatform* DefaultPlatform::create(Backend* backend) noexcept {
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
return new PlatformWebGL();
|
||||
#else
|
||||
return new PlatformDummyGL();
|
||||
return nullptr;
|
||||
#endif
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
// destroys an Platform create by create()
|
||||
// destroys a Platform created by create()
|
||||
void DefaultPlatform::destroy(DefaultPlatform** platform) noexcept {
|
||||
delete *platform;
|
||||
*platform = nullptr;
|
||||
@@ -185,5 +184,4 @@ void DefaultPlatform::destroy(DefaultPlatform** platform) noexcept {
|
||||
|
||||
DefaultPlatform::~DefaultPlatform() noexcept = default;
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -14,34 +14,49 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "private/backend/Program.h"
|
||||
|
||||
using namespace utils;
|
||||
#include "backend/Program.h"
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
// We want these in the .cpp file so they're not inlined (not worth it)
|
||||
Program::Program() noexcept {} // = default; does not work with msvc because of noexcept
|
||||
using namespace utils;
|
||||
|
||||
// We want these in the .cpp file, so they're not inlined (not worth it)
|
||||
Program::Program() noexcept { // NOLINT(modernize-use-equals-default)
|
||||
}
|
||||
|
||||
Program::Program(Program&& rhs) noexcept = default;
|
||||
Program& Program::operator=(Program&& rhs) noexcept = default;
|
||||
|
||||
Program& Program::operator=(Program&& rhs) noexcept {
|
||||
mUniformBlocks.operator=(rhs.mUniformBlocks);
|
||||
mSamplerGroups.operator=(std::move(rhs.mSamplerGroups));
|
||||
mShadersSource.operator=(std::move(rhs.mShadersSource));
|
||||
mName.operator=(std::move(rhs.mName));
|
||||
mLogger.operator=(std::move(rhs.mLogger));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program::~Program() noexcept = default;
|
||||
|
||||
Program& Program::diagnostics(utils::CString const& name,
|
||||
utils::Invocable<io::ostream&(utils::io::ostream&)>&& logger) {
|
||||
Program& Program::diagnostics(CString const& name,
|
||||
Invocable<io::ostream&(io::ostream&)>&& logger) {
|
||||
mName = name;
|
||||
mLogger = std::move(logger);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::shader(Program::Shader shader, void const* data, size_t size) noexcept {
|
||||
Program& Program::shader(ShaderStage shader, void const* data, size_t size) {
|
||||
ShaderBlob blob(size);
|
||||
std::copy_n((const uint8_t *)data, size, blob.data());
|
||||
mShadersSource[size_t(shader)] = std::move(blob);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::setUniformBlock(size_t bindingPoint, std::string_view uniformBlockName) noexcept {
|
||||
mUniformBlocks[bindingPoint] = { uniformBlockName.data(), uniformBlockName.size() };
|
||||
Program& Program::uniformBlockBindings(
|
||||
FixedCapacityVector<std::pair<utils::CString, uint8_t>> const& uniformBlockBindings) noexcept {
|
||||
for (auto const& item : uniformBlockBindings) {
|
||||
assert_invariant(item.second < UNIFORM_BINDING_COUNT);
|
||||
mUniformBlocks[item.second] = item.first;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -53,7 +68,12 @@ Program& Program::setSamplerGroup(size_t bindingPoint, ShaderStageFlags stageFla
|
||||
samplerList.reserve(count);
|
||||
samplerList.resize(count);
|
||||
std::copy_n(samplers, count, samplerList.data());
|
||||
mHasSamplers = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::specializationConstants(
|
||||
FixedCapacityVector<SpecializationConstant> specConstants) noexcept {
|
||||
mSpecializationConstants = std::move(specConstants);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -64,4 +84,5 @@ io::ostream& operator<<(io::ostream& out, const Program& builder) {
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -91,12 +91,14 @@ blitterFrag(VertexOut in [[stage_in]],
|
||||
{
|
||||
FragmentOut out = {};
|
||||
|
||||
#if defined(BLIT_COLOR) || defined(BLIT_DEPTH)
|
||||
// These coordinates match the Vulkan vkCmdBlitImage spec:
|
||||
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCmdBlitImage.html
|
||||
float2 uvbase = in.position.xy; // unnormalized coordinates at center of texel: (1.5, 2.5, etc)
|
||||
float2 uvoffset = uvbase - args->dstOffset;
|
||||
float2 uvscaled = uvoffset * args->scale;
|
||||
float2 uv = uvscaled + args->srcOffset;
|
||||
#endif
|
||||
|
||||
#ifdef BLIT_COLOR
|
||||
#ifdef MSAA_COLOR_SOURCE
|
||||
|
||||
@@ -24,13 +24,18 @@
|
||||
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class MetalBuffer {
|
||||
public:
|
||||
|
||||
MetalBuffer(MetalContext& context, BufferUsage usage, size_t size, bool forceGpuBuffer = false);
|
||||
MetalBuffer(MetalContext& context, BufferObjectBinding bindingType, BufferUsage usage,
|
||||
size_t size, bool forceGpuBuffer = false);
|
||||
~MetalBuffer();
|
||||
|
||||
MetalBuffer(const MetalBuffer& rhs) = delete;
|
||||
@@ -57,18 +62,21 @@ public:
|
||||
|
||||
void* getCpuBuffer() const noexcept { return mCpuBuffer; }
|
||||
|
||||
enum Stage {
|
||||
VERTEX = 1,
|
||||
FRAGMENT = 2
|
||||
enum Stage : uint8_t {
|
||||
VERTEX = 1u << 0u,
|
||||
FRAGMENT = 1u << 1u,
|
||||
COMPUTE = 1u << 2u
|
||||
};
|
||||
|
||||
/**
|
||||
* Bind multiple buffers to pipeline stages.
|
||||
*
|
||||
* bindBuffers binds an array of buffers to the given stage(s) of a MTLRenderCommandEncoder's
|
||||
* pipeline.
|
||||
* bindBuffers binds an array of buffers to the given stage(s) of a MTLCommandEncoders's
|
||||
* pipeline. The encoder must be either a MTLRenderCommandEncoder or a MTLComputeCommandEncoder.
|
||||
* For MTLRenderCommandEncoders, only the VERTEX and FRAGMENT stages may be specified.
|
||||
* For MTLComputeCommandEncoders, only the COMPUTE stage may be specified.
|
||||
*/
|
||||
static void bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLRenderCommandEncoder> encoder,
|
||||
static void bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLCommandEncoder> encoder,
|
||||
size_t bufferStart, uint8_t stages, MetalBuffer* const* buffers, size_t const* offsets,
|
||||
size_t count);
|
||||
|
||||
@@ -80,7 +88,122 @@ private:
|
||||
MetalContext& mContext;
|
||||
};
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
template <typename TYPE>
|
||||
static inline TYPE align(TYPE p, size_t alignment) noexcept {
|
||||
// alignment must be a power-of-two
|
||||
assert(alignment && !(alignment & alignment-1));
|
||||
return (TYPE)((p + alignment - 1) & ~(alignment - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages a single id<MTLBuffer>, allowing sub-allocations in a "ring" fashion. Each slot in the
|
||||
* buffer has a fixed size. When a new allocation is made, previous allocations become available
|
||||
* when the current id<MTLCommandBuffer> has finished executing on the GPU.
|
||||
*
|
||||
* If there are no slots available when a new allocation is requested, MetalRingBuffer falls back to
|
||||
* allocating a new id<MTLBuffer> per allocation until a slot is freed.
|
||||
*
|
||||
* All methods must be called from the Metal backend thread.
|
||||
*/
|
||||
class MetalRingBuffer {
|
||||
public:
|
||||
// In practice, MetalRingBuffer is used for argument buffers, which are kept in the constant
|
||||
// address space. Constant buffers have specific alignment requirements when specifying an
|
||||
// offset.
|
||||
#if defined(IOS)
|
||||
#if TARGET_OS_SIMULATOR
|
||||
// The iOS simulator has differing alignment requirements.
|
||||
static constexpr auto METAL_CONSTANT_BUFFER_OFFSET_ALIGNMENT = 256;
|
||||
#else
|
||||
static constexpr auto METAL_CONSTANT_BUFFER_OFFSET_ALIGNMENT = 4;
|
||||
#endif // TARGET_OS_SIMULATOR
|
||||
#else
|
||||
static constexpr auto METAL_CONSTANT_BUFFER_OFFSET_ALIGNMENT = 32;
|
||||
#endif
|
||||
static inline auto computeSlotSize(MTLSizeAndAlign layout) {
|
||||
return align(align(layout.size, layout.align), METAL_CONSTANT_BUFFER_OFFSET_ALIGNMENT);
|
||||
}
|
||||
|
||||
MetalRingBuffer(id<MTLDevice> device, MTLResourceOptions options, MTLSizeAndAlign layout,
|
||||
NSUInteger slotCount)
|
||||
: mDevice(device),
|
||||
mAuxBuffer(nil),
|
||||
mBufferOptions(options),
|
||||
mSlotSizeBytes(computeSlotSize(layout)),
|
||||
mSlotCount(slotCount) {
|
||||
mBuffer = [device newBufferWithLength:mSlotSizeBytes * mSlotCount options:mBufferOptions];
|
||||
assert_invariant(mBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new allocation in the buffer.
|
||||
* @param cmdBuffer When this command buffer has finished executing on the GPU, the previous
|
||||
* ring buffer allocation will be freed.
|
||||
* @return the id<MTLBuffer> and offset for the new allocation
|
||||
*/
|
||||
std::pair<id<MTLBuffer>, NSUInteger> createNewAllocation(id<MTLCommandBuffer> cmdBuffer) {
|
||||
const auto occupiedSlots = mOccupiedSlots->load(std::memory_order_relaxed);
|
||||
assert_invariant(occupiedSlots <= mSlotCount);
|
||||
if (UTILS_UNLIKELY(occupiedSlots == mSlotCount)) {
|
||||
// We don't have any room left, so we fall back to creating a one-off aux buffer.
|
||||
// If we already have an aux buffer, it will get freed here, unless it has been retained
|
||||
// by a MTLCommandBuffer. In that case, it will be freed when the command buffer
|
||||
// finishes executing.
|
||||
mAuxBuffer = [mDevice newBufferWithLength:mSlotSizeBytes options:mBufferOptions];
|
||||
assert_invariant(mAuxBuffer);
|
||||
return {mAuxBuffer, 0};
|
||||
}
|
||||
mCurrentSlot = (mCurrentSlot + 1) % mSlotCount;
|
||||
mOccupiedSlots->fetch_add(1, std::memory_order_relaxed);
|
||||
|
||||
// Release the previous allocation.
|
||||
if (UTILS_UNLIKELY(mAuxBuffer)) {
|
||||
mAuxBuffer = nil;
|
||||
} else {
|
||||
// Capture the mOccupiedSlots var via a weak_ptr because the MetalRingBuffer could be
|
||||
// destructed before the block executes.
|
||||
std::weak_ptr<AtomicCounterType> slots = mOccupiedSlots;
|
||||
[cmdBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
|
||||
if (auto s = slots.lock()) {
|
||||
s->fetch_sub(1, std::memory_order_relaxed);
|
||||
}
|
||||
}];
|
||||
}
|
||||
return getCurrentAllocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an allocation (buffer and offset) that is guaranteed not to be in use by the GPU.
|
||||
* @param cmdBuffer When this command buffer has finished executing on the GPU, the previous
|
||||
* ring buffer allocation will be freed.
|
||||
* @return the id<MTLBuffer> and offset for the current allocation
|
||||
*/
|
||||
std::pair<id<MTLBuffer>, NSUInteger> getCurrentAllocation() const {
|
||||
if (UTILS_UNLIKELY(mAuxBuffer)) {
|
||||
return { mAuxBuffer, 0 };
|
||||
}
|
||||
return { mBuffer, mCurrentSlot * mSlotSizeBytes };
|
||||
}
|
||||
|
||||
bool canAccomodateLayout(MTLSizeAndAlign layout) const {
|
||||
return mSlotSizeBytes >= computeSlotSize(layout);
|
||||
}
|
||||
|
||||
private:
|
||||
id<MTLDevice> mDevice;
|
||||
id<MTLBuffer> mBuffer;
|
||||
id<MTLBuffer> mAuxBuffer;
|
||||
|
||||
MTLResourceOptions mBufferOptions;
|
||||
|
||||
NSUInteger mSlotSizeBytes;
|
||||
NSUInteger mSlotCount;
|
||||
|
||||
NSUInteger mCurrentSlot = 0;
|
||||
using AtomicCounterType = std::atomic<NSUInteger>;
|
||||
std::shared_ptr<AtomicCounterType> mOccupiedSlots = std::make_shared<AtomicCounterType>(1);
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,15 +21,17 @@
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
|
||||
MetalBuffer::MetalBuffer(MetalContext& context, BufferUsage usage, size_t size, bool forceGpuBuffer)
|
||||
: mBufferSize(size), mContext(context) {
|
||||
MetalBuffer::MetalBuffer(MetalContext& context, BufferObjectBinding bindingType, BufferUsage usage,
|
||||
size_t size, bool forceGpuBuffer) : mBufferSize(size), mContext(context) {
|
||||
// If the buffer is less than 4K in size and is updated frequently, we don't use an explicit
|
||||
// buffer. Instead, we use immediate command encoder methods like setVertexBytes:length:atIndex:.
|
||||
if (size <= 4 * 1024 && usage == BufferUsage::DYNAMIC && !forceGpuBuffer) {
|
||||
mBuffer = nil;
|
||||
mCpuBuffer = malloc(size);
|
||||
return;
|
||||
}
|
||||
// This won't work for SSBOs, since they are read/write.
|
||||
if (size <= 4 * 1024 && bindingType != BufferObjectBinding::SHADER_STORAGE &&
|
||||
usage == BufferUsage::DYNAMIC && !forceGpuBuffer) {
|
||||
mBuffer = nil;
|
||||
mCpuBuffer = malloc(size);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we allocate a private GPU buffer.
|
||||
mBuffer = [context.device newBufferWithLength:size options:MTLResourceStorageModePrivate];
|
||||
@@ -93,9 +95,24 @@ id<MTLBuffer> MetalBuffer::getGpuBufferForDraw(id<MTLCommandBuffer> cmdBuffer) n
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
void MetalBuffer::bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLRenderCommandEncoder> encoder,
|
||||
void MetalBuffer::bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLCommandEncoder> encoder,
|
||||
size_t bufferStart, uint8_t stages, MetalBuffer* const* buffers, size_t const* offsets,
|
||||
size_t count) {
|
||||
// Ensure we were given the correct type of encoder:
|
||||
// either a MTLRenderCommandEncoder or a MTLComputeCommandEncoder.
|
||||
if (stages & MetalBuffer::Stage::VERTEX || stages & MetalBuffer::Stage::FRAGMENT) {
|
||||
assert_invariant([encoder respondsToSelector:@selector(setVertexBuffers:offsets:withRange:)]);
|
||||
assert_invariant([encoder respondsToSelector:@selector(setFragmentBuffers:offsets:withRange:)]);
|
||||
assert_invariant([encoder respondsToSelector:@selector(setVertexBytes:length:atIndex:)]);
|
||||
assert_invariant([encoder respondsToSelector:@selector(setFragmentBytes:length:atIndex:)]);
|
||||
assert_invariant(!(stages & MetalBuffer::Stage::COMPUTE));
|
||||
}
|
||||
if (stages & MetalBuffer::Stage::COMPUTE) {
|
||||
assert_invariant([encoder respondsToSelector:@selector(setBuffers:offsets:withRange:)]);
|
||||
assert_invariant([encoder respondsToSelector:@selector(setBytes:length:atIndex:)]);
|
||||
assert_invariant(!(stages & (MetalBuffer::Stage::FRAGMENT | MetalBuffer::Stage::VERTEX)));
|
||||
}
|
||||
|
||||
const NSRange bufferRange = NSMakeRange(bufferStart, count);
|
||||
|
||||
constexpr size_t MAX_BUFFERS = 16;
|
||||
@@ -120,14 +137,19 @@ void MetalBuffer::bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLRenderComman
|
||||
}
|
||||
|
||||
if (stages & Stage::VERTEX) {
|
||||
[encoder setVertexBuffers:metalBuffers.data()
|
||||
offsets:metalOffsets.data()
|
||||
withRange:bufferRange];
|
||||
[(id<MTLRenderCommandEncoder>) encoder setVertexBuffers:metalBuffers.data()
|
||||
offsets:metalOffsets.data()
|
||||
withRange:bufferRange];
|
||||
}
|
||||
if (stages & Stage::FRAGMENT) {
|
||||
[encoder setFragmentBuffers:metalBuffers.data()
|
||||
offsets:metalOffsets.data()
|
||||
withRange:bufferRange];
|
||||
[(id<MTLRenderCommandEncoder>) encoder setFragmentBuffers:metalBuffers.data()
|
||||
offsets:metalOffsets.data()
|
||||
withRange:bufferRange];
|
||||
}
|
||||
if (stages & Stage::COMPUTE) {
|
||||
[(id<MTLComputeCommandEncoder>) encoder setBuffers:metalBuffers.data()
|
||||
offsets:metalOffsets.data()
|
||||
withRange:bufferRange];
|
||||
}
|
||||
|
||||
for (size_t b = 0; b < count; b++) {
|
||||
@@ -146,14 +168,22 @@ void MetalBuffer::bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLRenderComman
|
||||
auto* bytes = static_cast<const uint8_t*>(cpuBuffer);
|
||||
|
||||
if (stages & Stage::VERTEX) {
|
||||
[encoder setVertexBytes:(bytes + offset)
|
||||
length:(buffer->getSize() - offset)
|
||||
atIndex:bufferIndex];
|
||||
[(id<MTLRenderCommandEncoder>) encoder setVertexBytes:(bytes + offset)
|
||||
length:(buffer->getSize() - offset)
|
||||
atIndex:bufferIndex];
|
||||
}
|
||||
if (stages & Stage::FRAGMENT) {
|
||||
[encoder setFragmentBytes:(bytes + offset)
|
||||
length:(buffer->getSize() - offset)
|
||||
atIndex:bufferIndex];
|
||||
[(id<MTLRenderCommandEncoder>) encoder setFragmentBytes:(bytes + offset)
|
||||
length:(buffer->getSize() - offset)
|
||||
atIndex:bufferIndex];
|
||||
}
|
||||
if (stages & Stage::COMPUTE) {
|
||||
// TODO: using setBytes means the data is read-only, which currently isn't enforced.
|
||||
// In practice this won't be an issue since MetalBuffer ensures all SSBOs are realized
|
||||
// through actual id<MTLBuffer> allocations.
|
||||
[(id<MTLComputeCommandEncoder>) encoder setBytes:(bytes + offset)
|
||||
length:(buffer->getSize() - offset)
|
||||
atIndex:bufferIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <QuartzCore/QuartzCore.h>
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <stack>
|
||||
|
||||
#if defined(FILAMENT_METAL_PROFILING)
|
||||
@@ -41,11 +42,12 @@ class MetalDriver;
|
||||
class MetalBlitter;
|
||||
class MetalBufferPool;
|
||||
class MetalRenderTarget;
|
||||
class MetalSamplerGroup;
|
||||
class MetalSwapChain;
|
||||
class MetalTexture;
|
||||
class MetalTimerQueryInterface;
|
||||
struct MetalUniformBuffer;
|
||||
struct MetalIndexBuffer;
|
||||
struct MetalSamplerGroup;
|
||||
struct MetalVertexBuffer;
|
||||
|
||||
constexpr static uint8_t MAX_SAMPLE_COUNT = 8; // Metal devices support at most 8 MSAA samples
|
||||
@@ -58,8 +60,12 @@ struct MetalContext {
|
||||
id<MTLCommandBuffer> pendingCommandBuffer = nullptr;
|
||||
id<MTLRenderCommandEncoder> currentRenderPassEncoder = nullptr;
|
||||
|
||||
std::atomic<bool> memorylessLimitsReached = false;
|
||||
|
||||
// Supported features.
|
||||
bool supportsTextureSwizzling = false;
|
||||
bool supportsAutoDepthResolve = false;
|
||||
bool supportsMemorylessRenderTargets = false;
|
||||
uint8_t maxColorRenderTargets = 4;
|
||||
struct {
|
||||
uint8_t common;
|
||||
@@ -79,7 +85,8 @@ struct MetalContext {
|
||||
// State trackers.
|
||||
PipelineStateTracker pipelineState;
|
||||
DepthStencilStateTracker depthStencilState;
|
||||
UniformBufferState uniformState[VERTEX_BUFFER_START];
|
||||
std::array<BufferState, Program::UNIFORM_BINDING_COUNT> uniformState;
|
||||
std::array<BufferState, MAX_SSBO_COUNT> ssboState;
|
||||
CullModeStateTracker cullModeState;
|
||||
WindingStateTracker windingState;
|
||||
|
||||
@@ -87,11 +94,16 @@ struct MetalContext {
|
||||
DepthStencilStateCache depthStencilStateCache;
|
||||
PipelineStateCache pipelineStateCache;
|
||||
SamplerStateCache samplerStateCache;
|
||||
ArgumentEncoderCache argumentEncoderCache;
|
||||
|
||||
MetalSamplerGroup* samplerBindings[SAMPLER_BINDING_COUNT] = {};
|
||||
MetalSamplerGroup* samplerBindings[Program::SAMPLER_BINDING_COUNT] = {};
|
||||
|
||||
// Keeps track of all alive sampler groups.
|
||||
// Keeps track of sampler groups we've finalized for the current render pass.
|
||||
tsl::robin_set<MetalSamplerGroup*> finalizedSamplerGroups;
|
||||
|
||||
// Keeps track of all alive sampler groups, textures.
|
||||
tsl::robin_set<MetalSamplerGroup*> samplerGroups;
|
||||
tsl::robin_set<MetalTexture*> textures;
|
||||
|
||||
MetalBufferPool* bufferPool;
|
||||
|
||||
|
||||
@@ -103,6 +103,15 @@ id<MTLCommandBuffer> getPendingCommandBuffer(MetalContext* context) {
|
||||
// all frames and their completion handlers finish before context is deallocated.
|
||||
[context->pendingCommandBuffer addCompletedHandler:^(id <MTLCommandBuffer> buffer) {
|
||||
context->resourceTracker.clearResources((__bridge void*) buffer);
|
||||
|
||||
auto errorCode = (MTLCommandBufferError)buffer.error.code;
|
||||
if (@available(macOS 11.0, *)) {
|
||||
if (errorCode == MTLCommandBufferErrorMemoryless) {
|
||||
utils::slog.w << "Metal: memoryless geometry limit reached. "
|
||||
"Continuing with private storage mode." << utils::io::endl;
|
||||
context->memorylessLimitsReached = true;
|
||||
}
|
||||
}
|
||||
}];
|
||||
ASSERT_POSTCONDITION(context->pendingCommandBuffer, "Could not obtain command buffer.");
|
||||
return context->pendingCommandBuffer;
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#include "private/backend/HandleAllocator.h"
|
||||
|
||||
#include <backend/SamplerDescriptor.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/debug.h>
|
||||
@@ -32,10 +34,12 @@ namespace backend {
|
||||
class MetalPlatform;
|
||||
|
||||
class MetalBuffer;
|
||||
class MetalSamplerGroup;
|
||||
class MetalTexture;
|
||||
struct MetalUniformBuffer;
|
||||
struct MetalContext;
|
||||
struct MetalProgram;
|
||||
struct UniformBufferState;
|
||||
struct BufferState;
|
||||
|
||||
#ifndef FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB
|
||||
#define FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB 8
|
||||
@@ -124,10 +128,9 @@ private:
|
||||
inline void setRenderPrimitiveRange(Handle<HwRenderPrimitive> rph, PrimitiveType pt,
|
||||
uint32_t offset, uint32_t minIndex, uint32_t maxIndex, uint32_t count);
|
||||
|
||||
void enumerateSamplerGroups(const MetalProgram* program, ShaderType shaderType,
|
||||
const std::function<void(const SamplerDescriptor*, size_t)>& f);
|
||||
void enumerateBoundUniformBuffers(const std::function<void(const UniformBufferState&,
|
||||
MetalBuffer*, uint32_t)>& f);
|
||||
void finalizeSamplerGroup(MetalSamplerGroup* sg);
|
||||
void enumerateBoundBuffers(BufferObjectBinding bindingType,
|
||||
const std::function<void(const BufferState&, MetalBuffer*, uint32_t)>& f);
|
||||
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -52,7 +52,7 @@ constexpr inline MTLCompareFunction getMetalCompareFunction(RasterState::DepthFu
|
||||
}
|
||||
}
|
||||
|
||||
constexpr inline MTLStencilOperation getMetalStencilOperation(RasterState::StencilOperation op) {
|
||||
constexpr inline MTLStencilOperation getMetalStencilOperation(StencilOperation op) {
|
||||
switch (op) {
|
||||
case StencilOperation::KEEP: return MTLStencilOperationKeep;
|
||||
case StencilOperation::ZERO: return MTLStencilOperationZero;
|
||||
@@ -262,6 +262,22 @@ constexpr inline bool isMetalFormatInteger(MTLPixelFormat format) {
|
||||
}
|
||||
}
|
||||
|
||||
constexpr inline bool isMetalFormatStencil(MTLPixelFormat format) {
|
||||
switch (format) {
|
||||
case MTLPixelFormatStencil8:
|
||||
case MTLPixelFormatDepth32Float_Stencil8:
|
||||
case MTLPixelFormatX32_Stencil8:
|
||||
#if !defined(IOS)
|
||||
case MTLPixelFormatDepth24Unorm_Stencil8:
|
||||
case MTLPixelFormatX24_Stencil8:
|
||||
#endif
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr inline MTLTextureType getMetalType(SamplerType target) {
|
||||
switch (target) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
@@ -321,8 +337,6 @@ constexpr inline MTLPrimitiveType getMetalPrimitiveType(PrimitiveType type) noex
|
||||
case PrimitiveType::LINE_STRIP: return MTLPrimitiveTypeLineStrip;
|
||||
case PrimitiveType::TRIANGLES: return MTLPrimitiveTypeTriangle;
|
||||
case PrimitiveType::TRIANGLE_STRIP: return MTLPrimitiveTypeTriangleStrip;
|
||||
case PrimitiveType::NONE:
|
||||
ASSERT_POSTCONDITION(false, "NONE is not a valid primitive type.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,14 @@
|
||||
#include "MetalExternalImage.h"
|
||||
#include "MetalState.h" // for MetalState::VertexDescription
|
||||
|
||||
#include "private/backend/SamplerGroup.h"
|
||||
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <math/vec2.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
@@ -114,15 +118,18 @@ private:
|
||||
|
||||
class MetalBufferObject : public HwBufferObject {
|
||||
public:
|
||||
MetalBufferObject(MetalContext& context, BufferUsage usage, uint32_t byteCount);
|
||||
MetalBufferObject(MetalContext& context, BufferObjectBinding bindingType, BufferUsage usage,
|
||||
uint32_t byteCount);
|
||||
|
||||
void updateBuffer(void* data, size_t size, uint32_t byteOffset);
|
||||
void updateBufferUnsynchronized(void* data, size_t size, uint32_t byteOffset);
|
||||
MetalBuffer* getBuffer() { return &buffer; }
|
||||
|
||||
// Tracks which uniform buffers this buffer object is bound into.
|
||||
static_assert(Program::BINDING_COUNT <= 32);
|
||||
// Tracks which uniform/ssbo buffers this buffer object is bound into.
|
||||
static_assert(Program::UNIFORM_BINDING_COUNT <= 32);
|
||||
static_assert(MAX_SSBO_COUNT <= 32);
|
||||
utils::bitset32 boundUniformBuffers;
|
||||
utils::bitset32 boundSsbos;
|
||||
|
||||
private:
|
||||
MetalBuffer buffer;
|
||||
@@ -159,14 +166,9 @@ struct MetalProgram : public HwProgram {
|
||||
|
||||
id<MTLFunction> vertexFunction;
|
||||
id<MTLFunction> fragmentFunction;
|
||||
id<MTLFunction> computeFunction;
|
||||
|
||||
struct SamplerBlockInfo {
|
||||
uint8_t samplerGroup = UINT8_MAX;
|
||||
uint8_t sampler = UINT8_MAX;
|
||||
};
|
||||
|
||||
std::array<SamplerBlockInfo, MAX_VERTEX_SAMPLER_COUNT> vertexSamplerBlockInfo;
|
||||
std::array<SamplerBlockInfo, MAX_FRAGMENT_SAMPLER_COUNT> fragmentSamplerBlockInfo;
|
||||
Program::SamplerGroupInfo samplerGroupInfo;
|
||||
|
||||
bool isValid = false;
|
||||
};
|
||||
@@ -184,7 +186,8 @@ struct PixelBufferShape {
|
||||
MTLSize size, uint32_t byteOffset);
|
||||
};
|
||||
|
||||
struct MetalTexture : public HwTexture {
|
||||
class MetalTexture : public HwTexture {
|
||||
public:
|
||||
MetalTexture(MetalContext& context, SamplerType target, uint8_t levels, TextureFormat format,
|
||||
uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
||||
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a)
|
||||
@@ -197,40 +200,144 @@ struct MetalTexture : public HwTexture {
|
||||
|
||||
~MetalTexture();
|
||||
|
||||
// Returns an id<MTLTexture> suitable for reading in a shader, taking into account swizzle and
|
||||
// LOD clamping.
|
||||
id<MTLTexture> getMtlTextureForRead() noexcept;
|
||||
|
||||
// Returns the id<MTLTexture> for attaching to a render pass.
|
||||
id<MTLTexture> getMtlTextureForWrite() noexcept {
|
||||
return texture;
|
||||
}
|
||||
|
||||
void loadImage(uint32_t level, MTLRegion region, PixelBufferDescriptor& p) noexcept;
|
||||
void loadSlice(uint32_t level, MTLRegion region, uint32_t byteOffset, uint32_t slice,
|
||||
PixelBufferDescriptor const& data) noexcept;
|
||||
void loadWithCopyBuffer(uint32_t level, uint32_t slice, MTLRegion region, PixelBufferDescriptor const& data,
|
||||
const PixelBufferShape& shape);
|
||||
void loadWithBlit(uint32_t level, uint32_t slice, MTLRegion region, PixelBufferDescriptor const& data,
|
||||
const PixelBufferShape& shape);
|
||||
void generateMipmaps() noexcept;
|
||||
|
||||
// A texture starts out with none of its mip levels (also referred to as LODs) available for
|
||||
// reading. 3 actions update the range of LODs available:
|
||||
// - calling loadImage
|
||||
// - calling generateMipmaps
|
||||
// - using the texture as a render target attachment
|
||||
// The range of available mips can only increase, never decrease.
|
||||
// A texture's available mips are consistent throughout a render pass.
|
||||
void updateLodRange(uint32_t level);
|
||||
void updateLodRange(uint32_t minLevel, uint32_t maxLevel);
|
||||
|
||||
// Returns true if the texture has all of its mip levels accessible for reading.
|
||||
// For any MetalTexture, once this is true, will always return true.
|
||||
// The value returned will remain consistent for an entire render pass.
|
||||
bool allLodsValid() const {
|
||||
return minLod == 0 && maxLod == levels - 1;
|
||||
}
|
||||
|
||||
static MTLPixelFormat decidePixelFormat(MetalContext* context, TextureFormat format);
|
||||
|
||||
MetalContext& context;
|
||||
MetalExternalImage externalImage;
|
||||
id<MTLTexture> texture = nil;
|
||||
|
||||
// A "sidecar" texture used to implement automatic MSAA resolve.
|
||||
// This is created by MetalRenderTarget and stored here so it can be used with multiple
|
||||
// render targets.
|
||||
id<MTLTexture> msaaSidecar = nil;
|
||||
|
||||
MTLPixelFormat devicePixelFormat;
|
||||
|
||||
private:
|
||||
void loadSlice(uint32_t level, MTLRegion region, uint32_t byteOffset, uint32_t slice,
|
||||
PixelBufferDescriptor const& data) noexcept;
|
||||
void loadWithCopyBuffer(uint32_t level, uint32_t slice, MTLRegion region, PixelBufferDescriptor const& data,
|
||||
const PixelBufferShape& shape);
|
||||
void loadWithBlit(uint32_t level, uint32_t slice, MTLRegion region, PixelBufferDescriptor const& data,
|
||||
const PixelBufferShape& shape);
|
||||
|
||||
id<MTLTexture> texture = nil;
|
||||
|
||||
// If non-nil, a swizzled texture view to use instead of "texture".
|
||||
// Filament swizzling only affects texture reads, so this should not be used when the texture is
|
||||
// bound as a render target attachment.
|
||||
id<MTLTexture> swizzledTextureView = nil;
|
||||
id<MTLTexture> lodTextureView = nil;
|
||||
|
||||
MTLPixelFormat devicePixelFormat;
|
||||
uint32_t minLod = UINT_MAX;
|
||||
uint32_t maxLod = 0;
|
||||
};
|
||||
|
||||
struct MetalSamplerGroup : public HwSamplerGroup {
|
||||
// NOTE: we have to use out-of-line allocation here because the size of a Handle<> is limited
|
||||
std::unique_ptr<SamplerGroup> sb; // FIXME: this shouldn't depend on filament::SamplerGroup
|
||||
explicit MetalSamplerGroup(size_t size) noexcept : sb(new SamplerGroup(size)) { }
|
||||
class MetalSamplerGroup : public HwSamplerGroup {
|
||||
public:
|
||||
explicit MetalSamplerGroup(size_t size) noexcept
|
||||
: size(size),
|
||||
textureHandles(size, Handle<HwTexture>()),
|
||||
textures(size, nil),
|
||||
samplers(size, nil) {}
|
||||
|
||||
inline void setTextureHandle(size_t index, Handle<HwTexture> th) {
|
||||
assert_invariant(!finalized);
|
||||
textureHandles[index] = th;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// This method is only used for debugging, to ensure all texture handles are alive.
|
||||
const auto& getTextureHandles() const {
|
||||
return textureHandles;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Encode a MTLTexture into this SamplerGroup at the given index.
|
||||
inline void setFinalizedTexture(size_t index, id<MTLTexture> t) {
|
||||
assert_invariant(!finalized);
|
||||
textures[index] = t;
|
||||
}
|
||||
|
||||
// Encode a MTLSamplerState into this SamplerGroup at the given index.
|
||||
inline void setFinalizedSampler(size_t index, id<MTLSamplerState> s) {
|
||||
assert_invariant(!finalized);
|
||||
samplers[index] = s;
|
||||
}
|
||||
|
||||
// A SamplerGroup is "finalized" when all of its textures have been set and is ready for use in
|
||||
// a draw call.
|
||||
// Once a SamplerGroup is finalized, it must be reset or mutated to be written into again.
|
||||
void finalize();
|
||||
bool isFinalized() const noexcept { return finalized; }
|
||||
|
||||
// Both of these methods "unfinalize" a SamplerGroup, allowing it to be updated via calls to
|
||||
// setFinalizedTexture or setFinalizedSampler. The difference is that when reset is called, all
|
||||
// the samplers/textures must be rebound. The MTLArgumentEncoder must be specified, in case
|
||||
// the texture types have changed.
|
||||
// Mutate re-encodes the current set of samplers/textures into the new argument
|
||||
// buffer.
|
||||
void reset(id<MTLCommandBuffer> cmdBuffer, id<MTLArgumentEncoder> e, id<MTLDevice> device);
|
||||
void mutate(id<MTLCommandBuffer> cmdBuffer);
|
||||
|
||||
id<MTLBuffer> getArgumentBuffer() const {
|
||||
assert_invariant(finalized);
|
||||
return argBuffer->getCurrentAllocation().first;
|
||||
}
|
||||
|
||||
NSUInteger getArgumentBufferOffset() const {
|
||||
return argBuffer->getCurrentAllocation().second;
|
||||
}
|
||||
|
||||
inline std::pair<Handle<HwTexture>, id<MTLTexture>> getFinalizedTexture(size_t index) {
|
||||
return {textureHandles[index], textures[index]};
|
||||
}
|
||||
|
||||
// Calls the Metal useResource:usage:stages: method for all the textures in this SamplerGroup.
|
||||
void useResources(id<MTLRenderCommandEncoder> renderPassEncoder);
|
||||
|
||||
size_t size;
|
||||
|
||||
public:
|
||||
|
||||
// These vectors are kept in sync with one another.
|
||||
utils::FixedCapacityVector<Handle<HwTexture>> textureHandles;
|
||||
utils::FixedCapacityVector<id<MTLTexture>> textures;
|
||||
utils::FixedCapacityVector<id<MTLSamplerState>> samplers;
|
||||
|
||||
id<MTLArgumentEncoder> encoder;
|
||||
|
||||
std::unique_ptr<MetalRingBuffer> argBuffer = nullptr;
|
||||
|
||||
bool finalized = false;
|
||||
};
|
||||
|
||||
class MetalRenderTarget : public HwRenderTarget {
|
||||
@@ -244,7 +351,7 @@ public:
|
||||
Attachment() = default;
|
||||
Attachment(MetalTexture* metalTexture, uint8_t level = 0, uint16_t layer = 0) :
|
||||
level(level), layer(layer),
|
||||
texture(metalTexture->texture),
|
||||
texture(metalTexture->getMtlTextureForWrite()),
|
||||
metalTexture(metalTexture) { }
|
||||
|
||||
id<MTLTexture> getTexture() const {
|
||||
@@ -286,8 +393,21 @@ public:
|
||||
|
||||
void setUpRenderPassAttachments(MTLRenderPassDescriptor* descriptor, const RenderPassParams& params);
|
||||
|
||||
MTLViewport getViewportFromClientViewport(
|
||||
Viewport rect, float depthRangeNear, float depthRangeFar) {
|
||||
const int32_t height = int32_t(getAttachmentSize().y);
|
||||
assert_invariant(height > 0);
|
||||
|
||||
// Metal's viewport coordinates have (0, 0) at the top-left, but Filament's have (0, 0) at
|
||||
// bottom-left.
|
||||
return {double(rect.left),
|
||||
double(height - rect.bottom - int32_t(rect.height)),
|
||||
double(rect.width), double(rect.height),
|
||||
double(depthRangeNear), double(depthRangeFar)};
|
||||
}
|
||||
|
||||
MTLRegion getRegionFromClientRect(Viewport rect) {
|
||||
const uint32_t height = getAttachmentHeight();
|
||||
const uint32_t height = getAttachmentSize().y;
|
||||
assert_invariant(height > 0);
|
||||
|
||||
// Convert the Filament rect into Metal texture coordinates, taking into account Metal's
|
||||
@@ -299,6 +419,8 @@ public:
|
||||
rect.width, rect.height);
|
||||
}
|
||||
|
||||
math::uint2 getAttachmentSize() noexcept;
|
||||
|
||||
bool isDefaultRenderTarget() const { return defaultRenderTarget; }
|
||||
uint8_t getSamples() const { return samples; }
|
||||
|
||||
@@ -311,10 +433,7 @@ private:
|
||||
|
||||
static MTLLoadAction getLoadAction(const RenderPassParams& params, TargetBufferFlags buffer);
|
||||
static MTLStoreAction getStoreAction(const RenderPassParams& params, TargetBufferFlags buffer);
|
||||
static id<MTLTexture> createMultisampledTexture(id<MTLDevice> device, MTLPixelFormat format,
|
||||
uint32_t width, uint32_t height, uint8_t samples);
|
||||
|
||||
uint32_t getAttachmentHeight() noexcept;
|
||||
id<MTLTexture> createMultisampledTexture(MTLPixelFormat format, uint32_t width, uint32_t height, uint8_t samples) const;
|
||||
|
||||
MetalContext* context;
|
||||
bool defaultRenderTarget = false;
|
||||
@@ -323,7 +442,7 @@ private:
|
||||
Attachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
||||
Attachment depth = {};
|
||||
Attachment stencil = {};
|
||||
uint32_t attachmentHeight = 0;
|
||||
math::uint2 attachmentSize = {};
|
||||
};
|
||||
|
||||
// MetalFence is used to implement both Fences and Syncs.
|
||||
|
||||
@@ -22,13 +22,15 @@
|
||||
|
||||
#include <filament/SwapChain.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include "private/backend/BackendUtils.h"
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/trap.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <math/vec2.h>
|
||||
#include <math/scalar.h>
|
||||
|
||||
#include <math.h>
|
||||
@@ -269,8 +271,9 @@ void MetalSwapChain::scheduleFrameCompletedCallback() {
|
||||
}];
|
||||
}
|
||||
|
||||
MetalBufferObject::MetalBufferObject(MetalContext& context, BufferUsage usage, uint32_t byteCount)
|
||||
: HwBufferObject(byteCount), buffer(context, usage, byteCount) {}
|
||||
MetalBufferObject::MetalBufferObject(MetalContext& context, BufferObjectBinding bindingType,
|
||||
BufferUsage usage, uint32_t byteCount)
|
||||
: HwBufferObject(byteCount), buffer(context, bindingType, usage, byteCount) {}
|
||||
|
||||
void MetalBufferObject::updateBuffer(void* data, size_t size, uint32_t byteOffset) {
|
||||
buffer.copyIntoBuffer(data, size, byteOffset);
|
||||
@@ -286,7 +289,7 @@ MetalVertexBuffer::MetalVertexBuffer(MetalContext& context, uint8_t bufferCount,
|
||||
|
||||
MetalIndexBuffer::MetalIndexBuffer(MetalContext& context, BufferUsage usage, uint8_t elementSize,
|
||||
uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount),
|
||||
buffer(context, usage, elementSize * indexCount, true) { }
|
||||
buffer(context, BufferObjectBinding::VERTEX, usage, elementSize * indexCount, true) { }
|
||||
|
||||
void MetalRenderPrimitive::setBuffers(MetalVertexBuffer* vertexBuffer, MetalIndexBuffer*
|
||||
indexBuffer) {
|
||||
@@ -297,9 +300,8 @@ void MetalRenderPrimitive::setBuffers(MetalVertexBuffer* vertexBuffer, MetalInde
|
||||
|
||||
vertexDescription = {};
|
||||
|
||||
// Each attribute gets its own vertex buffer.
|
||||
|
||||
uint32_t bufferIndex = 0;
|
||||
// Each attribute gets its own vertex buffer, starting at logical buffer 1.
|
||||
uint32_t bufferIndex = 1;
|
||||
for (uint32_t attributeIndex = 0; attributeIndex < attributeCount; attributeIndex++) {
|
||||
const auto& attribute = vertexBuffer->attributes[attributeIndex];
|
||||
if (attribute.buffer == Attribute::BUFFER_UNUSED) {
|
||||
@@ -311,10 +313,10 @@ void MetalRenderPrimitive::setBuffers(MetalVertexBuffer* vertexBuffer, MetalInde
|
||||
// shader to read from missing vertex attributes.
|
||||
vertexDescription.attributes[attributeIndex] = {
|
||||
.format = format,
|
||||
.buffer = ZERO_VERTEX_BUFFER,
|
||||
.buffer = ZERO_VERTEX_BUFFER_LOGICAL_INDEX,
|
||||
.offset = 0
|
||||
};
|
||||
vertexDescription.layouts[ZERO_VERTEX_BUFFER] = {
|
||||
vertexDescription.layouts[ZERO_VERTEX_BUFFER_LOGICAL_INDEX] = {
|
||||
.step = MTLVertexStepFunctionConstant,
|
||||
.stride = 16
|
||||
};
|
||||
@@ -338,12 +340,12 @@ void MetalRenderPrimitive::setBuffers(MetalVertexBuffer* vertexBuffer, MetalInde
|
||||
|
||||
MetalProgram::MetalProgram(id<MTLDevice> device, const Program& program) noexcept
|
||||
: HwProgram(program.getName()), vertexFunction(nil), fragmentFunction(nil),
|
||||
isValid(false) {
|
||||
computeFunction(nil), isValid(false) {
|
||||
|
||||
using MetalFunctionPtr = __strong id<MTLFunction>*;
|
||||
|
||||
static_assert(Program::SHADER_TYPE_COUNT == 2, "Only vertex and fragment shaders expected.");
|
||||
MetalFunctionPtr shaderFunctions[2] = { &vertexFunction, &fragmentFunction };
|
||||
static_assert(Program::SHADER_TYPE_COUNT == 3, "Only vertex, fragment, and/or compute shaders expected.");
|
||||
MetalFunctionPtr shaderFunctions[3] = { &vertexFunction, &fragmentFunction, &computeFunction };
|
||||
|
||||
const auto& sources = program.getShadersSource();
|
||||
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
|
||||
@@ -374,51 +376,37 @@ MetalProgram::MetalProgram(id<MTLDevice> device, const Program& program) noexcep
|
||||
return;
|
||||
}
|
||||
|
||||
*shaderFunctions[i] = [library newFunctionWithName:@"main0"];
|
||||
MTLFunctionConstantValues* constants = [MTLFunctionConstantValues new];
|
||||
auto const& specializationConstants = program.getSpecializationConstants();
|
||||
for (auto const& sc : specializationConstants) {
|
||||
const std::array<MTLDataType, 3> types{
|
||||
MTLDataTypeInt, MTLDataTypeFloat, MTLDataTypeBool };
|
||||
std::visit([&sc, constants, type = types[sc.value.index()]](auto&& arg) {
|
||||
[constants setConstantValue:&arg
|
||||
type:type
|
||||
atIndex:sc.id];
|
||||
}, sc.value);
|
||||
}
|
||||
|
||||
id<MTLFunction> function = [library newFunctionWithName:@"main0"
|
||||
constantValues:constants
|
||||
error:&error];
|
||||
assert_invariant(function);
|
||||
*shaderFunctions[i] = function;
|
||||
}
|
||||
|
||||
UTILS_UNUSED_IN_RELEASE const bool isRasterizationProgram =
|
||||
vertexFunction != nil && fragmentFunction != nil;
|
||||
UTILS_UNUSED_IN_RELEASE const bool isComputeProgram = computeFunction != nil;
|
||||
// The program must be either a rasterization program XOR a compute program.
|
||||
assert_invariant(isRasterizationProgram != isComputeProgram);
|
||||
|
||||
// All stages of the program have compiled successfully, this is a valid program.
|
||||
isValid = true;
|
||||
|
||||
// This calculates Metal resource binding indices. Filament's sampler bindings range from 0-31
|
||||
// across both vertex and fragment stages. However, Metal binding indices must be < 16, with a
|
||||
// separate binding "namespace" for each stage. So, we recompute binding indices for each shader
|
||||
// stage. This logic should match updateResourceBinding in GLSLPostProcessor.cpp
|
||||
// This is an example how binding indices each of shader stages is generated from sampler's
|
||||
// bindings. Below is sampler's bindings.
|
||||
// 0 shadowMap { fragment }
|
||||
// 1 structure { fragment }
|
||||
// 2 targets { vertex }
|
||||
// 3 color { vertex | fragment }
|
||||
// 4 depth { vertex | fragment }
|
||||
// Below is generated vertex sampler binding indices.
|
||||
// 0 targets
|
||||
// 1 color
|
||||
// 2 depth
|
||||
// Below is generated fragment sampler binding indices.
|
||||
// 0 shadowMap
|
||||
// 1 structure
|
||||
// 2 color
|
||||
// 3 depth
|
||||
auto& samplerGroupInfo = program.getSamplerGroupInfo();
|
||||
for (size_t shaderType = 0; shaderType != PIPELINE_STAGE_COUNT; ++shaderType) {
|
||||
size_t bindingIdx = 0;
|
||||
auto& samplerBlockInfo = (shaderType == ShaderType::VERTEX) ? vertexSamplerBlockInfo
|
||||
: fragmentSamplerBlockInfo;
|
||||
for (size_t samplerGroupIdx = 0; samplerGroupIdx != SAMPLER_GROUP_COUNT; ++samplerGroupIdx) {
|
||||
auto& groupData = samplerGroupInfo[samplerGroupIdx];
|
||||
auto stageFlags = groupData.stageFlags;
|
||||
if (!stageFlags.hasShaderType(static_cast<ShaderType>(shaderType))) {
|
||||
continue;
|
||||
}
|
||||
auto& samplers = groupData.samplers;
|
||||
for (size_t samplerIdx = 0, c = samplers.size(); samplerIdx != c; ++samplerIdx) {
|
||||
samplerBlockInfo[bindingIdx].samplerGroup = samplerGroupIdx;
|
||||
samplerBlockInfo[bindingIdx].sampler = samplerIdx;
|
||||
++bindingIdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Save this program's SamplerGroupInfo, it's used during draw calls to bind sampler groups to
|
||||
// the appropriate stage(s).
|
||||
samplerGroupInfo = program.getSamplerGroupInfo();
|
||||
}
|
||||
|
||||
MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t levels,
|
||||
@@ -533,14 +521,33 @@ MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t le
|
||||
: HwTexture(target, levels, samples, width, height, depth, format, usage), context(context),
|
||||
externalImage(context) {
|
||||
texture = metalTexture;
|
||||
minLod = 0;
|
||||
maxLod = levels - 1;
|
||||
updateLodRange(0, levels - 1);
|
||||
}
|
||||
|
||||
MetalTexture::~MetalTexture() {
|
||||
externalImage.set(nullptr);
|
||||
}
|
||||
|
||||
id<MTLTexture> MetalTexture::getMtlTextureForRead() noexcept {
|
||||
if (lodTextureView) {
|
||||
return lodTextureView;
|
||||
}
|
||||
// The texture's swizzle remains constant throughout its lifetime, however its LOD range can
|
||||
// change. We'll cache the LOD view, and set lodTextureView to nil if minLod or maxLod is
|
||||
// updated.
|
||||
id<MTLTexture> t = swizzledTextureView ? swizzledTextureView : texture;
|
||||
if (!t) {
|
||||
return nil;
|
||||
}
|
||||
if (UTILS_UNLIKELY(minLod > maxLod)) {
|
||||
// If the texture does not have any available LODs, provide a view of only level 0.
|
||||
// Filament should prevent this from ever occurring.
|
||||
lodTextureView = createTextureViewWithLodRange(t, 0, 0);
|
||||
return lodTextureView;
|
||||
}
|
||||
lodTextureView = createTextureViewWithLodRange(t, minLod, maxLod);
|
||||
return lodTextureView;
|
||||
}
|
||||
|
||||
MTLPixelFormat MetalTexture::decidePixelFormat(MetalContext* context, TextureFormat format) {
|
||||
const MTLPixelFormat metalFormat = getMetalFormat(context, format);
|
||||
@@ -662,6 +669,13 @@ void MetalTexture::loadImage(uint32_t level, MTLRegion region, PixelBufferDescri
|
||||
updateLodRange(level);
|
||||
}
|
||||
|
||||
void MetalTexture::generateMipmaps() noexcept {
|
||||
id <MTLBlitCommandEncoder> blitEncoder = [getPendingCommandBuffer(&context) blitCommandEncoder];
|
||||
[blitEncoder generateMipmapsForTexture:texture];
|
||||
[blitEncoder endEncoding];
|
||||
updateLodRange(0, texture.mipmapLevelCount - 1);
|
||||
}
|
||||
|
||||
void MetalTexture::loadSlice(uint32_t level, MTLRegion region, uint32_t byteOffset, uint32_t slice,
|
||||
PixelBufferDescriptor const& data) noexcept {
|
||||
const PixelBufferShape shape = PixelBufferShape::compute(data, format, region.size, byteOffset);
|
||||
@@ -782,16 +796,103 @@ void MetalTexture::loadWithBlit(uint32_t level, uint32_t slice, MTLRegion region
|
||||
}
|
||||
|
||||
void MetalTexture::updateLodRange(uint32_t level) {
|
||||
assert_invariant(!isInRenderPass(&context));
|
||||
minLod = std::min(minLod, level);
|
||||
maxLod = std::max(maxLod, level);
|
||||
lodTextureView = nil;
|
||||
}
|
||||
|
||||
void MetalTexture::updateLodRange(uint32_t min, uint32_t max) {
|
||||
assert_invariant(!isInRenderPass(&context));
|
||||
assert_invariant(min <= max);
|
||||
minLod = std::min(minLod, min);
|
||||
maxLod = std::max(maxLod, max);
|
||||
lodTextureView = nil;
|
||||
}
|
||||
|
||||
void MetalSamplerGroup::finalize() {
|
||||
assert_invariant(encoder);
|
||||
// TODO: we should be able to encode textures and samplers inside setFinalizedTexture and
|
||||
// setFinalizedSampler as they become available, but Metal doesn't seem to like this; the arg
|
||||
// buffer gets encoded incorrectly. This warrants more investigation.
|
||||
|
||||
auto [buffer, offset] = argBuffer->getCurrentAllocation();
|
||||
[encoder setArgumentBuffer:buffer offset:offset];
|
||||
|
||||
// Encode all textures and samplers.
|
||||
for (size_t s = 0; s < size; s++) {
|
||||
[encoder setTexture:textures[s] atIndex:(s * 2 + 0)];
|
||||
[encoder setSamplerState:samplers[s] atIndex:(s * 2 + 1)];
|
||||
}
|
||||
|
||||
finalized = true;
|
||||
}
|
||||
|
||||
void MetalSamplerGroup::reset(id<MTLCommandBuffer> cmdBuffer, id<MTLArgumentEncoder> e,
|
||||
id<MTLDevice> device) {
|
||||
encoder = e;
|
||||
|
||||
// The number of slots in the ring buffer we use to manage argument buffer allocations.
|
||||
// This number was chosen to avoid running out of slots and having to allocate a "fallback"
|
||||
// buffer when SamplerGroups are updated multiple times a frame. This value can reduced after
|
||||
// auditing Filament's calls to updateSamplerGroup, which should be as few times as possible.
|
||||
// For example, the bloom downsample pass should be refactored to maintain two separate
|
||||
// MaterialInstances instead of "ping ponging" between two texture bindings, which causes a
|
||||
// single SamplerGroup to be updated many times a frame.
|
||||
static constexpr auto METAL_ARGUMENT_BUFFER_SLOTS = 32;
|
||||
|
||||
MTLSizeAndAlign argBufferLayout;
|
||||
argBufferLayout.size = encoder.encodedLength;
|
||||
argBufferLayout.align = encoder.alignment;
|
||||
// Chances are, even though the MTLArgumentEncoder might change, the required size and alignment
|
||||
// probably won't. So we can re-use the previous ring buffer.
|
||||
if (UTILS_UNLIKELY(!argBuffer || !argBuffer->canAccomodateLayout(argBufferLayout))) {
|
||||
argBuffer = std::make_unique<MetalRingBuffer>(device, MTLResourceStorageModeShared,
|
||||
argBufferLayout, METAL_ARGUMENT_BUFFER_SLOTS);
|
||||
} else {
|
||||
argBuffer->createNewAllocation(cmdBuffer);
|
||||
}
|
||||
|
||||
// Clear all textures and samplers.
|
||||
assert_invariant(textureHandles.size() == textures.size());
|
||||
assert_invariant(textures.size() == samplers.size());
|
||||
for (size_t s = 0; s < textureHandles.size(); s++) {
|
||||
textureHandles[s] = {};
|
||||
textures[s] = nil;
|
||||
samplers[s] = nil;
|
||||
}
|
||||
|
||||
finalized = false;
|
||||
}
|
||||
|
||||
void MetalSamplerGroup::mutate(id<MTLCommandBuffer> cmdBuffer) {
|
||||
assert_invariant(finalized); // only makes sense to mutate if this sampler group is finalized
|
||||
assert_invariant(argBuffer);
|
||||
argBuffer->createNewAllocation(cmdBuffer);
|
||||
finalized = false;
|
||||
}
|
||||
|
||||
void MetalSamplerGroup::useResources(id<MTLRenderCommandEncoder> renderPassEncoder) {
|
||||
assert_invariant(finalized);
|
||||
if (@available(iOS 13, *)) {
|
||||
// TODO: pass only the appropriate stages to useResources.
|
||||
[renderPassEncoder useResources:textures.data()
|
||||
count:textures.size()
|
||||
usage:MTLResourceUsageRead | MTLResourceUsageSample
|
||||
stages:MTLRenderStageFragment | MTLRenderStageVertex];
|
||||
} else {
|
||||
[renderPassEncoder useResources:textures.data()
|
||||
count:textures.size()
|
||||
usage:MTLResourceUsageRead | MTLResourceUsageSample];
|
||||
}
|
||||
}
|
||||
|
||||
MetalRenderTarget::MetalRenderTarget(MetalContext* context, uint32_t width, uint32_t height,
|
||||
uint8_t samples, Attachment colorAttachments[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT],
|
||||
Attachment depthAttachment, Attachment stencilAttachment) :
|
||||
HwRenderTarget(width, height), context(context), samples(samples) {
|
||||
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmin = {std::numeric_limits<size_t>::max()};
|
||||
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmax = {0};
|
||||
math::uint2 tmin = {std::numeric_limits<uint32_t>::max()};
|
||||
UTILS_UNUSED_IN_RELEASE math::uint2 tmax = {0};
|
||||
UTILS_UNUSED_IN_RELEASE size_t attachmentCount = 0;
|
||||
|
||||
for (size_t i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
||||
@@ -816,7 +917,7 @@ MetalRenderTarget::MetalRenderTarget(MetalContext* context, uint32_t width, uint
|
||||
if (samples > 1 && color[i].getSampleCount() == 1) {
|
||||
auto& sidecar = color[i].metalTexture->msaaSidecar;
|
||||
if (!sidecar) {
|
||||
sidecar = createMultisampledTexture(context->device, color[i].getPixelFormat(),
|
||||
sidecar = createMultisampledTexture(color[i].getPixelFormat(),
|
||||
color[i].metalTexture->width, color[i].metalTexture->height, samples);
|
||||
}
|
||||
}
|
||||
@@ -841,7 +942,7 @@ MetalRenderTarget::MetalRenderTarget(MetalContext* context, uint32_t width, uint
|
||||
if (samples > 1 && depth.getSampleCount() == 1) {
|
||||
auto& sidecar = depth.metalTexture->msaaSidecar;
|
||||
if (!sidecar) {
|
||||
sidecar = createMultisampledTexture(context->device, depth.getPixelFormat(),
|
||||
sidecar = createMultisampledTexture(depth.getPixelFormat(),
|
||||
depth.metalTexture->width, depth.metalTexture->height, samples);
|
||||
}
|
||||
}
|
||||
@@ -866,7 +967,7 @@ MetalRenderTarget::MetalRenderTarget(MetalContext* context, uint32_t width, uint
|
||||
if (samples > 1 && stencil.getSampleCount() == 1) {
|
||||
auto& sidecar = stencil.metalTexture->msaaSidecar;
|
||||
if (!sidecar) {
|
||||
sidecar = createMultisampledTexture(context->device, stencil.getPixelFormat(),
|
||||
sidecar = createMultisampledTexture(stencil.getPixelFormat(),
|
||||
stencil.metalTexture->width, stencil.metalTexture->height, samples);
|
||||
}
|
||||
}
|
||||
@@ -880,9 +981,9 @@ MetalRenderTarget::MetalRenderTarget(MetalContext* context, uint32_t width, uint
|
||||
// The render target dimensions must be less than or equal to the attachment size.
|
||||
assert_invariant(width <= tmin.x && height <= tmin.y);
|
||||
|
||||
// Store the height of all attachments. We'll use this when converting from Filament's
|
||||
// Store the width/height of all attachments. We'll use this when converting from Filament's
|
||||
// coordinate system to Metal's.
|
||||
attachmentHeight = tmin.y;
|
||||
attachmentSize = tmin;
|
||||
}
|
||||
|
||||
void MetalRenderTarget::setUpRenderPassAttachments(MTLRenderPassDescriptor* descriptor,
|
||||
@@ -953,6 +1054,7 @@ void MetalRenderTarget::setUpRenderPassAttachments(MTLRenderPassDescriptor* desc
|
||||
descriptor.depthAttachment.slice = 0;
|
||||
const bool discard = any(discardFlags & TargetBufferFlags::DEPTH);
|
||||
if (!discard) {
|
||||
assert_invariant(context->supportsAutoDepthResolve);
|
||||
descriptor.depthAttachment.resolveTexture = depthAttachment.getTexture();
|
||||
descriptor.depthAttachment.resolveLevel = depthAttachment.level;
|
||||
descriptor.depthAttachment.resolveSlice = depthAttachment.layer;
|
||||
@@ -985,10 +1087,14 @@ void MetalRenderTarget::setUpRenderPassAttachments(MTLRenderPassDescriptor* desc
|
||||
descriptor.stencilAttachment.slice = 0;
|
||||
const bool discard = any(discardFlags & TargetBufferFlags::STENCIL);
|
||||
if (!discard) {
|
||||
assert_invariant(context->supportsAutoDepthResolve);
|
||||
descriptor.stencilAttachment.resolveTexture = stencilAttachment.getTexture();
|
||||
descriptor.stencilAttachment.resolveLevel = stencilAttachment.level;
|
||||
descriptor.stencilAttachment.resolveSlice = stencilAttachment.layer;
|
||||
descriptor.stencilAttachment.storeAction = MTLStoreActionMultisampleResolve;
|
||||
if (@available(iOS 12.0, *)) {
|
||||
descriptor.stencilAttachment.stencilResolveFilter = MTLMultisampleStencilResolveFilterSample0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1050,8 +1156,8 @@ MTLStoreAction MetalRenderTarget::getStoreAction(const RenderPassParams& params,
|
||||
return MTLStoreActionStore;
|
||||
}
|
||||
|
||||
id<MTLTexture> MetalRenderTarget::createMultisampledTexture(id<MTLDevice> device,
|
||||
MTLPixelFormat format, uint32_t width, uint32_t height, uint8_t samples) {
|
||||
id<MTLTexture> MetalRenderTarget::createMultisampledTexture(MTLPixelFormat format,
|
||||
uint32_t width, uint32_t height, uint8_t samples) const {
|
||||
MTLTextureDescriptor* descriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
|
||||
width:width
|
||||
@@ -1062,18 +1168,25 @@ id<MTLTexture> MetalRenderTarget::createMultisampledTexture(id<MTLDevice> device
|
||||
descriptor.usage = MTLTextureUsageRenderTarget;
|
||||
descriptor.resourceOptions = MTLResourceStorageModePrivate;
|
||||
|
||||
return [device newTextureWithDescriptor:descriptor];
|
||||
if (context->supportsMemorylessRenderTargets) {
|
||||
if (@available(macOS 11.0, *)) {
|
||||
descriptor.resourceOptions = MTLResourceStorageModeMemoryless;
|
||||
}
|
||||
}
|
||||
|
||||
return [context->device newTextureWithDescriptor:descriptor];
|
||||
}
|
||||
|
||||
uint32_t MetalRenderTarget::getAttachmentHeight() noexcept {
|
||||
math::uint2 MetalRenderTarget::getAttachmentSize() noexcept {
|
||||
if (defaultRenderTarget) {
|
||||
// The default render target always has a color attachment.
|
||||
auto colorAttachment = getDrawColorAttachment(0);
|
||||
assert_invariant(colorAttachment);
|
||||
return colorAttachment.getTexture().height;
|
||||
id<MTLTexture> t = colorAttachment.getTexture();
|
||||
return {t.width, t.height};
|
||||
}
|
||||
assert_invariant(attachmentHeight > 0);
|
||||
return attachmentHeight;
|
||||
assert_invariant(attachmentSize.x > 0 && attachmentSize.y > 0);
|
||||
return attachmentSize;
|
||||
}
|
||||
|
||||
MetalFence::MetalFence(MetalContext& context) : context(context), value(context.signalId++) { }
|
||||
|
||||
@@ -20,10 +20,12 @@
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
#include "private/backend/Driver.h"
|
||||
#include "private/backend/Program.h"
|
||||
#include "backend/Program.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
|
||||
#include <memory>
|
||||
#include <tsl/robin_map.h>
|
||||
#include <utils/Hash.h>
|
||||
@@ -35,17 +37,42 @@ inline bool operator==(const SamplerParams& lhs, const SamplerParams& rhs) {
|
||||
return lhs.u == rhs.u;
|
||||
}
|
||||
|
||||
static constexpr uint32_t SAMPLER_GROUP_COUNT = Program::BINDING_COUNT;
|
||||
static constexpr uint32_t SAMPLER_BINDING_COUNT = MAX_SAMPLER_COUNT;
|
||||
static constexpr uint32_t VERTEX_BUFFER_START = Program::BINDING_COUNT;
|
||||
// Rasterization Bindings
|
||||
// ----------------------
|
||||
// Bindings Buffer name Count
|
||||
// ------------------------------------------------------
|
||||
// 0 Zero buffer (placeholder vertex buffer) 1
|
||||
// 1-16 Filament vertex buffers 16 limited by MAX_VERTEX_BUFFER_COUNT
|
||||
// 17-26 Uniform buffers 10 Program::UNIFORM_BINDING_COUNT
|
||||
// 27-30 Sampler groups (argument buffers) 4 Program::SAMPLER_BINDING_COUNT
|
||||
//
|
||||
// Total 31
|
||||
|
||||
// The "zero" buffer is a small buffer for missing attributes that resides in the vertex slot
|
||||
// immediately following any user-provided vertex buffers.
|
||||
static constexpr uint32_t ZERO_VERTEX_BUFFER = MAX_VERTEX_BUFFER_COUNT;
|
||||
// Compute Bindings
|
||||
// ----------------------
|
||||
// Bindings Buffer name Count
|
||||
// ------------------------------------------------------
|
||||
// 0-3 SSBO buffers 4 MAX_SSBO_COUNT
|
||||
// 17-26 Uniform buffers 10 Program::UNIFORM_BINDING_COUNT
|
||||
// 27-30 Sampler groups (argument buffers) 4 Program::SAMPLER_BINDING_COUNT
|
||||
//
|
||||
// Total 18
|
||||
|
||||
// The total number of vertex buffer "slots" that the Metal backend can bind.
|
||||
// + 1 to account for the zero buffer.
|
||||
static constexpr uint32_t VERTEX_BUFFER_COUNT = MAX_VERTEX_BUFFER_COUNT + 1;
|
||||
// + 1 to account for the zero buffer, a placeholder buffer used internally by the Metal backend.
|
||||
// MAX_VERTEX_BUFFER_COUNT represents the max number of vertex buffers Filament can bind.
|
||||
static constexpr uint32_t LOGICAL_VERTEX_BUFFER_COUNT = MAX_VERTEX_BUFFER_COUNT + 1;
|
||||
|
||||
// The "zero" buffer is a small buffer for missing attributes.
|
||||
static constexpr uint32_t ZERO_VERTEX_BUFFER_LOGICAL_INDEX = 0u;
|
||||
static constexpr uint32_t ZERO_VERTEX_BUFFER_BINDING = 0u;
|
||||
|
||||
static constexpr uint32_t USER_VERTEX_BUFFER_BINDING_START = 1u;
|
||||
|
||||
// These constants must match the equivalent in CodeGenerator.h.
|
||||
static constexpr uint32_t UNIFORM_BUFFER_BINDING_START = 17u;
|
||||
static constexpr uint32_t SSBO_BINDING_START = 0u;
|
||||
static constexpr uint32_t SAMPLER_GROUP_BINDING_START = 27u;
|
||||
|
||||
// Forward declarations necessary here, definitions at end of file.
|
||||
inline bool operator==(const MTLViewport& lhs, const MTLViewport& rhs);
|
||||
@@ -58,7 +85,7 @@ inline bool operator!=(const MTLViewport& lhs, const MTLViewport& rhs);
|
||||
struct VertexDescription {
|
||||
struct Attribute {
|
||||
MTLVertexFormat format; // 8 bytes
|
||||
uint32_t buffer; // 4 bytes
|
||||
uint32_t buffer; // 4 bytes a logical vertex buffer index
|
||||
uint32_t offset; // 4 bytes
|
||||
};
|
||||
struct Layout {
|
||||
@@ -66,7 +93,8 @@ struct VertexDescription {
|
||||
uint64_t stride; // 8 bytes
|
||||
};
|
||||
Attribute attributes[MAX_VERTEX_ATTRIBUTE_COUNT] = {}; // 256 bytes
|
||||
Layout layouts[VERTEX_BUFFER_COUNT] = {}; // 272 bytes
|
||||
// layouts[n] represents the layout of the vertex buffer at logical index n
|
||||
Layout layouts[LOGICAL_VERTEX_BUFFER_COUNT] = {}; // 272 bytes
|
||||
|
||||
bool operator==(const VertexDescription& rhs) const noexcept {
|
||||
bool result = true;
|
||||
@@ -126,9 +154,11 @@ static_assert(sizeof(BlendState) == 56, "BlendState is unexpected size.");
|
||||
// StateCache caches Metal state objects using StateType as a key.
|
||||
// MetalType is the corresponding Metal API type.
|
||||
// StateCreator is a functor that creates a new state of type MetalType.
|
||||
// HashFn is a functor that hashes StateType.
|
||||
template<typename StateType,
|
||||
typename MetalType,
|
||||
typename StateCreator>
|
||||
typename StateCreator,
|
||||
typename HashFn = utils::hash::MurmurHashFn<StateType>>
|
||||
class StateCache {
|
||||
|
||||
public:
|
||||
@@ -141,6 +171,8 @@ public:
|
||||
void setDevice(id<MTLDevice> device) noexcept { mDevice = device; }
|
||||
|
||||
MetalType getOrCreateState(const StateType& state) noexcept {
|
||||
assert_invariant(mDevice);
|
||||
|
||||
// Check if a valid state already exists in the cache.
|
||||
auto iter = mStateCache.find(state);
|
||||
if (UTILS_LIKELY(iter != mStateCache.end())) {
|
||||
@@ -150,6 +182,7 @@ public:
|
||||
|
||||
// If we reach this point, we couldn't find one in the cache; create a new one.
|
||||
const auto& metalObject = creator(mDevice, state);
|
||||
assert_invariant(metalObject);
|
||||
|
||||
mStateCache.emplace(std::make_pair(
|
||||
state,
|
||||
@@ -164,7 +197,6 @@ private:
|
||||
StateCreator creator;
|
||||
id<MTLDevice> mDevice = nil;
|
||||
|
||||
using HashFn = utils::hash::MurmurHashFn<StateType>;
|
||||
tsl::robin_map<StateType, MetalType, HashFn> mStateCache;
|
||||
|
||||
};
|
||||
@@ -258,23 +290,39 @@ using PipelineStateCache = StateCache<MetalPipelineState, id<MTLRenderPipelineSt
|
||||
// Depth-stencil State
|
||||
|
||||
struct DepthStencilState {
|
||||
struct StencilDescriptor {
|
||||
MTLCompareFunction stencilCompare = MTLCompareFunctionAlways; // 8 bytes
|
||||
MTLStencilOperation stencilOperationStencilFail = MTLStencilOperationKeep; // 8 bytes
|
||||
MTLStencilOperation stencilOperationDepthFail = MTLStencilOperationKeep; // 8 bytes
|
||||
MTLStencilOperation stencilOperationDepthStencilPass = MTLStencilOperationKeep; // 8 bytes
|
||||
uint32_t readMask = 0xFFFF; // 4 bytes
|
||||
uint32_t writeMask = 0xFFFF; // 4 bytes
|
||||
|
||||
bool operator==(const StencilDescriptor& rhs) const {
|
||||
return stencilCompare == rhs.stencilCompare &&
|
||||
stencilOperationStencilFail == rhs.stencilOperationStencilFail &&
|
||||
stencilOperationDepthFail == rhs.stencilOperationDepthFail &&
|
||||
stencilOperationDepthStencilPass == rhs.stencilOperationDepthStencilPass &&
|
||||
readMask == rhs.readMask &&
|
||||
writeMask == rhs.writeMask;
|
||||
}
|
||||
|
||||
bool operator!=(const StencilDescriptor& rhs) const {
|
||||
return !(rhs == *this);
|
||||
}
|
||||
} front, back;
|
||||
|
||||
MTLCompareFunction depthCompare = MTLCompareFunctionAlways; // 8 bytes
|
||||
MTLCompareFunction stencilCompare = MTLCompareFunctionAlways; // 8 bytes
|
||||
MTLStencilOperation stencilOperationStencilFail = MTLStencilOperationKeep; // 8 bytes
|
||||
MTLStencilOperation stencilOperationDepthFail = MTLStencilOperationKeep; // 8 bytes
|
||||
MTLStencilOperation stencilOperationDepthStencilPass = MTLStencilOperationKeep; // 8 bytes
|
||||
bool depthWriteEnabled = false; // 1 byte
|
||||
bool stencilWriteEnabled = false; // 1 byte
|
||||
char padding[6] = { 0 }; // 7 bytes
|
||||
uint8_t padding[6] = { 0 }; // 6 bytes
|
||||
|
||||
bool operator==(const DepthStencilState& rhs) const {
|
||||
return depthCompare == rhs.depthCompare &&
|
||||
stencilCompare == rhs.stencilCompare &&
|
||||
stencilOperationStencilFail == rhs.stencilOperationStencilFail &&
|
||||
stencilOperationDepthFail == rhs.stencilOperationDepthFail &&
|
||||
stencilOperationDepthStencilPass == rhs.stencilOperationDepthStencilPass &&
|
||||
depthWriteEnabled == rhs.depthWriteEnabled &&
|
||||
stencilWriteEnabled == rhs.stencilWriteEnabled;
|
||||
depthWriteEnabled == rhs.depthWriteEnabled &&
|
||||
front == rhs.front &&
|
||||
back == rhs.back &&
|
||||
stencilWriteEnabled == rhs.stencilWriteEnabled;
|
||||
}
|
||||
|
||||
bool operator!=(const DepthStencilState& rhs) const noexcept {
|
||||
@@ -284,7 +332,7 @@ struct DepthStencilState {
|
||||
|
||||
// This assert checks that the struct is the size we expect without any "hidden" padding bytes
|
||||
// inserted by the compiler.
|
||||
static_assert(sizeof(DepthStencilState) == 48, "DepthStencilState unexpected size.");
|
||||
static_assert(sizeof(DepthStencilState) == 96, "DepthStencilState unexpected size.");
|
||||
|
||||
struct DepthStateCreator {
|
||||
id<MTLDepthStencilState> operator()(id<MTLDevice> device, const DepthStencilState& state)
|
||||
@@ -300,38 +348,19 @@ using DepthStencilStateCache = StateCache<DepthStencilState, id<MTLDepthStencilS
|
||||
|
||||
class MetalBufferObject;
|
||||
|
||||
struct UniformBufferState {
|
||||
struct BufferState {
|
||||
MetalBufferObject* buffer = nullptr; // 8 bytes
|
||||
uint32_t offset = 0; // 4 bytes
|
||||
bool bound = false; // 1 byte
|
||||
char padding[3] = { 0 }; // 3 bytes
|
||||
|
||||
bool operator==(const UniformBufferState& rhs) const noexcept {
|
||||
return this->bound == rhs.bound &&
|
||||
this->buffer == rhs.buffer &&
|
||||
this->offset == rhs.offset;
|
||||
}
|
||||
|
||||
bool operator!=(const UniformBufferState& rhs) const noexcept {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(UniformBufferState) == 16, "UniformBufferState unexpected size.");
|
||||
|
||||
using UniformBufferStateTracker = StateTracker<UniformBufferState>;
|
||||
|
||||
// Sampler states
|
||||
|
||||
struct SamplerState {
|
||||
SamplerParams samplerParams;
|
||||
uint32_t minLod = 0;
|
||||
uint32_t maxLod = UINT_MAX;
|
||||
|
||||
bool operator==(const SamplerState& rhs) const noexcept {
|
||||
return this->samplerParams == rhs.samplerParams &&
|
||||
this->minLod == rhs.minLod &&
|
||||
this->maxLod == rhs.maxLod;
|
||||
return this->samplerParams == rhs.samplerParams;
|
||||
}
|
||||
|
||||
bool operator!=(const SamplerState& rhs) const noexcept {
|
||||
@@ -339,7 +368,7 @@ struct SamplerState {
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(SamplerState) == 12, "SamplerState unexpected size.");
|
||||
static_assert(sizeof(SamplerState) == 4, "SamplerState unexpected size.");
|
||||
|
||||
struct SamplerStateCreator {
|
||||
id<MTLSamplerState> operator()(id<MTLDevice> device, const SamplerState& state) noexcept;
|
||||
@@ -352,6 +381,38 @@ using SamplerStateCache = StateCache<SamplerState, id<MTLSamplerState>, SamplerS
|
||||
using CullModeStateTracker = StateTracker<MTLCullMode>;
|
||||
using WindingStateTracker = StateTracker<MTLWinding>;
|
||||
|
||||
// Argument encoder
|
||||
|
||||
struct ArgumentEncoderState {
|
||||
utils::FixedCapacityVector<MTLTextureType> textureTypes;
|
||||
|
||||
explicit ArgumentEncoderState(utils::FixedCapacityVector<MTLTextureType>&& types)
|
||||
: textureTypes(std::move(types)) {}
|
||||
|
||||
bool operator==(const ArgumentEncoderState& rhs) const noexcept {
|
||||
return std::equal(textureTypes.begin(), textureTypes.end(), rhs.textureTypes.begin(),
|
||||
rhs.textureTypes.end());
|
||||
}
|
||||
|
||||
bool operator!=(const ArgumentEncoderState& rhs) const noexcept {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
struct ArgumentEncoderHasher {
|
||||
uint32_t operator()(const ArgumentEncoderState& key) const noexcept {
|
||||
return utils::hash::murmur3((const uint32_t*)key.textureTypes.data(),
|
||||
sizeof(MTLTextureType) * key.textureTypes.size() / 4, 0);
|
||||
}
|
||||
};
|
||||
|
||||
struct ArgumentEncoderCreator {
|
||||
id<MTLArgumentEncoder> operator()(id<MTLDevice> device, const ArgumentEncoderState& state) noexcept;
|
||||
};
|
||||
|
||||
using ArgumentEncoderCache = StateCache<ArgumentEncoderState, id<MTLArgumentEncoder>,
|
||||
ArgumentEncoderCreator, ArgumentEncoderHasher>;
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
|
||||
|
||||
@@ -38,18 +38,18 @@ id<MTLRenderPipelineState> PipelineStateCreator::operator()(id<MTLDevice> device
|
||||
if (vertexDescription.attributes[i].format > MTLVertexFormatInvalid) {
|
||||
const auto& attribute = vertexDescription.attributes[i];
|
||||
vertex.attributes[i].format = attribute.format;
|
||||
vertex.attributes[i].bufferIndex = VERTEX_BUFFER_START + attribute.buffer;
|
||||
vertex.attributes[i].bufferIndex = attribute.buffer;
|
||||
vertex.attributes[i].offset = attribute.offset;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < VERTEX_BUFFER_COUNT; i++) {
|
||||
for (uint32_t i = 0; i < LOGICAL_VERTEX_BUFFER_COUNT; i++) {
|
||||
if (vertexDescription.layouts[i].stride > 0) {
|
||||
const auto& layout = vertexDescription.layouts[i];
|
||||
vertex.layouts[VERTEX_BUFFER_START + i].stride = layout.stride;
|
||||
vertex.layouts[VERTEX_BUFFER_START + i].stepFunction = layout.step;
|
||||
vertex.layouts[i].stride = layout.stride;
|
||||
vertex.layouts[i].stepFunction = layout.step;
|
||||
if (layout.step == MTLVertexStepFunctionConstant) {
|
||||
vertex.layouts[VERTEX_BUFFER_START + i].stepRate = 0;
|
||||
vertex.layouts[i].stepRate = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,15 +102,27 @@ id<MTLDepthStencilState> DepthStateCreator::operator()(id<MTLDevice> device,
|
||||
MTLDepthStencilDescriptor* depthStencilDescriptor = [MTLDepthStencilDescriptor new];
|
||||
depthStencilDescriptor.depthCompareFunction = state.depthCompare;
|
||||
depthStencilDescriptor.depthWriteEnabled = BOOL(state.depthWriteEnabled);
|
||||
MTLStencilDescriptor* stencilDescriptor = [MTLStencilDescriptor new];
|
||||
stencilDescriptor.stencilCompareFunction = state.stencilCompare;
|
||||
stencilDescriptor.stencilFailureOperation = state.stencilOperationStencilFail;
|
||||
stencilDescriptor.depthFailureOperation = state.stencilOperationDepthFail;
|
||||
stencilDescriptor.depthStencilPassOperation = state.stencilOperationDepthStencilPass;
|
||||
stencilDescriptor.readMask = 0xFFFFFFFF;
|
||||
stencilDescriptor.writeMask = state.stencilWriteEnabled ? 0xFFFFFFFF : 0x0;
|
||||
depthStencilDescriptor.backFaceStencil = stencilDescriptor;
|
||||
depthStencilDescriptor.frontFaceStencil = stencilDescriptor;
|
||||
|
||||
// Front-facing stencil.
|
||||
MTLStencilDescriptor* frontStencilDescriptor = [MTLStencilDescriptor new];
|
||||
frontStencilDescriptor.stencilCompareFunction = state.front.stencilCompare;
|
||||
frontStencilDescriptor.stencilFailureOperation = state.front.stencilOperationStencilFail;
|
||||
frontStencilDescriptor.depthFailureOperation = state.front.stencilOperationDepthFail;
|
||||
frontStencilDescriptor.depthStencilPassOperation = state.front.stencilOperationDepthStencilPass;
|
||||
frontStencilDescriptor.readMask = state.front.readMask;
|
||||
frontStencilDescriptor.writeMask = state.stencilWriteEnabled ? state.front.writeMask : 0x0;
|
||||
depthStencilDescriptor.frontFaceStencil = frontStencilDescriptor;
|
||||
|
||||
// Back-facing stencil.
|
||||
MTLStencilDescriptor* backStencilDescriptor = [MTLStencilDescriptor new];
|
||||
backStencilDescriptor.stencilCompareFunction = state.back.stencilCompare;
|
||||
backStencilDescriptor.stencilFailureOperation = state.back.stencilOperationStencilFail;
|
||||
backStencilDescriptor.depthFailureOperation = state.back.stencilOperationDepthFail;
|
||||
backStencilDescriptor.depthStencilPassOperation = state.back.stencilOperationDepthStencilPass;
|
||||
backStencilDescriptor.readMask = state.back.readMask;
|
||||
backStencilDescriptor.writeMask = state.stencilWriteEnabled ? state.back.writeMask : 0x0;
|
||||
depthStencilDescriptor.backFaceStencil = backStencilDescriptor;
|
||||
|
||||
return [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
|
||||
}
|
||||
|
||||
@@ -125,11 +137,10 @@ id<MTLSamplerState> SamplerStateCreator::operator()(id<MTLDevice> device,
|
||||
samplerDescriptor.tAddressMode = getAddressMode(params.wrapT);
|
||||
samplerDescriptor.rAddressMode = getAddressMode(params.wrapR);
|
||||
samplerDescriptor.maxAnisotropy = 1u << params.anisotropyLog2;
|
||||
samplerDescriptor.lodMaxClamp = (float) state.maxLod;
|
||||
samplerDescriptor.lodMinClamp = (float) state.minLod;
|
||||
samplerDescriptor.compareFunction =
|
||||
params.compareMode == SamplerCompareMode::NONE ?
|
||||
MTLCompareFunctionNever : getCompareFunction(params.compareFunc);
|
||||
samplerDescriptor.supportArgumentBuffers = YES;
|
||||
|
||||
#if defined(IOS)
|
||||
// Older Apple devices (and the simulator) don't support setting a comparison function in
|
||||
@@ -144,5 +155,38 @@ id<MTLSamplerState> SamplerStateCreator::operator()(id<MTLDevice> device,
|
||||
return [device newSamplerStateWithDescriptor:samplerDescriptor];
|
||||
}
|
||||
|
||||
id<MTLArgumentEncoder> ArgumentEncoderCreator::operator()(id<MTLDevice> device,
|
||||
const ArgumentEncoderState &state) noexcept {
|
||||
const auto& textureTypes = state.textureTypes;
|
||||
const auto& count = textureTypes.size();
|
||||
assert_invariant(count > 0);
|
||||
|
||||
// Metal has separate data types for textures versus samplers, so the argument buffer layout
|
||||
// alternates between texture and sampler, i.e.:
|
||||
// textureA
|
||||
// samplerA
|
||||
// textureB
|
||||
// samplerB
|
||||
// etc
|
||||
NSMutableArray<MTLArgumentDescriptor*>* arguments =
|
||||
[NSMutableArray arrayWithCapacity:(count * 2)];
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
MTLArgumentDescriptor* textureArgument = [MTLArgumentDescriptor argumentDescriptor];
|
||||
textureArgument.index = i * 2 + 0;
|
||||
textureArgument.dataType = MTLDataTypeTexture;
|
||||
textureArgument.textureType = textureTypes[i];
|
||||
textureArgument.access = MTLArgumentAccessReadOnly;
|
||||
[arguments addObject:textureArgument];
|
||||
|
||||
MTLArgumentDescriptor* samplerArgument = [MTLArgumentDescriptor argumentDescriptor];
|
||||
samplerArgument.index = i * 2 + 1;
|
||||
samplerArgument.dataType = MTLDataTypeSampler;
|
||||
textureArgument.access = MTLArgumentAccessReadOnly;
|
||||
[arguments addObject:samplerArgument];
|
||||
}
|
||||
|
||||
return [device newArgumentEncoderWithArguments:arguments];
|
||||
}
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
|
||||
@@ -29,6 +29,14 @@ API_AVAILABLE(ios(13.0))
|
||||
id<MTLTexture> createTextureViewWithSwizzle(id<MTLTexture> texture,
|
||||
MTLTextureSwizzleChannels swizzle);
|
||||
|
||||
/**
|
||||
* Creates a texture view of the passed-in texture with the given lod range (inclusive). If the
|
||||
* range represents all mip levels, simply returns texture.
|
||||
* lodMax must be greater than or equal to lodMin.
|
||||
*/
|
||||
id<MTLTexture> createTextureViewWithLodRange(id<MTLTexture> texture, NSUInteger lodMin,
|
||||
NSUInteger lodMax);
|
||||
|
||||
/**
|
||||
* Creates a texture view of the passed-in texture with the given layer.
|
||||
*
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include "MetalUtils.h"
|
||||
|
||||
#include <utils/debug.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
id<MTLTexture> createTextureViewWithSwizzle(id<MTLTexture> texture,
|
||||
@@ -37,6 +39,24 @@ id<MTLTexture> createTextureViewWithSwizzle(id<MTLTexture> texture,
|
||||
swizzle:swizzle];
|
||||
}
|
||||
|
||||
id<MTLTexture> createTextureViewWithLodRange(id<MTLTexture> texture, NSUInteger lodMin,
|
||||
NSUInteger lodMax) {
|
||||
assert_invariant(lodMax >= lodMin);
|
||||
if (lodMin == 0 && lodMax >= texture.mipmapLevelCount - 1) {
|
||||
return texture;
|
||||
}
|
||||
NSUInteger slices = texture.arrayLength;
|
||||
if (texture.textureType == MTLTextureTypeCube ||
|
||||
texture.textureType == MTLTextureTypeCubeArray) {
|
||||
slices *= 6;
|
||||
}
|
||||
NSRange levelRange = NSMakeRange(lodMin, lodMax - lodMin + 1);
|
||||
return [texture newTextureViewWithPixelFormat:texture.pixelFormat
|
||||
textureType:texture.textureType
|
||||
levels:levelRange
|
||||
slices:NSMakeRange(0, slices)];
|
||||
}
|
||||
|
||||
id<MTLTexture> createTextureViewWithSingleSlice(id<MTLTexture> texture, NSUInteger slice) {
|
||||
if (texture.textureType == MTLTextureType2D) {
|
||||
return texture;
|
||||
|
||||
@@ -177,6 +177,10 @@ bool NoopDriver::isWorkaroundNeeded(Workaround workaround) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FeatureLevel NoopDriver::getFeatureLevel() {
|
||||
return FeatureLevel::FEATURE_LEVEL_1;
|
||||
}
|
||||
|
||||
math::float2 NoopDriver::getClipSpaceParams() {
|
||||
return math::float2{ 1.0f, 0.0f };
|
||||
}
|
||||
@@ -269,8 +273,11 @@ void NoopDriver::commit(Handle<HwSwapChain> sch) {
|
||||
void NoopDriver::bindUniformBuffer(uint32_t index, Handle<HwBufferObject> ubh) {
|
||||
}
|
||||
|
||||
void NoopDriver::bindUniformBufferRange(uint32_t index, Handle<HwBufferObject> ubh,
|
||||
uint32_t offset, uint32_t size) {
|
||||
void NoopDriver::bindBufferRange(BufferObjectBinding bindingType, uint32_t index,
|
||||
Handle<HwBufferObject> ubh, uint32_t offset, uint32_t size) {
|
||||
}
|
||||
|
||||
void NoopDriver::unbindBuffer(BufferObjectBinding bindingType, uint32_t index) {
|
||||
}
|
||||
|
||||
void NoopDriver::bindSamplers(uint32_t index, Handle<HwSamplerGroup> sbh) {
|
||||
@@ -297,6 +304,11 @@ void NoopDriver::readPixels(Handle<HwRenderTarget> src,
|
||||
scheduleDestroy(std::move(p));
|
||||
}
|
||||
|
||||
void NoopDriver::readBufferSubData(backend::BufferObjectHandle boh,
|
||||
uint32_t offset, uint32_t size, backend::BufferDescriptor&& p) {
|
||||
scheduleDestroy(std::move(p));
|
||||
}
|
||||
|
||||
void NoopDriver::blit(TargetBufferFlags buffers,
|
||||
Handle<HwRenderTarget> dst, Viewport dstRect,
|
||||
Handle<HwRenderTarget> src, Viewport srcRect,
|
||||
@@ -307,10 +319,16 @@ void NoopDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> rph
|
||||
uint32_t instanceCount) {
|
||||
}
|
||||
|
||||
void NoopDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGroupCount) {
|
||||
}
|
||||
|
||||
void NoopDriver::beginTimerQuery(Handle<HwTimerQuery> tqh) {
|
||||
}
|
||||
|
||||
void NoopDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
|
||||
}
|
||||
|
||||
void NoopDriver::resetState(int) {
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -119,6 +119,8 @@ constexpr inline GLenum getBufferBindingType(BufferObjectBinding bindingType) no
|
||||
return GL_ARRAY_BUFFER;
|
||||
case BufferObjectBinding::UNIFORM:
|
||||
return GL_UNIFORM_BUFFER;
|
||||
case BufferObjectBinding::SHADER_STORAGE:
|
||||
return GL_SHADER_STORAGE_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,6 +327,20 @@ constexpr inline GLenum getSwizzleChannel(TextureSwizzle c) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
constexpr inline GLenum getCullingMode(CullingMode mode) noexcept {
|
||||
switch (mode) {
|
||||
case CullingMode::NONE:
|
||||
// should never happen
|
||||
return GL_FRONT_AND_BACK;
|
||||
case CullingMode::FRONT:
|
||||
return GL_FRONT;
|
||||
case CullingMode::BACK:
|
||||
return GL_BACK;
|
||||
case CullingMode::FRONT_AND_BACK:
|
||||
return GL_FRONT_AND_BACK;
|
||||
}
|
||||
}
|
||||
|
||||
// clang looses it on this one, and generates a huge jump table when
|
||||
// inlined. So we don't mark it as inline (only constexpr) which solves the problem,
|
||||
// strangely, when not inlined, clang simply generates an array lookup.
|
||||
|
||||
@@ -40,7 +40,7 @@ bool OpenGLContext::queryOpenGLVersion(GLint* major, GLint* minor) noexcept {
|
||||
OpenGLContext::OpenGLContext() noexcept {
|
||||
state.vao.p = &mDefaultVAO;
|
||||
|
||||
// There query work with all GL/GLES versions!
|
||||
// These queries work with all GL/GLES versions!
|
||||
state.vendor = (char const*)glGetString(GL_VENDOR);
|
||||
state.renderer = (char const*)glGetString(GL_RENDERER);
|
||||
state.version = (char const*)glGetString(GL_VERSION);
|
||||
@@ -55,25 +55,66 @@ OpenGLContext::OpenGLContext() noexcept {
|
||||
|
||||
queryOpenGLVersion(&state.major, &state.minor);
|
||||
|
||||
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &gets.max_renderbuffer_size);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &gets.max_uniform_block_size);
|
||||
glGetIntegerv(GL_MAX_SAMPLES, &gets.max_samples);
|
||||
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &gets.max_draw_buffers);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &gets.max_texture_image_units);
|
||||
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &gets.max_combined_texture_image_units);
|
||||
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &gets.max_transform_feedback_separate_attribs);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &gets.max_uniform_buffer_bindings);
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &gets.uniform_buffer_offset_alignment);
|
||||
|
||||
constexpr auto const caps3 = FEATURE_LEVEL_CAPS[+FeatureLevel::FEATURE_LEVEL_3];
|
||||
constexpr GLint MAX_VERTEX_SAMPLER_COUNT = caps3.MAX_VERTEX_SAMPLER_COUNT;
|
||||
constexpr GLint MAX_FRAGMENT_SAMPLER_COUNT = caps3.MAX_FRAGMENT_SAMPLER_COUNT;
|
||||
|
||||
if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GLES) {
|
||||
// This works on all versions of GLES
|
||||
if (state.major == 3 && state.minor >= 0) {
|
||||
mShaderModel = ShaderModel::MOBILE;
|
||||
}
|
||||
if (state.major == 3 && state.minor >= 1) {
|
||||
features.multisample_texture = true;
|
||||
}
|
||||
initExtensionsGLES();
|
||||
if (state.major == 3) {
|
||||
assert_invariant(gets.max_texture_image_units >= 16);
|
||||
assert_invariant(gets.max_combined_texture_image_units >= 32);
|
||||
if (state.minor >= 1) {
|
||||
features.multisample_texture = true;
|
||||
// figure out our feature level
|
||||
if (ext.EXT_texture_cube_map_array) {
|
||||
mFeatureLevel = FeatureLevel::FEATURE_LEVEL_2;
|
||||
if (gets.max_texture_image_units >= MAX_FRAGMENT_SAMPLER_COUNT &&
|
||||
gets.max_combined_texture_image_units >=
|
||||
(MAX_FRAGMENT_SAMPLER_COUNT + MAX_VERTEX_SAMPLER_COUNT)) {
|
||||
mFeatureLevel = FeatureLevel::FEATURE_LEVEL_3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
|
||||
// OpenGL version
|
||||
if (state.major == 4 && state.minor >= 1) {
|
||||
initExtensionsGL();
|
||||
if (state.major == 4) {
|
||||
assert_invariant(state.minor >= 1);
|
||||
mShaderModel = ShaderModel::DESKTOP;
|
||||
if (state.minor >= 3) {
|
||||
// cubemap arrays are available as of OpenGL 4.0
|
||||
mFeatureLevel = FeatureLevel::FEATURE_LEVEL_2;
|
||||
// figure out our feature level
|
||||
if (gets.max_texture_image_units >= MAX_FRAGMENT_SAMPLER_COUNT &&
|
||||
gets.max_combined_texture_image_units >=
|
||||
(MAX_FRAGMENT_SAMPLER_COUNT + MAX_VERTEX_SAMPLER_COUNT)) {
|
||||
mFeatureLevel = FeatureLevel::FEATURE_LEVEL_3;
|
||||
}
|
||||
}
|
||||
features.multisample_texture = true;
|
||||
}
|
||||
features.multisample_texture = true;
|
||||
// feedback loops are allowed on GL desktop as long as writes are disabled
|
||||
bugs.allow_read_only_ancillary_feedback_loop = true;
|
||||
initExtensionsGL();
|
||||
assert_invariant(gets.max_texture_image_units >= 16);
|
||||
assert_invariant(gets.max_combined_texture_image_units >= 32);
|
||||
}
|
||||
#ifdef GL_EXT_texture_filter_anisotropic
|
||||
if (ext.EXT_texture_filter_anisotropic) {
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gets.max_anisotropy);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Figure out which driver bugs we need to workaround
|
||||
@@ -183,6 +224,7 @@ OpenGLContext::OpenGLContext() noexcept {
|
||||
// TODO: see if we could use `bugs.allow_read_only_ancillary_feedback_loop = true`
|
||||
}
|
||||
|
||||
slog.v << "Feature level: " << +mFeatureLevel << '\n';
|
||||
slog.v << "Active workarounds: " << '\n';
|
||||
UTILS_NOUNROLL
|
||||
for (auto [enabled, name, _] : mBugDatabase) {
|
||||
@@ -192,18 +234,6 @@ OpenGLContext::OpenGLContext() noexcept {
|
||||
}
|
||||
flush(slog.v);
|
||||
|
||||
// now we can query getter and features
|
||||
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &gets.max_renderbuffer_size);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &gets.max_uniform_block_size);
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &gets.uniform_buffer_offset_alignment);
|
||||
glGetIntegerv(GL_MAX_SAMPLES, &gets.max_samples);
|
||||
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &gets.max_draw_buffers);
|
||||
#ifdef GL_EXT_texture_filter_anisotropic
|
||||
if (ext.EXT_texture_filter_anisotropic) {
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gets.max_anisotropy);
|
||||
}
|
||||
#endif
|
||||
|
||||
assert_invariant(gets.max_draw_buffers >= 4); // minspec
|
||||
|
||||
#ifndef NDEBUG
|
||||
@@ -213,36 +243,13 @@ OpenGLContext::OpenGLContext() noexcept {
|
||||
<< "GL_MAX_SAMPLES = " << gets.max_samples << '\n'
|
||||
<< "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = " << gets.max_anisotropy << '\n'
|
||||
<< "GL_MAX_UNIFORM_BLOCK_SIZE = " << gets.max_uniform_block_size << '\n'
|
||||
<< "GL_MAX_TEXTURE_IMAGE_UNITS = " << gets.max_texture_image_units << '\n'
|
||||
<< "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = " << gets.uniform_buffer_offset_alignment << '\n'
|
||||
;
|
||||
flush(slog.v);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set our default state
|
||||
*/
|
||||
|
||||
// We need to make sure our internal state matches the GL state when we start.
|
||||
// (some of these calls may be unneeded as they might be the gl defaults)
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_DITHER);
|
||||
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||
glDisable(GL_SAMPLE_COVERAGE);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
// Point sprite size and seamless cubemap filtering are disabled by default in desktop GL.
|
||||
// In OpenGL ES, these flags do not exist because they are always on.
|
||||
#if BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL
|
||||
enable(GL_PROGRAM_POINT_SIZE);
|
||||
#endif
|
||||
|
||||
#ifdef GL_ARB_seamless_cube_map
|
||||
enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
#endif
|
||||
setDefaultState();
|
||||
|
||||
#ifdef GL_EXT_texture_filter_anisotropic
|
||||
if (ext.EXT_texture_filter_anisotropic) {
|
||||
@@ -261,10 +268,6 @@ OpenGLContext::OpenGLContext() noexcept {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GL_FRAGMENT_SHADER_DERIVATIVE_HINT
|
||||
glHint(GL_FRAGMENT_SHADER_DERIVATIVE_HINT, GL_NICEST);
|
||||
#endif
|
||||
|
||||
#if !defined(NDEBUG) && defined(GL_KHR_debug)
|
||||
if (ext.KHR_debug) {
|
||||
auto cb = [](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
|
||||
@@ -296,6 +299,50 @@ OpenGLContext::OpenGLContext() noexcept {
|
||||
glDebugMessageCallback(cb, nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGLContext::setDefaultState() noexcept {
|
||||
// We need to make sure our internal state matches the GL state when we start.
|
||||
// (some of these calls may be unneeded as they might be the gl defaults)
|
||||
GLenum caps[] = {
|
||||
GL_BLEND,
|
||||
GL_CULL_FACE,
|
||||
GL_SCISSOR_TEST,
|
||||
GL_DEPTH_TEST,
|
||||
GL_STENCIL_TEST,
|
||||
GL_DITHER,
|
||||
GL_SAMPLE_ALPHA_TO_COVERAGE,
|
||||
GL_SAMPLE_COVERAGE,
|
||||
GL_POLYGON_OFFSET_FILL,
|
||||
};
|
||||
size_t capsCount = sizeof(caps) / sizeof(caps[0]);
|
||||
|
||||
UTILS_NOUNROLL
|
||||
for (GLenum capi = 0; capi < capsCount; ++capi) {
|
||||
size_t capIndex = getIndexForCap(caps[capi]);
|
||||
GLenum cap = caps[capi];
|
||||
if (state.enables.caps[capIndex]) {
|
||||
glEnable(cap);
|
||||
} else {
|
||||
glDisable(cap);
|
||||
}
|
||||
}
|
||||
|
||||
// Point sprite size and seamless cubemap filtering are disabled by default in desktop GL.
|
||||
// In OpenGL ES, these flags do not exist because they are always on.
|
||||
#if BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
enable(GL_PROGRAM_POINT_SIZE);
|
||||
#endif
|
||||
|
||||
#ifdef GL_ARB_seamless_cube_map
|
||||
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
#endif
|
||||
|
||||
#ifdef GL_FRAGMENT_SHADER_DERIVATIVE_HINT
|
||||
glHint(GL_FRAGMENT_SHADER_DERIVATIVE_HINT, GL_NICEST);
|
||||
#endif
|
||||
|
||||
#if defined(GL_EXT_clip_control) || defined(GL_ARB_clip_control) || defined(GL_VERSION_4_5)
|
||||
if (ext.EXT_clip_control) {
|
||||
@@ -328,16 +375,18 @@ void OpenGLContext::initExtensionsGLES() noexcept {
|
||||
#if !defined(__EMSCRIPTEN__)
|
||||
ext.EXT_texture_compression_etc2 = true;
|
||||
#endif
|
||||
ext.EXT_texture_filter_anisotropic = exts.has("GL_EXT_texture_filter_anisotropic"sv);
|
||||
ext.GOOGLE_cpp_style_line_directive = exts.has("GL_GOOGLE_cpp_style_line_directive"sv);
|
||||
ext.KHR_debug = exts.has("GL_KHR_debug"sv);
|
||||
ext.OES_EGL_image_external_essl3 = exts.has("GL_OES_EGL_image_external_essl3"sv);
|
||||
ext.QCOM_tiled_rendering = exts.has("GL_QCOM_tiled_rendering"sv);
|
||||
ext.EXT_texture_compression_s3tc = exts.has("GL_EXT_texture_compression_s3tc"sv);
|
||||
ext.EXT_texture_compression_s3tc_srgb = exts.has("GL_EXT_texture_compression_s3tc_srgb"sv);
|
||||
ext.EXT_texture_cube_map_array = exts.has("GL_EXT_texture_cube_map_array"sv) || exts.has("GL_OES_texture_cube_map_array"sv);
|
||||
ext.GOOGLE_cpp_style_line_directive = exts.has("GL_GOOGLE_cpp_style_line_directive"sv);
|
||||
ext.KHR_debug = exts.has("GL_KHR_debug"sv);
|
||||
ext.KHR_texture_compression_astc_hdr = exts.has("GL_KHR_texture_compression_astc_hdr"sv);
|
||||
ext.KHR_texture_compression_astc_ldr = exts.has("GL_KHR_texture_compression_astc_ldr"sv);
|
||||
ext.OES_EGL_image_external_essl3 = exts.has("GL_OES_EGL_image_external_essl3"sv);
|
||||
ext.QCOM_tiled_rendering = exts.has("GL_QCOM_tiled_rendering"sv);
|
||||
ext.WEBGL_compressed_texture_etc = exts.has("WEBGL_compressed_texture_etc"sv);
|
||||
ext.WEBGL_compressed_texture_s3tc = exts.has("WEBGL_compressed_texture_s3tc"sv);
|
||||
ext.WEBGL_compressed_texture_s3tc_srgb = exts.has("WEBGL_compressed_texture_s3tc_srgb"sv);
|
||||
ext.WEBGL_compressed_texture_etc = exts.has("WEBGL_compressed_texture_etc"sv);
|
||||
// ES 3.2 implies EXT_color_buffer_float
|
||||
if (state.major >= 3 && state.minor >= 2) {
|
||||
ext.EXT_color_buffer_float = true;
|
||||
@@ -369,13 +418,15 @@ void OpenGLContext::initExtensionsGL() noexcept {
|
||||
ext.EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv);
|
||||
ext.EXT_shader_framebuffer_fetch = exts.has("GL_EXT_shader_framebuffer_fetch"sv);
|
||||
ext.EXT_texture_compression_etc2 = exts.has("GL_ARB_ES3_compatibility"sv);
|
||||
ext.EXT_texture_compression_s3tc = exts.has("GL_EXT_texture_compression_s3tc"sv);
|
||||
ext.EXT_texture_compression_s3tc_srgb = exts.has("GL_EXT_texture_compression_s3tc_srgb"sv);
|
||||
ext.EXT_texture_filter_anisotropic = exts.has("GL_EXT_texture_filter_anisotropic"sv);
|
||||
ext.EXT_texture_sRGB = exts.has("GL_EXT_texture_sRGB"sv);
|
||||
ext.GOOGLE_cpp_style_line_directive = exts.has("GL_GOOGLE_cpp_style_line_directive"sv);
|
||||
ext.KHR_debug = major >= 4 && minor >= 3;
|
||||
ext.KHR_texture_compression_astc_hdr = exts.has("GL_KHR_texture_compression_astc_hdr"sv);
|
||||
ext.KHR_texture_compression_astc_ldr = exts.has("GL_KHR_texture_compression_astc_ldr"sv);
|
||||
ext.OES_EGL_image_external_essl3 = exts.has("GL_OES_EGL_image_external_essl3"sv);
|
||||
ext.EXT_texture_compression_s3tc = exts.has("GL_EXT_texture_compression_s3tc"sv);
|
||||
ext.EXT_texture_compression_s3tc_srgb = exts.has("GL_EXT_texture_compression_s3tc_srgb"sv);
|
||||
}
|
||||
|
||||
void OpenGLContext::bindBuffer(GLenum target, GLuint buffer) noexcept {
|
||||
@@ -488,4 +539,161 @@ void OpenGLContext::deleteVertexArrays(GLsizei n, const GLuint* arrays) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLContext::resetState() noexcept {
|
||||
// Force GL state to match the Filament state
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, state.draw_fbo);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, state.read_fbo);
|
||||
|
||||
// state.program
|
||||
glUseProgram(state.program.use);
|
||||
|
||||
// state.vao
|
||||
if (state.vao.p) {
|
||||
glBindVertexArray(state.vao.p->vao);
|
||||
} else {
|
||||
bindVertexArray(nullptr);
|
||||
}
|
||||
|
||||
// state.raster
|
||||
glFrontFace(state.raster.frontFace);
|
||||
glCullFace(state.raster.cullFace);
|
||||
glBlendEquationSeparate(state.raster.blendEquationRGB, state.raster.blendEquationA);
|
||||
glBlendFuncSeparate(
|
||||
state.raster.blendFunctionSrcRGB,
|
||||
state.raster.blendFunctionDstRGB,
|
||||
state.raster.blendFunctionSrcA,
|
||||
state.raster.blendFunctionDstA
|
||||
);
|
||||
glColorMask(
|
||||
state.raster.colorMask,
|
||||
state.raster.colorMask,
|
||||
state.raster.colorMask,
|
||||
state.raster.colorMask
|
||||
);
|
||||
glDepthMask(state.raster.depthMask);
|
||||
glDepthFunc(state.raster.depthFunc);
|
||||
|
||||
// state.stencil
|
||||
glStencilFuncSeparate(
|
||||
GL_FRONT,
|
||||
state.stencil.front.func.func,
|
||||
state.stencil.front.func.ref,
|
||||
state.stencil.front.func.mask
|
||||
);
|
||||
glStencilFuncSeparate(
|
||||
GL_BACK,
|
||||
state.stencil.back.func.func,
|
||||
state.stencil.back.func.ref,
|
||||
state.stencil.back.func.mask
|
||||
);
|
||||
glStencilOpSeparate(
|
||||
GL_FRONT,
|
||||
state.stencil.front.op.sfail,
|
||||
state.stencil.front.op.dpfail,
|
||||
state.stencil.front.op.dppass
|
||||
);
|
||||
glStencilOpSeparate(
|
||||
GL_BACK,
|
||||
state.stencil.back.op.sfail,
|
||||
state.stencil.back.op.dpfail,
|
||||
state.stencil.back.op.dppass
|
||||
);
|
||||
glStencilMaskSeparate(GL_FRONT, state.stencil.front.stencilMask);
|
||||
glStencilMaskSeparate(GL_BACK, state.stencil.back.stencilMask);
|
||||
|
||||
// state.polygonOffset
|
||||
glPolygonOffset(state.polygonOffset.factor, state.polygonOffset.units);
|
||||
|
||||
// state.enables
|
||||
setDefaultState();
|
||||
|
||||
// state.buffers
|
||||
// Reset state.buffers to its default state to avoid the complexity and error-prone
|
||||
// nature of resetting the GL state to its existing state
|
||||
state.buffers = {};
|
||||
GLenum bufferTargets[] = {
|
||||
GL_UNIFORM_BUFFER,
|
||||
GL_TRANSFORM_FEEDBACK_BUFFER,
|
||||
#if !defined(__EMSCRIPTEN__)
|
||||
GL_SHADER_STORAGE_BUFFER,
|
||||
#endif
|
||||
GL_ARRAY_BUFFER,
|
||||
GL_COPY_READ_BUFFER,
|
||||
GL_COPY_WRITE_BUFFER,
|
||||
GL_ELEMENT_ARRAY_BUFFER,
|
||||
GL_PIXEL_PACK_BUFFER,
|
||||
GL_PIXEL_UNPACK_BUFFER,
|
||||
};
|
||||
size_t bufferTargetCount = sizeof(bufferTargets) / sizeof(bufferTargets[0]);
|
||||
for (size_t targetArrayIndex = 0; targetArrayIndex < bufferTargetCount; ++targetArrayIndex) {
|
||||
GLenum target = bufferTargets[targetArrayIndex];
|
||||
glBindBuffer(target, 0);
|
||||
}
|
||||
|
||||
for (size_t bufferIndex = 0; bufferIndex < MAX_BUFFER_BINDINGS; ++bufferIndex) {
|
||||
if (bufferIndex < (size_t)gets.max_uniform_buffer_bindings) {
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, bufferIndex, 0);
|
||||
}
|
||||
|
||||
if (bufferIndex < (size_t)gets.max_transform_feedback_separate_attribs) {
|
||||
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, bufferIndex, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// state.textures
|
||||
// Reset state.textures to its default state to avoid the complexity and error-prone
|
||||
// nature of resetting the GL state to its existing state
|
||||
state.textures = {};
|
||||
const GLuint textureTargets[] = {
|
||||
GL_TEXTURE_2D,
|
||||
GL_TEXTURE_2D_ARRAY,
|
||||
GL_TEXTURE_CUBE_MAP,
|
||||
GL_TEXTURE_3D,
|
||||
#if !defined(__EMSCRIPTEN__)
|
||||
GL_TEXTURE_2D_MULTISAMPLE,
|
||||
GL_TEXTURE_EXTERNAL_OES,
|
||||
GL_TEXTURE_CUBE_MAP_ARRAY,
|
||||
#endif
|
||||
};
|
||||
const size_t textureTargetCount = sizeof(textureTargets) / sizeof(textureTargets[0]);
|
||||
for (GLint unit = 0; unit < gets.max_combined_texture_image_units; ++unit) {
|
||||
glActiveTexture(GL_TEXTURE0 + unit);
|
||||
glBindSampler(unit, 0);
|
||||
|
||||
for (size_t textureTargetArrayIndex = 0; textureTargetArrayIndex < textureTargetCount; ++textureTargetArrayIndex) {
|
||||
GLuint target = textureTargets[textureTargetArrayIndex];
|
||||
glBindTexture(target, 0);
|
||||
}
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE0 + state.textures.active);
|
||||
|
||||
// state.unpack
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, state.unpack.alignment);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, state.unpack.row_length);
|
||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, state.unpack.skip_pixels);
|
||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, state.unpack.skip_row);
|
||||
|
||||
// state.pack
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, state.pack.alignment);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, state.pack.row_length);
|
||||
glPixelStorei(GL_PACK_SKIP_PIXELS, state.pack.skip_pixels);
|
||||
glPixelStorei(GL_PACK_SKIP_ROWS, state.pack.skip_row);
|
||||
|
||||
// state.window
|
||||
glScissor(
|
||||
state.window.scissor.x,
|
||||
state.window.scissor.y,
|
||||
state.window.scissor.z,
|
||||
state.window.scissor.w
|
||||
);
|
||||
glViewport(
|
||||
state.window.viewport.x,
|
||||
state.window.viewport.y,
|
||||
state.window.viewport.z,
|
||||
state.window.viewport.w
|
||||
);
|
||||
glDepthRangef(state.window.depthRange.x, state.window.depthRange.y);
|
||||
|
||||
}
|
||||
|
||||
} // namesapce filament
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace filament::backend {
|
||||
@@ -35,6 +36,7 @@ namespace filament::backend {
|
||||
class OpenGLContext {
|
||||
public:
|
||||
static constexpr const size_t MAX_TEXTURE_UNIT_COUNT = MAX_SAMPLER_COUNT;
|
||||
static constexpr const size_t DUMMY_TEXTURE_BINDING = 31; // highest binding less than 32
|
||||
static constexpr const size_t MAX_BUFFER_BINDINGS = 32;
|
||||
typedef math::details::TVec4<GLint> vec4gli;
|
||||
typedef math::details::TVec2<GLclampf> vec2glf;
|
||||
@@ -71,6 +73,7 @@ public:
|
||||
|
||||
ShaderModel getShaderModel() const noexcept { return mShaderModel; }
|
||||
|
||||
void resetState() noexcept;
|
||||
|
||||
inline void useProgram(GLuint program) noexcept;
|
||||
|
||||
@@ -101,9 +104,11 @@ public:
|
||||
inline void colorMask(GLboolean flag) noexcept;
|
||||
inline void depthMask(GLboolean flag) noexcept;
|
||||
inline void depthFunc(GLenum func) noexcept;
|
||||
inline void stencilFunc(GLenum func, GLint ref, GLuint mask) noexcept;
|
||||
inline void stencilOp(GLenum sfail, GLenum dpfail, GLenum dppass) noexcept;
|
||||
inline void stencilMask(GLuint mask) noexcept;
|
||||
inline void stencilFuncSeparate(GLenum funcFront, GLint refFront, GLuint maskFront,
|
||||
GLenum funcBack, GLint refBack, GLuint maskBack) noexcept;
|
||||
inline void stencilOpSeparate(GLenum sfailFront, GLenum dpfailFront, GLenum dppassFront,
|
||||
GLenum sfailBack, GLenum dpfailBack, GLenum dppassBack) noexcept;
|
||||
inline void stencilMaskSeparate(GLuint maskFront, GLuint maskBack) noexcept;
|
||||
inline void polygonOffset(GLfloat factor, GLfloat units) noexcept;
|
||||
inline void beginQuery(GLenum target, GLuint query) noexcept;
|
||||
inline void endQuery(GLenum target) noexcept;
|
||||
@@ -123,6 +128,10 @@ public:
|
||||
GLint max_renderbuffer_size;
|
||||
GLint max_samples;
|
||||
GLint max_uniform_block_size;
|
||||
GLint max_texture_image_units;
|
||||
GLint max_combined_texture_image_units;
|
||||
GLint max_transform_feedback_separate_attribs;
|
||||
GLint max_uniform_buffer_bindings;
|
||||
GLint uniform_buffer_offset_alignment;
|
||||
} gets = {};
|
||||
|
||||
@@ -143,9 +152,12 @@ public:
|
||||
bool EXT_multisampled_render_to_texture = false;
|
||||
bool EXT_multisampled_render_to_texture2 = false;
|
||||
bool EXT_shader_framebuffer_fetch = false;
|
||||
bool KHR_texture_compression_astc_hdr = false;
|
||||
bool KHR_texture_compression_astc_ldr = false;
|
||||
bool EXT_texture_compression_etc2 = false;
|
||||
bool EXT_texture_compression_s3tc = false;
|
||||
bool EXT_texture_compression_s3tc_srgb = false;
|
||||
bool EXT_texture_cube_map_array = false;
|
||||
bool EXT_texture_filter_anisotropic = false;
|
||||
bool EXT_texture_sRGB = false;
|
||||
bool GOOGLE_cpp_style_line_directive = false;
|
||||
@@ -206,7 +218,8 @@ public:
|
||||
// GL and Vulkan and probably Metal.
|
||||
bool allow_read_only_ancillary_feedback_loop = false;
|
||||
|
||||
// Some Adreno drivers would crash gl draw when there's uninitialized uniform array exists, even when the code using that uniform array is not called. it's needed to do an initialization to avoid it.
|
||||
// Some Adreno drivers crash in glDrawXXX() when there's an uninitialized uniform block,
|
||||
// even when the shader doesn't access it.
|
||||
bool enable_initialize_non_used_uniform_array = false;
|
||||
} bugs;
|
||||
|
||||
@@ -220,6 +233,8 @@ public:
|
||||
}
|
||||
void resetProgram() noexcept { state.program.use = 0; }
|
||||
|
||||
FeatureLevel getFeatureLevel() const noexcept { return mFeatureLevel; }
|
||||
|
||||
// Try to keep the State structure sorted by data-access patterns
|
||||
struct State {
|
||||
GLint major = 0;
|
||||
@@ -253,6 +268,9 @@ public:
|
||||
GLboolean colorMask = GL_TRUE;
|
||||
GLboolean depthMask = GL_TRUE;
|
||||
GLenum depthFunc = GL_LESS;
|
||||
} raster;
|
||||
|
||||
struct {
|
||||
struct StencilFunc {
|
||||
GLenum func = GL_ALWAYS;
|
||||
GLint ref = 0;
|
||||
@@ -260,7 +278,7 @@ public:
|
||||
bool operator != (StencilFunc const& rhs) const noexcept {
|
||||
return func != rhs.func || ref != rhs.ref || mask != rhs.mask;
|
||||
}
|
||||
} stencilFunc;
|
||||
};
|
||||
struct StencilOp {
|
||||
GLenum sfail = GL_KEEP;
|
||||
GLenum dpfail = GL_KEEP;
|
||||
@@ -268,9 +286,13 @@ public:
|
||||
bool operator != (StencilOp const& rhs) const noexcept {
|
||||
return sfail != rhs.sfail || dpfail != rhs.dpfail || dppass != rhs.dppass;
|
||||
}
|
||||
} stencilOp;
|
||||
GLuint stencilMask = ~GLuint(0);
|
||||
} raster;
|
||||
};
|
||||
struct {
|
||||
StencilFunc func;
|
||||
StencilOp op;
|
||||
GLuint stencilMask = ~GLuint(0);
|
||||
} front, back;
|
||||
} stencil;
|
||||
|
||||
struct PolygonOffset {
|
||||
GLfloat factor = 0;
|
||||
@@ -292,7 +314,7 @@ public:
|
||||
GLsizeiptr size = 0;
|
||||
} buffers[MAX_BUFFER_BINDINGS];
|
||||
} targets[2]; // there are only 2 indexed buffer target (uniform and transform feedback)
|
||||
GLuint genericBinding[8] = { 0 };
|
||||
GLuint genericBinding[9] = { 0 };
|
||||
} buffers;
|
||||
|
||||
struct {
|
||||
@@ -332,6 +354,7 @@ public:
|
||||
|
||||
private:
|
||||
ShaderModel mShaderModel = ShaderModel::MOBILE;
|
||||
FeatureLevel mFeatureLevel = FeatureLevel::FEATURE_LEVEL_1;
|
||||
|
||||
const std::array<std::tuple<bool const&, char const*, char const*>, sizeof(bugs)> mBugDatabase{{
|
||||
{ bugs.disable_glFlush,
|
||||
@@ -389,6 +412,8 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void setDefaultState() noexcept;
|
||||
|
||||
static constexpr const size_t TEXTURE_TARGET_COUNT =
|
||||
sizeof(state.textures.units[0].targets) / sizeof(state.textures.units[0].targets[0]);
|
||||
|
||||
@@ -440,17 +465,18 @@ constexpr size_t OpenGLContext::getIndexForCap(GLenum cap) noexcept { //NOLINT
|
||||
constexpr size_t OpenGLContext::getIndexForBufferTarget(GLenum target) noexcept {
|
||||
size_t index = 0;
|
||||
switch (target) {
|
||||
// The indexed buffers MUST be first in this list
|
||||
// The indexed buffers MUST be first in this list (those usable with bindBufferRange)
|
||||
case GL_UNIFORM_BUFFER: index = 0; break;
|
||||
case GL_TRANSFORM_FEEDBACK_BUFFER: index = 1; break;
|
||||
case GL_SHADER_STORAGE_BUFFER: index = 2; break;
|
||||
|
||||
case GL_ARRAY_BUFFER: index = 2; break;
|
||||
case GL_COPY_READ_BUFFER: index = 3; break;
|
||||
case GL_COPY_WRITE_BUFFER: index = 4; break;
|
||||
case GL_ELEMENT_ARRAY_BUFFER: index = 5; break;
|
||||
case GL_PIXEL_PACK_BUFFER: index = 6; break;
|
||||
case GL_PIXEL_UNPACK_BUFFER: index = 7; break;
|
||||
default: index = 8; break; // should never happen
|
||||
case GL_ARRAY_BUFFER: index = 3; break;
|
||||
case GL_COPY_READ_BUFFER: index = 4; break;
|
||||
case GL_COPY_WRITE_BUFFER: index = 5; break;
|
||||
case GL_ELEMENT_ARRAY_BUFFER: index = 6; break;
|
||||
case GL_PIXEL_PACK_BUFFER: index = 7; break;
|
||||
case GL_PIXEL_UNPACK_BUFFER: index = 8; break;
|
||||
default: index = 9; break; // should never happen
|
||||
}
|
||||
assert_invariant(index < sizeof(state.buffers.genericBinding)/sizeof(state.buffers.genericBinding[0])); // NOLINT(misc-redundant-expression)
|
||||
return index;
|
||||
@@ -511,7 +537,7 @@ void OpenGLContext::bindVertexArray(RenderPrimitive const* p) noexcept {
|
||||
void OpenGLContext::bindBufferRange(GLenum target, GLuint index, GLuint buffer,
|
||||
GLintptr offset, GLsizeiptr size) noexcept {
|
||||
size_t targetIndex = getIndexForBufferTarget(target);
|
||||
assert_invariant(targetIndex <= 1); // validity check
|
||||
assert_invariant(targetIndex <= 2); // validity check
|
||||
|
||||
// this ALSO sets the generic binding
|
||||
if ( state.buffers.targets[targetIndex].buffers[index].name != buffer
|
||||
@@ -604,21 +630,18 @@ void OpenGLContext::disable(GLenum cap) noexcept {
|
||||
}
|
||||
|
||||
void OpenGLContext::frontFace(GLenum mode) noexcept {
|
||||
// WARNING: don't call this without updating mRasterState
|
||||
update_state(state.raster.frontFace, mode, [&]() {
|
||||
glFrontFace(mode);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLContext::cullFace(GLenum mode) noexcept {
|
||||
// WARNING: don't call this without updating mRasterState
|
||||
update_state(state.raster.cullFace, mode, [&]() {
|
||||
glCullFace(mode);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLContext::blendEquation(GLenum modeRGB, GLenum modeA) noexcept {
|
||||
// WARNING: don't call this without updating mRasterState
|
||||
if (UTILS_UNLIKELY(
|
||||
state.raster.blendEquationRGB != modeRGB || state.raster.blendEquationA != modeA)) {
|
||||
state.raster.blendEquationRGB = modeRGB;
|
||||
@@ -628,7 +651,6 @@ void OpenGLContext::blendEquation(GLenum modeRGB, GLenum modeA) noexcept {
|
||||
}
|
||||
|
||||
void OpenGLContext::blendFunction(GLenum srcRGB, GLenum srcA, GLenum dstRGB, GLenum dstA) noexcept {
|
||||
// WARNING: don't call this without updating mRasterState
|
||||
if (UTILS_UNLIKELY(
|
||||
state.raster.blendFunctionSrcRGB != srcRGB ||
|
||||
state.raster.blendFunctionSrcA != srcA ||
|
||||
@@ -643,43 +665,48 @@ void OpenGLContext::blendFunction(GLenum srcRGB, GLenum srcA, GLenum dstRGB, GLe
|
||||
}
|
||||
|
||||
void OpenGLContext::colorMask(GLboolean flag) noexcept {
|
||||
// WARNING: don't call this without updating mRasterState
|
||||
update_state(state.raster.colorMask, flag, [&]() {
|
||||
glColorMask(flag, flag, flag, flag);
|
||||
});
|
||||
}
|
||||
void OpenGLContext::depthMask(GLboolean flag) noexcept {
|
||||
// WARNING: don't call this without updating mRasterState
|
||||
update_state(state.raster.depthMask, flag, [&]() {
|
||||
glDepthMask(flag);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLContext::depthFunc(GLenum func) noexcept {
|
||||
// WARNING: don't call this without updating mRasterState
|
||||
update_state(state.raster.depthFunc, func, [&]() {
|
||||
glDepthFunc(func);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLContext::stencilFunc(GLenum func, GLint ref, GLuint mask) noexcept {
|
||||
// WARNING: don't call this without updating mRasterState
|
||||
update_state(state.raster.stencilFunc, {func, ref, mask}, [&]() {
|
||||
glStencilFunc(func, ref, mask);
|
||||
void OpenGLContext::stencilFuncSeparate(GLenum funcFront, GLint refFront, GLuint maskFront,
|
||||
GLenum funcBack, GLint refBack, GLuint maskBack) noexcept {
|
||||
update_state(state.stencil.front.func, {funcFront, refFront, maskFront}, [&]() {
|
||||
glStencilFuncSeparate(GL_FRONT, funcFront, refFront, maskFront);
|
||||
});
|
||||
update_state(state.stencil.back.func, {funcBack, refBack, maskBack}, [&]() {
|
||||
glStencilFuncSeparate(GL_BACK, funcBack, refBack, maskBack);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLContext::stencilOp(GLenum sfail, GLenum dpfail, GLenum dppass) noexcept {
|
||||
// WARNING: don't call this without updating mRasterState
|
||||
update_state(state.raster.stencilOp, {sfail, dpfail, dppass}, [&]() {
|
||||
glStencilOp(sfail, dpfail, dppass);
|
||||
void OpenGLContext::stencilOpSeparate(GLenum sfailFront, GLenum dpfailFront, GLenum dppassFront,
|
||||
GLenum sfailBack, GLenum dpfailBack, GLenum dppassBack) noexcept {
|
||||
update_state(state.stencil.front.op, {sfailFront, dpfailFront, dppassFront}, [&]() {
|
||||
glStencilOpSeparate(GL_FRONT, sfailFront, dpfailFront, dppassFront);
|
||||
});
|
||||
update_state(state.stencil.back.op, {sfailBack, dpfailBack, dppassBack}, [&]() {
|
||||
glStencilOpSeparate(GL_BACK, sfailBack, dpfailBack, dppassBack);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLContext::stencilMask(GLuint mask) noexcept {
|
||||
// WARNING: don't call this without updating mRasterState
|
||||
update_state(state.raster.stencilMask, mask, [&]() {
|
||||
glStencilMask(mask);
|
||||
void OpenGLContext::stencilMaskSeparate(GLuint maskFront, GLuint maskBack) noexcept {
|
||||
update_state(state.stencil.front.stencilMask, maskFront, [&]() {
|
||||
glStencilMaskSeparate(GL_FRONT, maskFront);
|
||||
});
|
||||
update_state(state.stencil.back.stencilMask, maskBack, [&]() {
|
||||
glStencilMaskSeparate(GL_BACK, maskBack);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "OpenGLTimerQuery.h"
|
||||
#include "OpenGLContext.h"
|
||||
|
||||
#include <backend/SamplerDescriptor.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Panic.h>
|
||||
@@ -233,6 +235,9 @@ ShaderModel OpenGLDriver::getShaderModel() const noexcept {
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Change and track GL state
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void OpenGLDriver::resetState(int) {
|
||||
mContext.resetState();
|
||||
}
|
||||
|
||||
void OpenGLDriver::bindSampler(GLuint unit, GLuint sampler) noexcept {
|
||||
mContext.bindSampler(unit, sampler);
|
||||
@@ -249,32 +254,22 @@ void OpenGLDriver::useProgram(OpenGLProgram* p) noexcept {
|
||||
}
|
||||
|
||||
|
||||
void OpenGLDriver::setRasterStateSlow(RasterState rs) noexcept {
|
||||
mRasterState = rs;
|
||||
void OpenGLDriver::setRasterState(RasterState rs) noexcept {
|
||||
auto& gl = mContext;
|
||||
|
||||
mRenderPassColorWrite |= rs.colorWrite;
|
||||
mRenderPassDepthWrite |= rs.depthWrite;
|
||||
|
||||
// culling state
|
||||
switch (rs.culling) {
|
||||
case CullingMode::NONE:
|
||||
gl.disable(GL_CULL_FACE);
|
||||
break;
|
||||
case CullingMode::FRONT:
|
||||
gl.cullFace(GL_FRONT);
|
||||
break;
|
||||
case CullingMode::BACK:
|
||||
gl.cullFace(GL_BACK);
|
||||
break;
|
||||
case CullingMode::FRONT_AND_BACK:
|
||||
gl.cullFace(GL_FRONT_AND_BACK);
|
||||
break;
|
||||
if (rs.culling == CullingMode::NONE) {
|
||||
gl.disable(GL_CULL_FACE);
|
||||
} else {
|
||||
gl.enable(GL_CULL_FACE);
|
||||
gl.cullFace(getCullingMode(rs.culling));
|
||||
}
|
||||
|
||||
gl.frontFace(rs.inverseFrontFaces ? GL_CW : GL_CCW);
|
||||
|
||||
if (rs.culling != CullingMode::NONE) {
|
||||
gl.enable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
// blending state
|
||||
if (!rs.hasBlending()) {
|
||||
gl.disable(GL_BLEND);
|
||||
@@ -300,19 +295,6 @@ void OpenGLDriver::setRasterStateSlow(RasterState rs) noexcept {
|
||||
gl.depthMask(GLboolean(rs.depthWrite));
|
||||
}
|
||||
|
||||
// stencil test / operation
|
||||
if (rs.stencilFunc == RasterState::StencilFunction::A && !rs.stencilWrite) {
|
||||
gl.disable(GL_STENCIL_TEST);
|
||||
} else {
|
||||
gl.enable(GL_STENCIL_TEST);
|
||||
gl.stencilFunc(getStencilFunc(rs.stencilFunc), rs.stencilRef, ~GLuint(0));
|
||||
gl.stencilOp(getStencilOp(rs.stencilOpStencilFail),
|
||||
getStencilOp(rs.stencilOpDepthFail),
|
||||
getStencilOp(rs.stencilOpDepthStencilPass));
|
||||
GLuint stencilMask = rs.stencilWrite ? ~GLuint(0) : 0x00;
|
||||
gl.stencilMask(stencilMask);
|
||||
}
|
||||
|
||||
// write masks
|
||||
gl.colorMask(GLboolean(rs.colorWrite));
|
||||
|
||||
@@ -324,6 +306,49 @@ void OpenGLDriver::setRasterStateSlow(RasterState rs) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDriver::setStencilState(StencilState ss) noexcept {
|
||||
auto& gl = mContext;
|
||||
|
||||
mRenderPassStencilWrite |= ss.stencilWrite;
|
||||
|
||||
// stencil test / operation
|
||||
// GL_STENCIL_TEST must be enabled if we're testing OR writing to the stencil buffer.
|
||||
if (UTILS_LIKELY(
|
||||
ss.front.stencilFunc == StencilState::StencilFunction::A &&
|
||||
ss.back.stencilFunc == StencilState::StencilFunction::A &&
|
||||
ss.front.stencilOpDepthFail == StencilOperation::KEEP &&
|
||||
ss.back.stencilOpDepthFail == StencilOperation::KEEP &&
|
||||
ss.front.stencilOpStencilFail == StencilOperation::KEEP &&
|
||||
ss.back.stencilOpStencilFail == StencilOperation::KEEP &&
|
||||
ss.front.stencilOpDepthStencilPass == StencilOperation::KEEP &&
|
||||
ss.back.stencilOpDepthStencilPass == StencilOperation::KEEP)) {
|
||||
// that's equivalent to having the stencil test disabled
|
||||
gl.disable(GL_STENCIL_TEST);
|
||||
} else {
|
||||
gl.enable(GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
// glStencilFuncSeparate() also sets the reference value, which may be used depending
|
||||
// on the stencilOp, so we always need to call glStencilFuncSeparate().
|
||||
gl.stencilFuncSeparate(
|
||||
getStencilFunc(ss.front.stencilFunc), ss.front.ref, ss.front.readMask,
|
||||
getStencilFunc(ss.back.stencilFunc), ss.back.ref, ss.back.readMask);
|
||||
|
||||
if (UTILS_LIKELY(!ss.stencilWrite)) {
|
||||
gl.stencilMaskSeparate(0x00, 0x00);
|
||||
} else {
|
||||
// Stencil ops are only relevant when stencil write is enabled
|
||||
gl.stencilOpSeparate(
|
||||
getStencilOp(ss.front.stencilOpStencilFail),
|
||||
getStencilOp(ss.front.stencilOpDepthFail),
|
||||
getStencilOp(ss.front.stencilOpDepthStencilPass),
|
||||
getStencilOp(ss.back.stencilOpStencilFail),
|
||||
getStencilOp(ss.back.stencilOpDepthFail),
|
||||
getStencilOp(ss.back.stencilOpDepthStencilPass));
|
||||
gl.stencilMaskSeparate(ss.front.writeMask, ss.back.writeMask);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Creating driver objects
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -490,8 +515,8 @@ void OpenGLDriver::textureStorage(OpenGLDriver::GLTexture* t,
|
||||
|
||||
auto& gl = mContext;
|
||||
|
||||
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t);
|
||||
gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
|
||||
gl.activeTexture(OpenGLContext::DUMMY_TEXTURE_BINDING);
|
||||
|
||||
switch (t->gl.target) {
|
||||
case GL_TEXTURE_2D:
|
||||
@@ -1484,6 +1509,9 @@ bool OpenGLDriver::isTextureFormatSupported(TextureFormat format) {
|
||||
return ext.EXT_texture_compression_s3tc || // this is ES specific
|
||||
ext.WEBGL_compressed_texture_s3tc; // this is WEBGL specific
|
||||
}
|
||||
if (isASTCCompression(format)) {
|
||||
return ext.KHR_texture_compression_astc_hdr;
|
||||
}
|
||||
return getInternalFormat(format) != 0;
|
||||
}
|
||||
|
||||
@@ -1617,6 +1645,10 @@ bool OpenGLDriver::isWorkaroundNeeded(Workaround workaround) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FeatureLevel OpenGLDriver::getFeatureLevel() {
|
||||
return mContext.getFeatureLevel();
|
||||
}
|
||||
|
||||
math::float2 OpenGLDriver::getClipSpaceParams() {
|
||||
return mContext.ext.EXT_clip_control ?
|
||||
// z-coordinate of virtual and physical clip-space is in [-w, 0]
|
||||
@@ -1812,7 +1844,7 @@ void OpenGLDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
|
||||
params.filterMag = SamplerMagFilter::NEAREST;
|
||||
params.filterMin = SamplerMinFilter::NEAREST;
|
||||
#ifndef NDEBUG
|
||||
slog.w << "SamplerGroup specifies a filtered depth texture, which is not allowed."
|
||||
slog.w << "HwSamplerGroup specifies a filtered depth texture, which is not allowed."
|
||||
<< io::endl;
|
||||
#endif
|
||||
}
|
||||
@@ -1842,8 +1874,8 @@ void OpenGLDriver::setMinMaxLevels(Handle<HwTexture> th, uint32_t minLevel, uint
|
||||
auto& gl = mContext;
|
||||
|
||||
GLTexture* t = handle_cast<GLTexture *>(th);
|
||||
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t);
|
||||
gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
|
||||
gl.activeTexture(OpenGLContext::DUMMY_TEXTURE_BINDING);
|
||||
|
||||
// Must fit within int8_t.
|
||||
assert_invariant(minLevel <= 0x7f && maxLevel <= 0x7f);
|
||||
@@ -1879,8 +1911,8 @@ void OpenGLDriver::generateMipmaps(Handle<HwTexture> th) {
|
||||
assert_invariant(t->gl.target != GL_TEXTURE_2D_MULTISAMPLE);
|
||||
// Note: glGenerateMimap can also fail if the internal format is not both
|
||||
// color-renderable and filterable (i.e.: doesn't work for depth)
|
||||
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t);
|
||||
gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
|
||||
gl.activeTexture(OpenGLContext::DUMMY_TEXTURE_BINDING);
|
||||
|
||||
t->gl.baseLevel = 0;
|
||||
t->gl.maxLevel = static_cast<int8_t>(t->levels - 1);
|
||||
@@ -1927,8 +1959,8 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
|
||||
// fallthrough...
|
||||
case SamplerType::SAMPLER_2D:
|
||||
// NOTE: GL_TEXTURE_2D_MULTISAMPLE is not allowed
|
||||
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t);
|
||||
gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
|
||||
gl.activeTexture(OpenGLContext::DUMMY_TEXTURE_BINDING);
|
||||
assert_invariant(t->gl.target == GL_TEXTURE_2D);
|
||||
glTexSubImage2D(t->gl.target, GLint(level),
|
||||
GLint(xoffset), GLint(yoffset),
|
||||
@@ -1936,8 +1968,8 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
|
||||
break;
|
||||
case SamplerType::SAMPLER_3D:
|
||||
assert_invariant(zoffset + depth <= std::max(1u, t->depth >> level));
|
||||
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t);
|
||||
gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
|
||||
gl.activeTexture(OpenGLContext::DUMMY_TEXTURE_BINDING);
|
||||
assert_invariant(t->gl.target == GL_TEXTURE_3D);
|
||||
glTexSubImage3D(t->gl.target, GLint(level),
|
||||
GLint(xoffset), GLint(yoffset), GLint(zoffset),
|
||||
@@ -1947,8 +1979,8 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
assert_invariant(zoffset + depth <= t->depth);
|
||||
// NOTE: GL_TEXTURE_2D_MULTISAMPLE is not allowed
|
||||
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t);
|
||||
gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
|
||||
gl.activeTexture(OpenGLContext::DUMMY_TEXTURE_BINDING);
|
||||
assert_invariant(t->gl.target == GL_TEXTURE_2D_ARRAY ||
|
||||
t->gl.target == GL_TEXTURE_CUBE_MAP_ARRAY);
|
||||
glTexSubImage3D(t->gl.target, GLint(level),
|
||||
@@ -1957,8 +1989,8 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
|
||||
break;
|
||||
case SamplerType::SAMPLER_CUBEMAP: {
|
||||
assert_invariant(t->gl.target == GL_TEXTURE_CUBE_MAP);
|
||||
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t);
|
||||
gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
|
||||
gl.activeTexture(OpenGLContext::DUMMY_TEXTURE_BINDING);
|
||||
|
||||
assert_invariant(width == height);
|
||||
const size_t faceSize = PixelBufferDescriptor::computeDataSize(
|
||||
@@ -2021,8 +2053,8 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level,
|
||||
// fallthrough...
|
||||
case SamplerType::SAMPLER_2D:
|
||||
// NOTE: GL_TEXTURE_2D_MULTISAMPLE is not allowed
|
||||
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t);
|
||||
gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
|
||||
gl.activeTexture(OpenGLContext::DUMMY_TEXTURE_BINDING);
|
||||
assert_invariant(t->gl.target == GL_TEXTURE_2D);
|
||||
glCompressedTexSubImage2D(t->gl.target, GLint(level),
|
||||
GLint(xoffset), GLint(yoffset),
|
||||
@@ -2030,8 +2062,8 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level,
|
||||
t->gl.internalFormat, imageSize, p.buffer);
|
||||
break;
|
||||
case SamplerType::SAMPLER_3D:
|
||||
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t);
|
||||
gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
|
||||
gl.activeTexture(OpenGLContext::DUMMY_TEXTURE_BINDING);
|
||||
assert_invariant(t->gl.target == GL_TEXTURE_3D);
|
||||
glCompressedTexSubImage3D(t->gl.target, GLint(level),
|
||||
GLint(xoffset), GLint(yoffset), GLint(zoffset),
|
||||
@@ -2049,8 +2081,8 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level,
|
||||
break;
|
||||
case SamplerType::SAMPLER_CUBEMAP: {
|
||||
assert_invariant(t->gl.target == GL_TEXTURE_CUBE_MAP);
|
||||
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t);
|
||||
gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
|
||||
gl.activeTexture(OpenGLContext::DUMMY_TEXTURE_BINDING);
|
||||
|
||||
assert_invariant(width == height);
|
||||
const size_t faceSize = PixelBufferDescriptor::computeDataSize(
|
||||
@@ -2110,8 +2142,8 @@ void OpenGLDriver::setExternalTexture(GLTexture* t, void* image) {
|
||||
assert_invariant(t->target == SamplerType::SAMPLER_EXTERNAL);
|
||||
assert_invariant(t->gl.target == GL_TEXTURE_EXTERNAL_OES);
|
||||
|
||||
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t);
|
||||
gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
|
||||
gl.activeTexture(OpenGLContext::DUMMY_TEXTURE_BINDING);
|
||||
|
||||
#ifdef GL_OES_EGL_image
|
||||
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, static_cast<GLeglImageOES>(image));
|
||||
@@ -2311,9 +2343,9 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
// EXT_multisampled_render_to_texture emulation).
|
||||
// We would need to perform a "backward" resolve, i.e. load the resolved texture into the
|
||||
// tile, everything must appear as though the multi-sample buffer was lost.
|
||||
// However Filament specifies that a non multi-sample attachment to a
|
||||
// However, Filament specifies that a non multi-sample attachment to a
|
||||
// multi-sample RenderTarget is always discarded. We do this because implementing
|
||||
// the load on Metal is not trivial and it's not a feature we rely on at this time.
|
||||
// the load on Metal is not trivial, and it's not a feature we rely on at this time.
|
||||
discardFlags |= rt->gl.resolve;
|
||||
}
|
||||
|
||||
@@ -2324,8 +2356,9 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
}
|
||||
|
||||
// we need to reset those after we call clearWithRasterPipe()
|
||||
mRenderPassColorWrite = any(clearFlags & TargetBufferFlags::COLOR_ALL);
|
||||
mRenderPassDepthWrite = any(clearFlags & TargetBufferFlags::DEPTH);
|
||||
mRenderPassColorWrite = any(clearFlags & TargetBufferFlags::COLOR_ALL);
|
||||
mRenderPassDepthWrite = any(clearFlags & TargetBufferFlags::DEPTH);
|
||||
mRenderPassStencilWrite = any(clearFlags & TargetBufferFlags::STENCIL);
|
||||
|
||||
gl.viewport(params.viewport.left, params.viewport.bottom,
|
||||
(GLsizei)params.viewport.width, (GLsizei)params.viewport.height);
|
||||
@@ -2354,11 +2387,17 @@ void OpenGLDriver::endRenderPass(int) {
|
||||
}
|
||||
|
||||
if (!mRenderPassColorWrite) {
|
||||
// ignore discard flags if the buffer wasn't written at all
|
||||
discardFlags &= ~TargetBufferFlags::COLOR_ALL;
|
||||
}
|
||||
if (!mRenderPassDepthWrite) {
|
||||
// ignore discard flags if the buffer wasn't written at all
|
||||
discardFlags &= ~TargetBufferFlags::DEPTH;
|
||||
}
|
||||
if (!mRenderPassStencilWrite) {
|
||||
// ignore discard flags if the buffer wasn't written at all
|
||||
discardFlags &= ~TargetBufferFlags::STENCIL;
|
||||
}
|
||||
|
||||
// glInvalidateFramebuffer appeared on GLES 3.0 and GL4.3, for simplicity we just
|
||||
// ignore it on GL (rather than having to do a runtime check).
|
||||
@@ -2473,29 +2512,21 @@ GLsizei OpenGLDriver::getAttachments(AttachmentArray& attachments,
|
||||
}
|
||||
|
||||
// Sets up a scissor rectangle that automatically gets clipped against the viewport.
|
||||
void OpenGLDriver::setViewportScissor(Viewport const& viewportScissor) noexcept {
|
||||
void OpenGLDriver::setScissor(Viewport const& scissor) noexcept {
|
||||
constexpr uint32_t maxvalu = std::numeric_limits<int32_t>::max();
|
||||
|
||||
auto& gl = mContext;
|
||||
|
||||
// In OpenGL, all four scissor parameters are actually signed, so clamp to MAX_INT32.
|
||||
const int32_t maxval = std::numeric_limits<int32_t>::max();
|
||||
int32_t left = std::min(viewportScissor.left, maxval);
|
||||
int32_t bottom = std::min(viewportScissor.bottom, maxval);
|
||||
uint32_t width = std::min(viewportScissor.width, uint32_t(maxval));
|
||||
uint32_t height = std::min(viewportScissor.height, uint32_t(maxval));
|
||||
// Compute the intersection of the requested scissor rectangle with the current viewport.
|
||||
// Note that the viewport rectangle isn't necessarily equal to the bounds of the current
|
||||
// Filament View (e.g., when post-processing is enabled).
|
||||
OpenGLContext::vec4gli scissor;
|
||||
OpenGLContext::vec4gli viewport = gl.getViewport();
|
||||
scissor.x = std::max((int32_t)left, viewport[0]);
|
||||
scissor.y = std::max((int32_t)bottom, viewport[1]);
|
||||
int32_t right = std::min((int32_t)left + (int32_t)width, viewport[0] + viewport[2]);
|
||||
int32_t top = std::min((int32_t)bottom + (int32_t)height, viewport[1] + viewport[3]);
|
||||
// Compute width / height of the intersected region. If there's no intersection, pass zeroes
|
||||
// rather than negative values to satisfy OpenGL requirements.
|
||||
scissor.z = std::max(0, right - scissor.x);
|
||||
scissor.w = std::max(0, top - scissor.y);
|
||||
gl.setScissor(scissor.x, scissor.y, scissor.z, scissor.w);
|
||||
// TODO: disable scissor when it is bigger than the current surface?
|
||||
if (scissor.left == 0 && scissor.bottom == 0 &&
|
||||
scissor.width >= maxvalu && scissor.height >= maxvalu) {
|
||||
gl.disable(GL_SCISSOR_TEST);
|
||||
return;
|
||||
}
|
||||
|
||||
gl.setScissor(
|
||||
GLint(scissor.left), GLint(scissor.bottom),
|
||||
GLint(scissor.width), GLint(scissor.height));
|
||||
gl.enable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
@@ -2546,21 +2577,37 @@ void OpenGLDriver::bindUniformBuffer(uint32_t index, Handle<HwBufferObject> ubh)
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
|
||||
void OpenGLDriver::bindUniformBufferRange(uint32_t index, Handle<HwBufferObject> ubh,
|
||||
uint32_t offset, uint32_t size) {
|
||||
void OpenGLDriver::bindBufferRange(BufferObjectBinding bindingType, uint32_t index,
|
||||
Handle<HwBufferObject> ubh, uint32_t offset, uint32_t size) {
|
||||
DEBUG_MARKER()
|
||||
auto& gl = mContext;
|
||||
|
||||
assert_invariant(bindingType == BufferObjectBinding::SHADER_STORAGE ||
|
||||
bindingType == BufferObjectBinding::UNIFORM);
|
||||
|
||||
GLBufferObject* ub = handle_cast<GLBufferObject *>(ubh);
|
||||
assert_invariant(ub->gl.binding == GL_UNIFORM_BUFFER);
|
||||
|
||||
GLenum target = GLUtils::getBufferBindingType(bindingType);
|
||||
|
||||
assert_invariant(bindingType == BufferObjectBinding::SHADER_STORAGE ||
|
||||
ub->gl.binding == target);
|
||||
|
||||
assert_invariant(offset + size <= ub->byteCount);
|
||||
gl.bindBufferRange(ub->gl.binding, GLuint(index), ub->gl.id, offset, size);
|
||||
gl.bindBufferRange(target, GLuint(index), ub->gl.id, offset, size);
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
|
||||
void OpenGLDriver::unbindBuffer(BufferObjectBinding bindingType, uint32_t index) {
|
||||
DEBUG_MARKER()
|
||||
auto& gl = mContext;
|
||||
GLenum target = GLUtils::getBufferBindingType(bindingType);
|
||||
gl.bindBufferRange(target, GLuint(index), 0, 0, 0);
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
|
||||
void OpenGLDriver::bindSamplers(uint32_t index, Handle<HwSamplerGroup> sbh) {
|
||||
DEBUG_MARKER()
|
||||
assert_invariant(index < Program::BINDING_COUNT);
|
||||
assert_invariant(index < Program::SAMPLER_BINDING_COUNT);
|
||||
GLSamplerGroup* sb = handle_cast<GLSamplerGroup *>(sbh);
|
||||
mSamplerBindings[index] = sb;
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
@@ -2731,6 +2778,58 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDriver::readBufferSubData(backend::BufferObjectHandle boh,
|
||||
uint32_t offset, uint32_t size, backend::BufferDescriptor&& p) {
|
||||
auto& gl = mContext;
|
||||
|
||||
GLBufferObject const* bo = handle_cast<GLBufferObject const*>(boh);
|
||||
|
||||
// TODO: measure the two solutions
|
||||
if constexpr (true) {
|
||||
// schedule a copy of the buffer we're reading into a PBO, this *should* happen
|
||||
// asynchronously without stalling the CPU.
|
||||
GLuint pbo;
|
||||
glGenBuffers(1, &pbo);
|
||||
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, (GLsizeiptr)size, nullptr, GL_STATIC_DRAW);
|
||||
gl.bindBuffer(bo->gl.binding, bo->gl.id);
|
||||
glCopyBufferSubData(bo->gl.binding, GL_PIXEL_PACK_BUFFER, offset, 0, size);
|
||||
gl.bindBuffer(bo->gl.binding, 0);
|
||||
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
|
||||
// then, we schedule a mapBuffer of the PBO later, once the fence has signaled
|
||||
auto* pUserBuffer = new BufferDescriptor(std::move(p));
|
||||
whenGpuCommandsComplete([this, size, pbo, pUserBuffer]() mutable {
|
||||
BufferDescriptor& p = *pUserBuffer;
|
||||
auto& gl = mContext;
|
||||
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
|
||||
void* vaddr = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, size, GL_MAP_READ_BIT);
|
||||
if (vaddr) {
|
||||
memcpy(p.buffer, vaddr, size);
|
||||
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
||||
}
|
||||
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
glDeleteBuffers(1, &pbo);
|
||||
scheduleDestroy(std::move(p));
|
||||
delete pUserBuffer;
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
});
|
||||
} else {
|
||||
gl.bindBuffer(bo->gl.binding, bo->gl.id);
|
||||
// TODO: this glMapBufferRange may stall. Ideally we want to use whenGpuCommandsComplete
|
||||
// but that's tricky because boh could be destroyed right after this call.
|
||||
void* vaddr = glMapBufferRange(bo->gl.binding, offset, size, GL_MAP_READ_BIT);
|
||||
if (vaddr) {
|
||||
memcpy(p.buffer, vaddr, size);
|
||||
glUnmapBuffer(bo->gl.binding);
|
||||
}
|
||||
gl.bindBuffer(bo->gl.binding, 0);
|
||||
scheduleDestroy(std::move(p));
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDriver::whenGpuCommandsComplete(std::function<void()> fn) noexcept {
|
||||
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
mGpuCommandCompleteOps.emplace_back(sync, std::move(fn));
|
||||
@@ -2844,7 +2943,7 @@ void OpenGLDriver::endFrame(uint32_t frameId) {
|
||||
// at least do some minimal safety things here, such as resetting the VAO to 0.
|
||||
auto& gl = mContext;
|
||||
gl.bindVertexArray(nullptr);
|
||||
for (int unit = OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1; unit >= 0; unit--) {
|
||||
for (int unit = OpenGLContext::DUMMY_TEXTURE_BINDING; unit >= 0; unit--) {
|
||||
gl.bindTexture(unit, GL_TEXTURE_2D, 0);
|
||||
}
|
||||
gl.disable(GL_CULL_FACE);
|
||||
@@ -2883,17 +2982,15 @@ void OpenGLDriver::finish(int) {
|
||||
UTILS_NOINLINE
|
||||
void OpenGLDriver::clearWithRasterPipe(TargetBufferFlags clearFlags,
|
||||
math::float4 const& linearColor, GLfloat depth, GLint stencil) noexcept {
|
||||
RasterState rs(mRasterState);
|
||||
|
||||
if (any(clearFlags & TargetBufferFlags::COLOR_ALL)) {
|
||||
rs.colorWrite = true;
|
||||
mContext.colorMask(GL_TRUE);
|
||||
}
|
||||
if (any(clearFlags & TargetBufferFlags::DEPTH)) {
|
||||
rs.depthWrite = true;
|
||||
mContext.depthMask(GL_TRUE);
|
||||
}
|
||||
// stencil state is not part of the RasterState currently
|
||||
if (any(clearFlags & (TargetBufferFlags::COLOR_ALL | TargetBufferFlags::DEPTH))) {
|
||||
setRasterState(rs);
|
||||
if (any(clearFlags & TargetBufferFlags::STENCIL)) {
|
||||
mContext.stencilMaskSeparate(0xFF, mContext.state.stencil.back.stencilMask);
|
||||
}
|
||||
|
||||
if (any(clearFlags & TargetBufferFlags::COLOR0)) {
|
||||
@@ -3007,8 +3104,8 @@ void OpenGLDriver::updateTextureLodRange(GLTexture* texture, int8_t targetLevel)
|
||||
auto& gl = mContext;
|
||||
if (texture && any(texture->usage & TextureUsage::SAMPLEABLE)) {
|
||||
if (targetLevel < texture->gl.baseLevel || targetLevel > texture->gl.maxLevel) {
|
||||
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, texture);
|
||||
gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, texture);
|
||||
gl.activeTexture(OpenGLContext::DUMMY_TEXTURE_BINDING);
|
||||
if (targetLevel < texture->gl.baseLevel) {
|
||||
texture->gl.baseLevel = targetLevel;
|
||||
glTexParameteri(texture->gl.target, GL_TEXTURE_BASE_LEVEL, targetLevel);
|
||||
@@ -3054,10 +3151,11 @@ void OpenGLDriver::draw(PipelineState state, Handle<HwRenderPrimitive> rph, uint
|
||||
}
|
||||
|
||||
setRasterState(state.rasterState);
|
||||
setStencilState(state.stencilState);
|
||||
|
||||
gl.polygonOffset(state.polygonOffset.slope, state.polygonOffset.constant);
|
||||
|
||||
setViewportScissor(state.scissor);
|
||||
setScissor(state.scissor);
|
||||
|
||||
if (UTILS_LIKELY(instanceCount <= 1)) {
|
||||
glDrawRangeElements(GLenum(rp->type), rp->minIndex, rp->maxIndex, (GLsizei)rp->count,
|
||||
@@ -3075,6 +3173,32 @@ void OpenGLDriver::draw(PipelineState state, Handle<HwRenderPrimitive> rph, uint
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGroupCount) {
|
||||
executeRenderPassOps();
|
||||
|
||||
OpenGLProgram* p = handle_cast<OpenGLProgram*>(program);
|
||||
|
||||
// If the material debugger is enabled, avoid fatal (or cascading) errors and that can occur
|
||||
// during the draw call when the program is invalid. The shader compile error has already been
|
||||
// dumped to the console at this point, so it's fine to simply return early.
|
||||
if (FILAMENT_ENABLE_MATDBG && UTILS_UNLIKELY(!p->isValid())) {
|
||||
return;
|
||||
}
|
||||
|
||||
useProgram(p);
|
||||
|
||||
#if defined(GL_ES_VERSION_3_1) || defined(GL_VERSION_4_3)
|
||||
// FIXME: this line is commented-out for now due to issues switching G3 clients to API 21.
|
||||
// glDispatchCompute(workGroupCount.x, workGroupCount.y, workGroupCount.z);
|
||||
#endif
|
||||
|
||||
#ifdef FILAMENT_ENABLE_MATDBG
|
||||
CHECK_GL_ERROR_NON_FATAL(utils::slog.e)
|
||||
#else
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
#endif
|
||||
}
|
||||
|
||||
// explicit instantiation of the Dispatcher
|
||||
template class ConcreteDispatcher<OpenGLDriver>;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "private/backend/AcquiredImage.h"
|
||||
#include "private/backend/Driver.h"
|
||||
#include "private/backend/HandleAllocator.h"
|
||||
#include "private/backend/Program.h"
|
||||
#include "backend/Program.h"
|
||||
|
||||
#include "backend/TargetBufferInfo.h"
|
||||
|
||||
@@ -277,14 +277,9 @@ private:
|
||||
void framebufferTexture(TargetBufferInfo const& binfo,
|
||||
GLRenderTarget const* rt, GLenum attachment) noexcept;
|
||||
|
||||
void setRasterStateSlow(RasterState rs) noexcept;
|
||||
void setRasterState(RasterState rs) noexcept {
|
||||
mRenderPassColorWrite |= rs.colorWrite;
|
||||
mRenderPassDepthWrite |= rs.depthWrite;
|
||||
if (UTILS_UNLIKELY(rs != mRasterState)) {
|
||||
setRasterStateSlow(rs);
|
||||
}
|
||||
}
|
||||
void setRasterState(RasterState rs) noexcept;
|
||||
|
||||
void setStencilState(StencilState ss) noexcept;
|
||||
|
||||
void setTextureData(GLTexture* t,
|
||||
uint32_t level,
|
||||
@@ -328,7 +323,7 @@ private:
|
||||
return pos->second;
|
||||
}
|
||||
|
||||
const std::array<GLSamplerGroup*, Program::BINDING_COUNT>& getSamplerBindings() const {
|
||||
const std::array<GLSamplerGroup*, Program::SAMPLER_BINDING_COUNT>& getSamplerBindings() const {
|
||||
return mSamplerBindings;
|
||||
}
|
||||
|
||||
@@ -336,21 +331,20 @@ private:
|
||||
static GLsizei getAttachments(AttachmentArray& attachments,
|
||||
GLRenderTarget const* rt, TargetBufferFlags buffers) noexcept;
|
||||
|
||||
RasterState mRasterState;
|
||||
|
||||
// state required to represent the current render pass
|
||||
Handle<HwRenderTarget> mRenderPassTarget;
|
||||
RenderPassParams mRenderPassParams;
|
||||
GLboolean mRenderPassColorWrite{};
|
||||
GLboolean mRenderPassDepthWrite{};
|
||||
GLboolean mRenderPassStencilWrite{};
|
||||
|
||||
void clearWithRasterPipe(TargetBufferFlags clearFlags,
|
||||
math::float4 const& linearColor, GLfloat depth, GLint stencil) noexcept;
|
||||
|
||||
void setViewportScissor(Viewport const& viewportScissor) noexcept;
|
||||
void setScissor(Viewport const& scissor) noexcept;
|
||||
|
||||
// sampler buffer binding points (nullptr if not used)
|
||||
std::array<GLSamplerGroup*, Program::BINDING_COUNT> mSamplerBindings = {}; // 12 pointers
|
||||
std::array<GLSamplerGroup*, Program::SAMPLER_BINDING_COUNT> mSamplerBindings = {}; // 4 pointers
|
||||
|
||||
mutable tsl::robin_map<uint32_t, GLuint> mSamplerMap;
|
||||
mutable std::vector<GLTexture*> mExternalStreams;
|
||||
|
||||
@@ -34,7 +34,7 @@ using namespace utils;
|
||||
using namespace backend;
|
||||
|
||||
static void logCompilationError(utils::io::ostream& out,
|
||||
Program::Shader shaderType, const char* name,
|
||||
ShaderStage shaderType, const char* name,
|
||||
GLuint shaderId, CString const& sourceCode) noexcept;
|
||||
|
||||
static void logProgramLinkError(utils::io::ostream& out,
|
||||
@@ -45,19 +45,22 @@ OpenGLProgram::OpenGLProgram() noexcept
|
||||
}
|
||||
|
||||
OpenGLProgram::OpenGLProgram(OpenGLDriver& gld, Program&& programBuilder) noexcept
|
||||
: HwProgram(programBuilder.getName()),
|
||||
: HwProgram(std::move(programBuilder.getName())),
|
||||
mInitialized(false), mValid(true),
|
||||
mLazyInitializationData{ new(LazyInitializationData) } {
|
||||
|
||||
OpenGLContext& context = gld.getContext();
|
||||
|
||||
mLazyInitializationData->uniformBlockInfo = std::move(programBuilder.getUniformBlockInfo());
|
||||
mLazyInitializationData->uniformBlockInfo = std::move(programBuilder.getUniformBlockBindings());
|
||||
mLazyInitializationData->samplerGroupInfo = std::move(programBuilder.getSamplerGroupInfo());
|
||||
|
||||
// this cannot fail because we check compilation status after linking the program
|
||||
// shaders[] is filled with id of shader stages present.
|
||||
OpenGLProgram::compileShaders(context, programBuilder.getShadersSource(),
|
||||
gl.shaders, mLazyInitializationData->shaderSourceCode);
|
||||
OpenGLProgram::compileShaders(context,
|
||||
std::move(programBuilder.getShadersSource()),
|
||||
programBuilder.getSpecializationConstants(),
|
||||
gl.shaders,
|
||||
mLazyInitializationData->shaderSourceCode);
|
||||
|
||||
gld.runAtNextRenderPass(this, [this]() {
|
||||
// by this point we must not have a GL program
|
||||
@@ -98,49 +101,95 @@ OpenGLProgram::~OpenGLProgram() noexcept {
|
||||
*/
|
||||
void OpenGLProgram::compileShaders(OpenGLContext& context,
|
||||
Program::ShaderSource shadersSource,
|
||||
utils::FixedCapacityVector<Program::SpecializationConstant> const& specializationConstants,
|
||||
GLuint shaderIds[Program::SHADER_TYPE_COUNT],
|
||||
std::array<CString, Program::SHADER_TYPE_COUNT>& outShaderSourceCode) noexcept {
|
||||
|
||||
std::string specificationConstantString;
|
||||
for (auto const& sc : specializationConstants) {
|
||||
specificationConstantString += "#define SPIRV_CROSS_CONSTANT_ID_" + std::to_string(sc.id) + ' ';
|
||||
specificationConstantString += std::visit([](auto&& arg) {
|
||||
return std::to_string(arg);
|
||||
}, sc.value);
|
||||
specificationConstantString += '\n';
|
||||
}
|
||||
if (!specificationConstantString.empty()) {
|
||||
specificationConstantString += '\n';
|
||||
}
|
||||
|
||||
// build all shaders
|
||||
UTILS_NOUNROLL
|
||||
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
|
||||
Program::Shader type = static_cast<Program::Shader>(i);
|
||||
const ShaderStage stage = static_cast<ShaderStage>(i);
|
||||
GLenum glShaderType;
|
||||
switch (type) {
|
||||
case Program::Shader::VERTEX:
|
||||
glShaderType = GL_VERTEX_SHADER;
|
||||
break;
|
||||
case Program::Shader::FRAGMENT:
|
||||
glShaderType = GL_FRAGMENT_SHADER;
|
||||
break;
|
||||
switch (stage) {
|
||||
case ShaderStage::VERTEX: glShaderType = GL_VERTEX_SHADER; break;
|
||||
case ShaderStage::FRAGMENT: glShaderType = GL_FRAGMENT_SHADER; break;
|
||||
case ShaderStage::COMPUTE: glShaderType = GL_COMPUTE_SHADER; break;
|
||||
}
|
||||
|
||||
if (UTILS_LIKELY(!shadersSource[i].empty())) {
|
||||
Program::ShaderBlob const& shader = shadersSource[i];
|
||||
std::string_view shaderView(reinterpret_cast<const char*>(shader.data()), shader.size());
|
||||
std::string temp;
|
||||
Program::ShaderBlob& shader = shadersSource[i];
|
||||
|
||||
if (!context.ext.GOOGLE_cpp_style_line_directive) {
|
||||
// If usages of the Google-style line directive are present, remove them, as some
|
||||
// drivers don't allow the quotation marks.
|
||||
if (UTILS_UNLIKELY(requestsGoogleLineDirectivesExtension(
|
||||
shaderView.data(), shaderView.size()))) {
|
||||
temp = shaderView; // copy string
|
||||
removeGoogleLineDirectives(temp.data(), temp.size()); // length is unaffected
|
||||
shaderView = temp;
|
||||
}
|
||||
}
|
||||
// remove GOOGLE_cpp_style_line_directive
|
||||
std::string_view source = process_GOOGLE_cpp_style_line_directive(context,
|
||||
reinterpret_cast<char*>(shader.data()), shader.size());
|
||||
|
||||
// Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 and
|
||||
// MacOS doesn't support GL_ARB_shading_language_packing
|
||||
if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
|
||||
if (context.state.major == 4 && context.state.minor == 1 &&
|
||||
!context.ext.ARB_shading_language_packing) {
|
||||
if (temp.empty()) {
|
||||
temp = shaderView; // copy string
|
||||
}
|
||||
// add support for ARB_shading_language_packing if needed
|
||||
auto const packingFunctions = process_ARB_shading_language_packing(context);
|
||||
|
||||
std::string unpackHalf2x16{ R"(
|
||||
// split shader source, so we can insert the specification constants and the packing functions
|
||||
auto const [prolog, body] = splitShaderSource(source);
|
||||
|
||||
const std::array<const char*, 4> sources = {
|
||||
prolog.data(),
|
||||
specificationConstantString.c_str(),
|
||||
packingFunctions.data(),
|
||||
body.data()
|
||||
};
|
||||
|
||||
const std::array<GLint, 4> lengths = {
|
||||
(GLint)prolog.length(),
|
||||
(GLint)specificationConstantString.length(),
|
||||
(GLint)packingFunctions.length(),
|
||||
(GLint)body.length() - 1 // null terminated
|
||||
};
|
||||
|
||||
GLuint shaderId = glCreateShader(glShaderType);
|
||||
glShaderSource(shaderId, sources.size(), sources.data(), lengths.data());
|
||||
glCompileShader(shaderId);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// for debugging we return the original shader source (without the modifications we
|
||||
// made here), otherwise the line numbers wouldn't match.
|
||||
outShaderSourceCode[i] = { source.data(), source.length() };
|
||||
#endif
|
||||
|
||||
shaderIds[i] = shaderId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If usages of the Google-style line directive are present, remove them, as some
|
||||
// drivers don't allow the quotation marks. This happens in-place.
|
||||
std::string_view OpenGLProgram::process_GOOGLE_cpp_style_line_directive(OpenGLContext& context,
|
||||
char* source, size_t len) noexcept {
|
||||
if (!context.ext.GOOGLE_cpp_style_line_directive) {
|
||||
if (UTILS_UNLIKELY(requestsGoogleLineDirectivesExtension({ source, len }))) {
|
||||
removeGoogleLineDirectives(source, len); // length is unaffected
|
||||
}
|
||||
}
|
||||
return { source, len };
|
||||
}
|
||||
|
||||
// Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 and
|
||||
// macOS doesn't support GL_ARB_shading_language_packing
|
||||
std::string_view OpenGLProgram::process_ARB_shading_language_packing(OpenGLContext& context) noexcept {
|
||||
using namespace std::literals;
|
||||
if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
|
||||
if (context.state.major == 4 && context.state.minor == 1 &&
|
||||
!context.ext.ARB_shading_language_packing) {
|
||||
return R"(
|
||||
|
||||
// these don't handle denormals, NaNs or inf
|
||||
float u16tofp32(highp uint v) {
|
||||
@@ -175,33 +224,31 @@ highp uint packHalf2x16(vec2 v) {
|
||||
highp uint y = fp32tou16(v.y);
|
||||
return (y << 16) | x;
|
||||
}
|
||||
)"};
|
||||
// a good point for insertion is just before the first occurrence of an uniform block
|
||||
auto pos = temp.find("layout(std140)");
|
||||
if (pos != std::string_view::npos) {
|
||||
temp.insert(pos, unpackHalf2x16);
|
||||
}
|
||||
shaderView = temp;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint shaderId = glCreateShader(glShaderType);
|
||||
{ // scope for source/length (we don't want them to leak out)
|
||||
const char* const source = shaderView.data();
|
||||
|
||||
// the shader string is null terminated and the length includes the null character
|
||||
const GLint length = (GLint)shaderView.length() - 1;
|
||||
assert_invariant( source[length] == '\0' );
|
||||
|
||||
glShaderSource(shaderId, 1, &source, &length);
|
||||
glCompileShader(shaderId);
|
||||
#ifndef NDEBUG
|
||||
outShaderSourceCode[i] = { source, static_cast<size_t>(length) };
|
||||
#endif
|
||||
}
|
||||
shaderIds[i] = shaderId;
|
||||
)"sv;
|
||||
}
|
||||
}
|
||||
return ""sv;
|
||||
}
|
||||
|
||||
// split shader source code in two, the first section goes from the start to the line after the
|
||||
// last #extension, and the 2nd part goes from there to the end.
|
||||
std::array<std::string_view, 2> OpenGLProgram::splitShaderSource(std::string_view source) noexcept {
|
||||
auto start = source.find("#version");
|
||||
assert_invariant(start != std::string_view::npos);
|
||||
|
||||
auto pos = source.rfind("\n#extension");
|
||||
if (pos == std::string_view::npos) {
|
||||
pos = start;
|
||||
} else {
|
||||
++pos;
|
||||
}
|
||||
|
||||
auto eol = source.find('\n', pos) + 1;
|
||||
assert_invariant(eol != std::string_view::npos);
|
||||
|
||||
std::string_view version = source.substr(start, eol - start);
|
||||
std::string_view body = source.substr(version.length(), source.length() - version.length());
|
||||
return { version, body };
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -226,7 +273,7 @@ GLuint OpenGLProgram::linkProgram(const GLuint shaderIds[Program::SHADER_TYPE_CO
|
||||
*/
|
||||
bool OpenGLProgram::checkProgramStatus(const char* name,
|
||||
GLuint& program, GLuint shaderIds[Program::SHADER_TYPE_COUNT],
|
||||
std::array<CString, 2> const& shaderSourceCode) noexcept {
|
||||
std::array<CString, Program::SHADER_TYPE_COUNT> const& shaderSourceCode) noexcept {
|
||||
|
||||
GLint status;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
@@ -237,7 +284,7 @@ bool OpenGLProgram::checkProgramStatus(const char* name,
|
||||
// only if the link fails, we check the compilation status
|
||||
UTILS_NOUNROLL
|
||||
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
|
||||
const Program::Shader type = static_cast<Program::Shader>(i);
|
||||
const ShaderStage type = static_cast<ShaderStage>(i);
|
||||
const GLuint shader = shaderIds[i];
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||
if (status != GL_TRUE) {
|
||||
@@ -271,9 +318,7 @@ void OpenGLProgram::initialize(OpenGLContext& context) {
|
||||
gl.program, gl.shaders, initializationData->shaderSourceCode);
|
||||
|
||||
if (UTILS_LIKELY(mValid)) {
|
||||
initializeProgramState(context, gl.program,
|
||||
initializationData->uniformBlockInfo,
|
||||
initializationData->samplerGroupInfo);
|
||||
initializeProgramState(context, gl.program, *initializationData);
|
||||
}
|
||||
|
||||
// and destroy all temporary init data
|
||||
@@ -287,13 +332,13 @@ void OpenGLProgram::initialize(OpenGLContext& context) {
|
||||
* checkProgramStatus() has been successfully called.
|
||||
*/
|
||||
void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint program,
|
||||
Program::UniformBlockInfo const& uniformBlockInfo,
|
||||
Program::SamplerGroupInfo const& samplerGroupInfo) noexcept {
|
||||
LazyInitializationData const& lazyInitializationData) noexcept {
|
||||
|
||||
// Associate each UniformBlock in the program to a known binding.
|
||||
// Note: This is only needed, because the layout(binding=) syntax is not permitted in glsl
|
||||
// (ES3.0 and GL4.1). The backend needs a way to associate a uniform block to a binding point.
|
||||
UTILS_NOUNROLL
|
||||
for (GLuint binding = 0, n = uniformBlockInfo.size(); binding < n; binding++) {
|
||||
auto const& name = uniformBlockInfo[binding];
|
||||
for (GLuint binding = 0, n = lazyInitializationData.uniformBlockInfo.size(); binding < n; binding++) {
|
||||
auto const& name = lazyInitializationData.uniformBlockInfo[binding];
|
||||
if (!name.empty()) {
|
||||
GLint index = glGetUniformBlockIndex(program, name.c_str());
|
||||
if (index >= 0) {
|
||||
@@ -307,8 +352,8 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
|
||||
uint8_t tmu = 0;
|
||||
|
||||
UTILS_NOUNROLL
|
||||
for (size_t i = 0, c = samplerGroupInfo.size(); i < c; i++) {
|
||||
auto const& samplers = samplerGroupInfo[i].samplers;
|
||||
for (size_t i = 0, c = lazyInitializationData.samplerGroupInfo.size(); i < c; i++) {
|
||||
auto const& samplers = lazyInitializationData.samplerGroupInfo[i].samplers;
|
||||
if (samplers.empty()) {
|
||||
// this binding point doesn't have any samplers, skip it.
|
||||
continue;
|
||||
@@ -331,11 +376,11 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
|
||||
tmu++;
|
||||
}
|
||||
|
||||
// if this program doesn't use any sampler from this SamplerGroup, just cancel the
|
||||
// if this program doesn't use any sampler from this HwSamplerGroup, just cancel the
|
||||
// whole group.
|
||||
if (atLeastOneSamplerUsed) {
|
||||
// Cache the sampler uniform locations for each interface block
|
||||
mUsedBindingPoints[usedBindingCount] = i;
|
||||
mUsedSamplerBindingPoints[usedBindingCount] = i;
|
||||
usedBindingCount++;
|
||||
} else {
|
||||
tmu -= samplers.size();
|
||||
@@ -344,12 +389,12 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
|
||||
mUsedBindingsCount = usedBindingCount;
|
||||
}
|
||||
|
||||
void OpenGLProgram::updateSamplers(OpenGLDriver* gld) noexcept {
|
||||
void OpenGLProgram::updateSamplers(OpenGLDriver* gld) const noexcept {
|
||||
using GLTexture = OpenGLDriver::GLTexture;
|
||||
|
||||
// cache a few member variable locally, outside the loop
|
||||
auto const& UTILS_RESTRICT samplerBindings = gld->getSamplerBindings();
|
||||
auto const& UTILS_RESTRICT usedBindingPoints = mUsedBindingPoints;
|
||||
auto const& UTILS_RESTRICT usedBindingPoints = mUsedSamplerBindingPoints;
|
||||
|
||||
for (uint8_t i = 0, tmu = 0, n = mUsedBindingsCount; i < n; i++) {
|
||||
auto const binding = usedBindingPoints[i];
|
||||
@@ -373,13 +418,14 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* gld) noexcept {
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
void logCompilationError(io::ostream& out, Program::Shader shaderType,
|
||||
void logCompilationError(io::ostream& out, ShaderStage shaderType,
|
||||
const char* name, GLuint shaderId, CString const& sourceCode) noexcept {
|
||||
|
||||
auto to_string = [](Program::Shader type) -> const char* {
|
||||
auto to_string = [](ShaderStage type) -> const char* {
|
||||
switch (type) {
|
||||
case Program::Shader::VERTEX: return "vertex";
|
||||
case Program::Shader::FRAGMENT: return "fragment";
|
||||
case ShaderStage::VERTEX: return "vertex";
|
||||
case ShaderStage::FRAGMENT: return "fragment";
|
||||
case ShaderStage::COMPUTE: return "compute";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user